/* load files onto the Network Walkman */ #include #include #include #include #include #include #include #include "libnw.h" void usage( void ) { if ( errno ) { perror( "mple-load" ); } else { fprintf( stderr, "usage: %s -m /device/path -p {file.mp3|directory} [-a album] [-s serial]\n", "mple-load" ); } exit( 1 ); } void progress( double percent, void *context ) { char *filename = (char *)context; fprintf( stdout, "\r%s: % 6.2f%%", filename, percent * 100 ); } /* pulled from mp3filemanager */ /* * find all files in a tree. Dumb, susceptible to loops, etc. * Just be careful, eh? */ GList *findfiles( const gchar *start, GList *files ) { GDir *dir; GError *error; if ( g_file_test( start, G_FILE_TEST_IS_DIR )) { const gchar *readname; dir = g_dir_open( start, 0, &error ); if ( dir == NULL ) { return files; } while(( readname = g_dir_read_name( dir )) != NULL ) { gchar *newname; /* these appear to be helpfully removed for me, but just in case... */ if (( strcmp( readname, "." ) == 0 ) || ( strcmp( readname, ".." ) == 0 )) { continue; } /* this leaks memory pretty badly, but apparently by design. */ newname = g_build_path( "/", start, readname, NULL ); /* testing here saves some recursion */ if ( g_file_test( newname, G_FILE_TEST_IS_DIR )) { files = findfiles( newname, files ); g_free( newname ); } else { files = g_list_append( files, newname ); /* gets freed at cleanup */ } } g_dir_close( dir ); } else { files = g_list_append( files, g_strdup( start )); } return files; } struct load_context { nw_device_t *dev; guint16 folder; }; void load( gpointer data, gpointer user_data ) { struct load_context *context = (struct load_context *)user_data; gchar *path = (gchar *)data; guint16 newtrack; nw_attr_t *attrpath; attrpath = g_new0( nw_attr_t, 1 ); attrpath->type = NW_STRING; attrpath->data.gc = g_strdup( g_basename( path )); nw_set_attr( context->dev, "context", attrpath ); fprintf( stdout, "%s:", g_basename( path )); errno = 0; newtrack = nw_add_track( context->dev, path, NULL, context->folder, 0 ); if ( newtrack ) { fprintf( stdout, " written as track %d\n", newtrack ); } else { if ( errno == EINVAL ) { /* EINVAL signals either that the format's invalid or you screwed up the dev or filename arguments. Given that we've already checked the latter... */ fprintf( stdout, " not a valid MP3 file\n" ); } else { fprintf( stdout, " %s\n", strerror( errno )); /* could check if it's a fatal error here, such as out of disk space, and pass it back in the context structure... */ } } } void clean( gpointer data, gpointer user_data ) { g_free( data ); } int main( int argc, char *argv[] ) { struct stat statbuf; struct load_context context; nw_device_t *dev; guint16 folder = 0; gchar *mountpoint = NULL, *path = NULL, *album = NULL; int val = 0; guint32 msn = 0; gboolean msn_provided = FALSE; GList *files = NULL; nw_attr_t *attrtmp = NULL, *attrmtpt = NULL; errno = 0; /* safety clown says ... */ while (( val = getopt( argc, argv, "m:p:a:s:" )) != -1 ) { switch( val ) { case '?': case ':': usage(); case 's': msn_provided = TRUE; if ( strncmp( optarg, "0x", 2 ) == 0 ) { guint8 c; if ( strlen( optarg ) < 10 ) { fprintf( stderr, "MSN must be 8 hex digits\n" ); exit( 1 ); } /* urgh */ for ( c = 2; c < strlen( optarg ); c++ ) { char v = optarg[c]; if ( v > 'F' ) { v -= ( 'a' - 10 ); } else if ( v > '9' ) { v -= ( 'A' - 10 ); } else { v -= '0'; } msn |= ( v << (( c - 2 ) * 4 )); } } else { msn = atol( optarg ); } break; case 'm': mountpoint = optarg; break; case 'p': path = optarg; break; case 'a': album = optarg; break; default: fprintf( stderr, "wtf?" ); usage(); } } /* old usage: parameters are /mount/point /path/to/mp3 [folder] */ if (( optind == argc - 2 ) || ( optind == argc - 3 )) { mountpoint = argv[optind]; path = argv[optind + 1]; if ( optind == argc - 3 ) { album = argv[optind + 2]; } } /* one param -> file to load */ if (( optind == argc - 1 )) { path = argv[optind]; } /* sanity check */ if ( mountpoint == NULL ) { /* Go for auto-probe */ GList *devs; guint32 d = 0; fprintf( stderr, "no device specified, auto-probing..." ); devs = nw_get_devs( NULL ); if ( g_list_length( devs ) == 0 ) { fprintf( stderr, "no device found\n" ); exit( 1 ); } else { fprintf( stderr, "done\n" ); } if ( g_list_length( devs ) > 1 ) { fprintf( stderr, "More than one device found, please be more specific : \n" ); while( g_list_nth( devs, d )) { nw_device_t *dv = g_list_nth_data( devs, d ); if (( attrtmp = nw_get_attr( dev, "device" )) != NULL ) { fprintf( stderr, " %s", NW_STR_ATTR( attrtmp )); if (( attrmtpt = nw_get_attr( dv, "mountpoint" )) != NULL ) { fprintf( stderr, " (mounted at %s)", NW_STR_ATTR( attrmtpt )); } fprintf( stderr, "\n" ); } else { fprintf( stderr, " [attr read failed]\n" ); } nw_dev_free( dv ); d++; } g_list_free( devs ); exit( 1 ); } else { dev = g_list_nth_data( devs, d ); if (( attrtmp = nw_get_attr( dev, "device" )) != NULL ) { fprintf( stderr, "Using device %s at %p", NW_STR_ATTR( attrtmp ), dev ); if (( attrmtpt = nw_get_attr( dev, "mountpoint" )) != NULL ) { fprintf( stderr, " (mounted at %s)", NW_STR_ATTR( attrtmp )); } fprintf( stderr, "\n" ); } else { if ( errno == ENOENT ) { fprintf( stderr, "No device in device structure!\n" ); } else { fprintf( stderr, "device entry appears to be null\n" ); } exit( 1 ); } } } else { dev = nw_dev_init( mountpoint, NW_GUESS ); } if ( dev == NULL ) { fprintf( stderr, "No device specified or found\n" ); exit( 1 ); } if ( msn_provided ) { /*dev->msn = msn; dev->aux |= MPLE_MSN; xxx */ } else { /* xxx not applicable to v2, really */ if ( nw_get_attr( dev, "media serial number" ) == NULL ) { if ( nw_get_attr( dev, "mountpoint" ) == NULL ) { fprintf( stderr, "unable to identify device %s\n", mountpoint ); exit( 1 ); } } } nw_set_progress_func( dev, progress ); /* if the album parameter is set, get or create a folder with that name. Otherwise, use the first folder, or if there are no folders, create a folder called New Folder and use that. */ if ( album == NULL ) { if ( nw_parse_directory( dev ) == NULL ) { folder = nw_add_folder( dev, "New Folder", 0 ); } else { folder = 1; } } else { if (( folder = nw_get_folder( dev, album, 0 )) == 0 ) { folder = nw_add_folder( dev, album, 0 ); if ( folder ) { fprintf( stdout, "created folder %s as #%d\n", album, folder ); } else { perror( "mple_add_folder" ); exit( 1 ); } } if ( !folder ) { fprintf( stderr, "mple_add/get_folder: %s\n", strerror( errno )); exit( 1 ); } } /* find out if we're dealing with a file or a directory */ if ( stat( path, &statbuf ) != 0 ) { fprintf( stderr, "%s: %s\n", path, strerror( errno )); exit( 1 ); } if ( !S_ISDIR( statbuf.st_mode )) { files = g_list_append( files, g_strdup( path )); /* path gets g_free'd later, hence strdup */ } else { files = findfiles( path, files ); } if ( g_list_length( files ) == 0 ) { fprintf( stderr, "no files found\n" ); exit( 1 ); } context.dev = dev; context.folder = folder; g_list_foreach( files, load, (gpointer)&context ); g_list_foreach( files, clean, NULL ); g_list_free( files ); nw_dev_free( dev ); return 0; }