void spl_to_playlist_t(LIBMTP_mtpdevice_t* device, PTPObjectInfo *oi, const uint32_t id, LIBMTP_playlist_t * const pl) { // Fill in playlist metadata // Use the Filename as the playlist name, dropping the ".spl" extension pl->name = malloc(sizeof(char)*(strlen(oi->Filename) -4 +1)); memcpy(pl->name, oi->Filename, strlen(oi->Filename) -4); // Set terminating character pl->name[strlen(oi->Filename) - 4] = 0; pl->playlist_id = id; pl->parent_id = oi->ParentObject; pl->storage_id = oi->StorageID; pl->tracks = NULL; pl->no_tracks = 0; LIBMTP_PLST_DEBUG("pl->name='%s'\n", pl->name); // open a temporary file char tmpname[] = "/tmp/mtp-spl2pl-XXXXXX"; int fd = mkstemp(tmpname); if(fd < 0) { LIBMTP_ERROR("failed to make temp file for %s.spl -> %s, errno=%s\n", pl->name, tmpname, strerror(errno)); return; } // make sure the file will be deleted afterwards if(unlink(tmpname) < 0) LIBMTP_ERROR("failed to delete temp file for %s.spl -> %s, errno=%s\n", pl->name, tmpname, strerror(errno)); int ret = LIBMTP_Get_File_To_File_Descriptor(device, pl->playlist_id, fd, NULL, NULL); if( ret < 0 ) { // FIXME add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Playlist: Could not get .spl playlist file."); close(fd); LIBMTP_INFO("FIXME closed\n"); } text_t* p = read_into_spl_text_t(device, fd); close(fd); // FIXME cache these somewhere else so we don't keep calling this! LIBMTP_folder_t *folders; LIBMTP_file_t *files; folders = LIBMTP_Get_Folder_List(device); files = LIBMTP_Get_Filelisting_With_Callback(device, NULL, NULL); // convert the playlist listing to track ids pl->no_tracks = trackno_spl_text_t(p); LIBMTP_PLST_DEBUG("%u track%s found\n", pl->no_tracks, pl->no_tracks==1?"":"s"); pl->tracks = malloc(sizeof(uint32_t)*(pl->no_tracks)); tracks_from_spl_text_t(p, pl->tracks, folders, files); free_spl_text_t(p); // debug: add a break since this is the top level function call LIBMTP_PLST_DEBUG("------------\n\n"); }
int main (int argc, char **argv) { int do_delete = 0; int opt; fprintf(stdout, "libmtp version: " LIBMTP_VERSION_STRING "\n\n"); while ( (opt = getopt(argc, argv, "d")) != -1 ) { switch (opt) { case 'd': do_delete = 1; break; default: break; } } if(do_delete == 0) { printf("This is a dummy run. No folders will be deleted.\n"); printf("To delete folders, use the '-d' option.\n"); } LIBMTP_mtpdevice_t *device; LIBMTP_folder_t *folders; LIBMTP_file_t *files; LIBMTP_Init(); device = LIBMTP_Get_First_Device(); if (device == NULL) { printf("No devices.\n"); exit (0); } files = LIBMTP_Get_Filelisting_With_Callback(device,NULL,NULL); folders = LIBMTP_Get_Folder_List(device); if(folders == NULL) { printf("No folders found\n"); } else { prune_empty_folders(device,files,folders,do_delete); } LIBMTP_destroy_folder_t(folders); LIBMTP_destroy_file_t(files); LIBMTP_Release_Device(device); printf("OK.\n"); exit (0); }
/** * Push a playlist_t onto the device after converting it to a .spl format * * @param device mtp device pointer * @param pl the LIBMTP_playlist_t to convert (pl->playlist_id will be updated * with the newly created object's id) * @return 0 on success, any other value means failure. */ int playlist_t_to_spl(LIBMTP_mtpdevice_t *device, LIBMTP_playlist_t * const pl) { text_t* t; LIBMTP_folder_t *folders; LIBMTP_file_t *files; folders = LIBMTP_Get_Folder_List(device); files = LIBMTP_Get_Filelisting_With_Callback(device, NULL, NULL); char tmpname[] = "/tmp/mtp-spl2pl-XXXXXX"; // must be a var since mkstemp modifies it LIBMTP_PLST_DEBUG("pl->name='%s'\n",pl->name); // open a file descriptor int fd = mkstemp(tmpname); if(fd < 0) { LIBMTP_ERROR("failed to make temp file for %s.spl -> %s, errno=%s\n", pl->name, tmpname, strerror(errno)); return -1; } // make sure the file will be deleted afterwards if(unlink(tmpname) < 0) LIBMTP_ERROR("failed to delete temp file for %s.spl -> %s, errno=%s\n", pl->name, tmpname, strerror(errno)); // decide on which version of the .spl format to use uint32_t ver_major; uint32_t ver_minor = 0; PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo; if(FLAG_PLAYLIST_SPL_V2(ptp_usb)) ver_major = 2; else ver_major = 1; // FLAG_PLAYLIST_SPL_V1() LIBMTP_PLST_DEBUG("%u track%s\n", pl->no_tracks, pl->no_tracks==1?"":"s"); LIBMTP_PLST_DEBUG(".spl version %d.%02d\n", ver_major, ver_minor); // create the text for the playlist spl_text_t_from_tracks(&t, pl->tracks, pl->no_tracks, ver_major, ver_minor, NULL, folders, files); write_from_spl_text_t(device, fd, t); free_spl_text_t(t); // done with the text // create the file object for storing LIBMTP_file_t* f = malloc(sizeof(LIBMTP_file_t)); f->item_id = 0; f->parent_id = pl->parent_id; f->storage_id = pl->storage_id; f->filename = malloc(sizeof(char)*(strlen(pl->name)+5)); strcpy(f->filename, pl->name); strcat(f->filename, ".spl"); // append suffix f->filesize = lseek(fd, 0, SEEK_CUR); // file desc is currently at end of file f->filetype = LIBMTP_FILETYPE_UNKNOWN; f->next = NULL; LIBMTP_PLST_DEBUG("%s is %dB\n", f->filename, (int)f->filesize); // push the playlist to the device lseek(fd, 0, SEEK_SET); // reset file desc. to start of file int ret = LIBMTP_Send_File_From_File_Descriptor(device, fd, f, NULL, NULL); pl->playlist_id = f->item_id; free(f->filename); free(f); // release the memory when we're done with it close(fd); // debug: add a break since this is the top level function call LIBMTP_PLST_DEBUG("------------\n\n"); return ret; }
static void delete_done_cb (LIBMTP_mtpdevice_t *device, TracksDeletedCallbackData *data) { LIBMTP_folder_t *folders; LIBMTP_file_t *files; data->actually_free = FALSE; update_free_space_cb (device, RB_MTP_SOURCE (data->source)); /* if any of the folders we just deleted from are now empty, delete them */ folders = LIBMTP_Get_Folder_List (device); files = LIBMTP_Get_Filelisting_With_Callback (device, NULL, NULL); if (folders != NULL) { GHashTableIter iter; gpointer key; g_hash_table_iter_init (&iter, data->check_folders); while (g_hash_table_iter_next (&iter, &key, NULL)) { LIBMTP_folder_t *f; LIBMTP_folder_t *c; LIBMTP_file_t *file; uint32_t folder_id = GPOINTER_TO_UINT(key); while (folder_id != device->default_music_folder && folder_id != 0) { f = LIBMTP_Find_Folder (folders, folder_id); if (f == NULL) { rb_debug ("unable to find folder %u", folder_id); break; } /* don't delete folders with children that we didn't just delete */ for (c = f->child; c != NULL; c = c->sibling) { if (g_hash_table_lookup (data->check_folders, GUINT_TO_POINTER (c->folder_id)) == NULL) { break; } } if (c != NULL) { rb_debug ("folder %s has children", f->name); break; } /* don't delete folders that contain files */ for (file = files; file != NULL; file = file->next) { if (file->parent_id == folder_id) { break; } } if (file != NULL) { rb_debug ("folder %s contains at least one file: %s", f->name, file->filename); break; } /* ok, the folder is empty */ rb_debug ("deleting empty folder %s", f->name); LIBMTP_Delete_Object (device, f->folder_id); /* if the folder we just deleted has siblings, the parent * can't be empty. */ if (f->sibling != NULL) { rb_debug ("folder %s has siblings, can't delete parent", f->name); break; } folder_id = f->parent_id; } } LIBMTP_destroy_folder_t (folders); } else { rb_debug ("unable to get device folder list"); } /* clean up the file list */ while (files != NULL) { LIBMTP_file_t *n; n = files->next; LIBMTP_destroy_file_t (files); files = n; } g_idle_add ((GSourceFunc) delete_done_idle_cb, data); }