static int add_track_to_album(LIBMTP_album_t *albuminfo, LIBMTP_track_t *trackmeta) { LIBMTP_album_t *album; LIBMTP_album_t *album_orig; LIBMTP_album_t *found_album = NULL; int ret; /* Look for the album */ album = LIBMTP_Get_Album_List(device); album_orig = album; while(album != NULL) { if ((album->name != NULL && album->artist != NULL && !strcmp(album->name, albuminfo->name) && !strcmp(album->artist, albuminfo->artist)) || (album->name != NULL && album->composer != NULL && !strcmp(album->name, albuminfo->name) && !strcmp(album->composer, albuminfo->composer))) { /* Disconnect this album for later use */ found_album = album; album = album->next; found_album->next = NULL; } else { album = album->next; } } if (found_album == NULL) { printf("Could not find Album. Retrying with only Album name\n"); album = album_orig; while(album != NULL) { if ((album->name != NULL) && !strcmp(album->name, albuminfo->name) ){ /* Disconnect this album for later use */ found_album = album; album = album->next; found_album->next = NULL; } else { album = album->next; } } } if (found_album != NULL) { uint32_t *tracks; tracks = (uint32_t *)malloc((found_album->no_tracks+1) * sizeof(uint32_t)); printf("Album \"%s\" found: updating...\n", found_album->name); if (!tracks) { printf("failed malloc in add_track_to_album()\n"); return 1; } found_album->no_tracks++; if (found_album->tracks != NULL) { memcpy(tracks, found_album->tracks, found_album->no_tracks * sizeof(uint32_t)); free(found_album->tracks); } tracks[found_album->no_tracks-1] = trackmeta->item_id; found_album->tracks = tracks; ret = LIBMTP_Update_Album(device, found_album); } else { uint32_t *trackid; trackid = (uint32_t *)malloc(sizeof(uint32_t)); *trackid = trackmeta->item_id; albuminfo->tracks = trackid; albuminfo->no_tracks = 1; albuminfo->storage_id = trackmeta->storage_id; printf("Album doesn't exist: creating...\n"); ret = LIBMTP_Create_New_Album(device, albuminfo); /* albuminfo will be destroyed later by caller */ } /* Delete the earlier retrieved Album list */ album=album_orig; while(album!=NULL){ LIBMTP_album_t *tmp; tmp = album; album = album->next; LIBMTP_destroy_album_t(tmp); } if (ret != 0) { printf("Error creating or updating album.\n"); printf("(This could be due to that your device does not support albums.)\n"); LIBMTP_Dump_Errorstack(device); LIBMTP_Clear_Errorstack(device); } else { printf("success!\n"); } return ret; }
int main () { LIBMTP_mtpdevice_t *device_list, *iter; LIBMTP_Init(); fprintf(stdout, "libmtp version: " LIBMTP_VERSION_STRING "\n\n"); switch(LIBMTP_Get_Connected_Devices(&device_list)) { case LIBMTP_ERROR_NO_DEVICE_ATTACHED: fprintf(stdout, "mtp-albums: No Devices have been found\n"); return 0; case LIBMTP_ERROR_CONNECTING: fprintf(stderr, "mtp-albums: There has been an error connecting. Exit\n"); return 1; case LIBMTP_ERROR_MEMORY_ALLOCATION: fprintf(stderr, "mtp-albums: Memory Allocation Error. Exit\n"); return 1; case LIBMTP_ERROR_GENERAL: default: fprintf(stderr, "mtp-albums: Unknown error, please report " "this to the libmtp developers\n"); return 1; case LIBMTP_ERROR_NONE: fprintf(stdout, "mtp-albums: Successfully connected\n"); fflush(stdout); } for(iter = device_list; iter != NULL; iter = iter->next) { char *friendlyname; LIBMTP_album_t *album_list, *album, *tmp; friendlyname = LIBMTP_Get_Friendlyname(iter); if (friendlyname == NULL) { printf("Retrieving Albums on Device with name: (NULL)\n"); } else { printf("Retrieving Albums on Device with name: %s\n", friendlyname); free(friendlyname); } album_list = LIBMTP_Get_Album_List(iter); album = album_list; while(album != NULL) { dump_albuminfo(album); tmp = album; album = album->next; LIBMTP_destroy_album_t(tmp); } } LIBMTP_Release_Device_List(device_list); printf("OK.\n"); return 0; }
static gboolean load_mtp_db_idle_cb (RBMtpSource* source) { RhythmDB *db = NULL; RBMtpSourcePrivate *priv = MTP_SOURCE_GET_PRIVATE (source); LIBMTP_track_t *tracks = NULL; LIBMTP_album_t *albums; gboolean device_forgets_albums = TRUE; db = get_db_for_source (source); g_assert (db != NULL); albums = LIBMTP_Get_Album_List (priv->device); report_libmtp_errors (priv->device, FALSE); if (albums != NULL) { LIBMTP_album_t *album; for (album = albums; album != NULL; album = album->next) { rb_debug ("album: %s, %d tracks", album->name, album->no_tracks); g_hash_table_insert (priv->album_map, album->name, album); if (album->no_tracks != 0) { device_forgets_albums = FALSE; } } if (device_forgets_albums) { rb_debug ("stupid mtp device detected. will rebuild all albums."); } } else { rb_debug ("No albums"); device_forgets_albums = FALSE; } #ifdef HAVE_LIBMTP_030 tracks = LIBMTP_Get_Tracklisting_With_Callback (priv->device, NULL, NULL); #else tracks = LIBMTP_Get_Tracklisting (priv->device); #endif report_libmtp_errors (priv->device, FALSE); if (tracks != NULL) { LIBMTP_track_t *track; for (track = tracks; track != NULL; track = track->next) { add_mtp_track_to_db (source, db, track); if (device_forgets_albums && track->album != NULL) { add_track_to_album (source, track->album, track); } } } else { rb_debug ("No tracks"); } /* for stupid devices, remove any albums left with no tracks */ if (device_forgets_albums) { GHashTableIter iter; gpointer value; LIBMTP_album_t *album; g_hash_table_iter_init (&iter, priv->album_map); while (g_hash_table_iter_next (&iter, NULL, &value)) { int ret; album = value; if (album->no_tracks == 0) { rb_debug ("pruning empty album \"%s\"", album->name); ret = LIBMTP_Delete_Object (priv->device, album->album_id); if (ret != 0) { report_libmtp_errors (priv->device, FALSE); } g_hash_table_iter_remove (&iter); } } } g_object_unref (G_OBJECT (db)); return FALSE; }
static void get_track_list (RBMtpThread *thread, RBMtpThreadTask *task) { RBMtpTrackListCallback cb = task->callback; gboolean device_forgets_albums = TRUE; GHashTable *update_albums = NULL; LIBMTP_track_t *tracks = NULL; LIBMTP_album_t *albums; LIBMTP_album_t *album; /* get all the albums */ albums = LIBMTP_Get_Album_List (thread->device); rb_mtp_thread_report_errors (thread, FALSE); if (albums != NULL) { LIBMTP_album_t *album; for (album = albums; album != NULL; album = album->next) { if (album->name == NULL) continue; rb_debug ("album: %s, %d tracks", album->name, album->no_tracks); g_hash_table_insert (thread->albums, album->name, album); if (album->no_tracks != 0) { device_forgets_albums = FALSE; } } if (device_forgets_albums) { rb_debug ("stupid mtp device detected. will rebuild all albums."); } } else { rb_debug ("No albums"); device_forgets_albums = FALSE; } tracks = LIBMTP_Get_Tracklisting_With_Callback (thread->device, NULL, NULL); rb_mtp_thread_report_errors (thread, FALSE); if (tracks == NULL) { rb_debug ("no tracks on the device"); } else if (device_forgets_albums) { LIBMTP_track_t *track; rb_debug ("rebuilding albums"); update_albums = g_hash_table_new (g_direct_hash, g_direct_equal); for (track = tracks; track != NULL; track = track->next) { if (track->album != NULL) { gboolean new_album = FALSE; album = add_track_to_album (thread, track->album, track->item_id, track->storage_id, &new_album); g_hash_table_insert (update_albums, album, GINT_TO_POINTER (new_album)); } } rb_debug ("finished rebuilding albums"); } cb (tracks, task->user_data); /* the callback owns the tracklist */ if (device_forgets_albums) { GHashTableIter iter; gpointer album_ptr; gpointer new_album_ptr; rb_debug ("writing rebuilt albums back to the device"); g_hash_table_iter_init (&iter, update_albums); while (g_hash_table_iter_next (&iter, &album_ptr, &new_album_ptr)) { album = album_ptr; rb_debug ("writing album \"%s\"", album->name); write_album_to_device (thread, album, GPOINTER_TO_INT (new_album_ptr)); } g_hash_table_destroy (update_albums); rb_debug ("removing remaining empty albums"); g_hash_table_iter_init (&iter, thread->albums); while (g_hash_table_iter_next (&iter, NULL, &album_ptr)) { int ret; album = album_ptr; if (album->no_tracks == 0) { rb_debug ("pruning empty album \"%s\"", album->name); ret = LIBMTP_Delete_Object (thread->device, album->album_id); if (ret != 0) { rb_mtp_thread_report_errors (thread, FALSE); } g_hash_table_iter_remove (&iter); } } rb_debug ("finished updating albums on the device"); } }
void Plugin::AppendAlbum (LIBMTP_mtpdevice_t *device, LIBMTP_track_t *track, const UnmountableFileInfo& info) { auto albuminfo = LIBMTP_new_album_t (); albuminfo->artist = strdup (info.Artist_.toUtf8 ().constData ()); albuminfo->name = strdup (info.Album_.toUtf8 ().constData ()); albuminfo->genre = strdup (info.Genres_.join ("; ").toUtf8 ().constData ()); auto album = LIBMTP_Get_Album_List (device); auto albumOrig = album; decltype (album) foundAlbum = nullptr, resultingAlgum = nullptr; while (album) { if (album->name && (album->artist || album->composer) && QString::fromUtf8 (album->name) == info.Album_ && (QString::fromUtf8 (album->artist) == info.Artist_ || QString::fromUtf8 (album->composer) == info.Artist_)) { foundAlbum = album; album = album->next; foundAlbum->next = nullptr; } else album = album->next; } if (foundAlbum) { auto tracks = static_cast<uint32_t*> (malloc ((foundAlbum->no_tracks + 1) * sizeof (uint32_t))); ++foundAlbum->no_tracks; if (foundAlbum->tracks) { memcpy (tracks, foundAlbum->tracks, foundAlbum->no_tracks * sizeof (uint32_t)); free (foundAlbum->tracks); } tracks [foundAlbum->no_tracks - 1] = track->item_id; foundAlbum->tracks = tracks; if (LIBMTP_Update_Album (device, foundAlbum)) { LIBMTP_Dump_Errorstack (device); LIBMTP_Clear_Errorstack (device); } resultingAlgum = foundAlbum; } else { auto trackId = static_cast<uint32_t*> (malloc (sizeof (uint32_t))); *trackId = track->item_id; albuminfo->tracks = trackId; albuminfo->no_tracks = 1; albuminfo->storage_id = track->storage_id; if (LIBMTP_Create_New_Album (device, albuminfo)) { LIBMTP_Dump_Errorstack (device); LIBMTP_Clear_Errorstack (device); } resultingAlgum = albuminfo; } SetAlbumArt (device, resultingAlgum, info.AlbumArtPath_); while (albumOrig) { auto tmp = albumOrig; albumOrig = albumOrig->next; LIBMTP_destroy_album_t (tmp); } LIBMTP_destroy_album_t (albuminfo); }