Home | History | Annotate | Download | only in examples
      1 /**
      2  * \file sendtr.c
      3  * Example program to send a music track to a device.
      4  * This program is derived from the exact equivalent in libnjb.
      5  * based on Enrique Jorreto Ledesma's work on the original program by
      6  * Shaun Jackman and Linus Walleij.
      7  *
      8  * Copyright (C) 2003-2009 Linus Walleij <triad (at) df.lth.se>
      9  * Copyright (C) 2003-2005 Shaun Jackman
     10  * Copyright (C) 2003-2005 Enrique Jorrete Ledesma
     11  * Copyright (C) 2006 Chris A. Debenham <chris (at) adebenham.com>
     12  * Copyright (C) 2008 Nicolas Pennequin <nicolas.pennequin (at) free.fr>
     13  * Copyright (C) 2008 Joseph Nahmias <joe (at) nahmias.net>
     14  *
     15  * This library is free software; you can redistribute it and/or
     16  * modify it under the terms of the GNU Lesser General Public
     17  * License as published by the Free Software Foundation; either
     18  * version 2 of the License, or (at your option) any later version.
     19  *
     20  * This library is distributed in the hope that it will be useful,
     21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     23  * Lesser General Public License for more details.
     24  *
     25  * You should have received a copy of the GNU Lesser General Public
     26  * License along with this library; if not, write to the
     27  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
     28  * Boston, MA 02111-1307, USA.
     29  */
     30 
     31 #include "config.h"
     32 #include "common.h"
     33 #include "util.h"
     34 #include <stdlib.h>
     35 #include <limits.h>
     36 #include <string.h>
     37 #include <libgen.h>
     38 #include <sys/stat.h>
     39 #include <sys/types.h>
     40 #include <fcntl.h>
     41 #ifdef HAVE_LANGINFO_H
     42 #include <langinfo.h>
     43 #endif
     44 #include "libmtp.h"
     45 #include "pathutils.h"
     46 
     47 extern LIBMTP_folder_t *folders;
     48 extern LIBMTP_file_t *files;
     49 extern LIBMTP_mtpdevice_t *device;
     50 
     51 int sendtrack_function (char *, char *, char *, char *, char *, char *, char *, char *, uint16_t, uint16_t, uint16_t, uint32_t);
     52 void sendtrack_command (int, char **);
     53 void sendtrack_usage (void);
     54 
     55 void sendtrack_usage (void)
     56 {
     57   fprintf(stderr, "usage: sendtr [ -D debuglvl ] [ -q ]\n");
     58   fprintf(stderr, "-t <title> -a <artist> -A <Album artist> -w <writer or composer>\n");
     59   fprintf(stderr, "    -l <album> -c <codec> -g <genre> -n <track number> -y <year>\n");
     60   fprintf(stderr, "       -d <duration in seconds> -s <storage_id> <local path> <remote path>\n");
     61   fprintf(stderr, "(-q means the program will not ask for missing information.)\n");
     62 }
     63 
     64 static char *prompt (const char *prompt, char *buffer, size_t bufsz, int required)
     65 {
     66   char *cp, *bp;
     67 
     68   while (1) {
     69     fprintf(stdout, "%s> ", prompt);
     70     if ( fgets(buffer, bufsz, stdin) == NULL ) {
     71       if (ferror(stdin)) {
     72 	perror("fgets");
     73       } else {
     74 	fprintf(stderr, "EOF on stdin\n");
     75       }
     76       return NULL;
     77     }
     78 
     79     cp = strrchr(buffer, '\n');
     80     if ( cp != NULL ) *cp = '\0';
     81 
     82     bp = buffer;
     83     while ( bp != cp ) {
     84       if ( *bp != ' ' && *bp != '\t' ) return bp;
     85       bp++;
     86     }
     87 
     88     if (! required) return bp;
     89   }
     90 }
     91 
     92 static int add_track_to_album(LIBMTP_album_t *albuminfo, LIBMTP_track_t *trackmeta)
     93 {
     94   LIBMTP_album_t *album;
     95   LIBMTP_album_t *found_album = NULL;
     96   int ret;
     97 
     98   /* Look for the album */
     99   album = LIBMTP_Get_Album_List(device);
    100   while(album != NULL) {
    101     if ((album->name != NULL &&
    102 	album->artist != NULL &&
    103 	!strcmp(album->name, albuminfo->name) &&
    104 	!strcmp(album->artist, albuminfo->artist)) ||
    105 	  (album->name != NULL &&
    106 	album->composer != NULL &&
    107 	!strcmp(album->name, albuminfo->name) &&
    108 	!strcmp(album->composer, albuminfo->composer))) {
    109       /* Disconnect this album for later use */
    110       found_album = album;
    111       album = album->next;
    112       found_album->next = NULL;
    113     } else {
    114       LIBMTP_album_t *tmp;
    115 
    116       tmp = album;
    117       album = album->next;
    118       LIBMTP_destroy_album_t(tmp);
    119     }
    120   }
    121 
    122   if (found_album != NULL) {
    123     uint32_t *tracks;
    124 
    125     tracks = (uint32_t *)malloc((found_album->no_tracks+1) * sizeof(uint32_t));
    126     printf("Album \"%s\" found: updating...\n", found_album->name);
    127     if (!tracks) {
    128       printf("failed malloc in add_track_to_album()\n");
    129       return 1;
    130     }
    131     found_album->no_tracks++;
    132     if (found_album->tracks != NULL) {
    133       memcpy(tracks, found_album->tracks, found_album->no_tracks * sizeof(uint32_t));
    134       free(found_album->tracks);
    135     }
    136     tracks[found_album->no_tracks-1] = trackmeta->item_id;
    137     found_album->tracks = tracks;
    138     ret = LIBMTP_Update_Album(device, found_album);
    139     LIBMTP_destroy_album_t(found_album);
    140   } else {
    141     uint32_t *trackid;
    142 
    143     trackid = (uint32_t *)malloc(sizeof(uint32_t));
    144     *trackid = trackmeta->item_id;
    145     albuminfo->tracks = trackid;
    146     albuminfo->no_tracks = 1;
    147     albuminfo->storage_id = trackmeta->storage_id;
    148     printf("Album doesn't exist: creating...\n");
    149     ret = LIBMTP_Create_New_Album(device, albuminfo);
    150     /* albuminfo will be destroyed later by caller */
    151   }
    152 
    153   if (ret != 0) {
    154     printf("Error creating or updating album.\n");
    155     printf("(This could be due to that your device does not support albums.)\n");
    156     LIBMTP_Dump_Errorstack(device);
    157     LIBMTP_Clear_Errorstack(device);
    158   } else {
    159     printf("success!\n");
    160   }
    161   return ret;
    162 }
    163 
    164 int sendtrack_function(char * from_path, char * to_path, char *partist, char *palbumartist, char *ptitle, char *pgenre, char *palbum, char *pcomposer, uint16_t tracknum, uint16_t length, uint16_t year, uint32_t storageid)
    165 {
    166   char *filename, *parent;
    167   char artist[80], albumartist[80], title[80], genre[80], album[80], composer[80];
    168   char num[80];
    169   uint64_t filesize;
    170   uint32_t parent_id = 0;
    171   struct stat sb;
    172   LIBMTP_track_t *trackmeta;
    173   LIBMTP_album_t *albuminfo;
    174   int ret;
    175 
    176   printf("Sending track %s to %s\n",from_path,to_path);
    177 
    178   trackmeta = LIBMTP_new_track_t();
    179   albuminfo = LIBMTP_new_album_t();
    180 
    181   parent = dirname(strdup(to_path));
    182   filename = basename(strdup(to_path));
    183   parent_id = parse_path (parent,files,folders);
    184   if (parent_id == -1) {
    185     printf("Parent folder could not be found, skipping\n");
    186     return 1;
    187   }
    188 
    189   if ( stat(from_path, &sb) == -1 ) {
    190     fprintf(stderr, "%s: ", from_path);
    191     perror("stat");
    192     return 1;
    193   } else if (S_ISREG (sb.st_mode)) {
    194     filesize = sb.st_size;
    195     trackmeta->filetype = find_filetype (from_path);
    196     if (!LIBMTP_FILETYPE_IS_TRACK(trackmeta->filetype)) {
    197       printf("Not a valid track codec: \"%s\"\n", LIBMTP_Get_Filetype_Description(trackmeta->filetype));
    198       return 1;
    199     }
    200 
    201     if (ptitle == NULL) {
    202       ptitle = prompt("Title", title, 80, 0);
    203     }
    204     if (!strlen(ptitle))
    205       ptitle = NULL;
    206 
    207     if (palbum == NULL) {
    208       palbum = prompt("Album", album, 80, 0);
    209     }
    210     if (!strlen(palbum))
    211       palbum = NULL;
    212 
    213     if (palbumartist == NULL) {
    214       palbumartist = prompt("Album artist", albumartist, 80, 0);
    215     }
    216     if (partist == NULL) {
    217       partist = prompt("Artist", artist, 80, 0);
    218     }
    219     if (!strlen(partist))
    220       partist = NULL;
    221 
    222     if (pcomposer == NULL) {
    223       pcomposer = prompt("Writer or Composer", composer, 80, 0);
    224     }
    225     if (!strlen(pcomposer))
    226       pcomposer = NULL;
    227 
    228     if (pgenre == NULL) {
    229       pgenre = prompt("Genre", genre, 80, 0);
    230     }
    231     if (!strlen(pgenre))
    232       pgenre = NULL;
    233 
    234     if (tracknum == 0) {
    235       char *pnum;
    236       if ( (pnum = prompt("Track number", num, 80, 0)) == NULL )
    237       tracknum = 0;
    238       if ( strlen(pnum) ) {
    239         tracknum = strtoul(pnum, 0, 10);
    240       } else {
    241         tracknum = 0;
    242       }
    243     }
    244 
    245     if (year == 0) {
    246       char *pnum;
    247       if ( (pnum = prompt("Year", num, 80, 0)) == NULL )
    248         year = 0;
    249       if ( strlen(pnum) ) {
    250         year = strtoul(pnum, 0, 10);
    251       } else {
    252         year = 0;
    253       }
    254     }
    255 
    256     if (length == 0) {
    257       char *pnum;
    258       if ( (pnum = prompt("Length", num, 80, 0)) == NULL )
    259         length = 0;
    260       if ( strlen(pnum) ) {
    261         length = strtoul(pnum, 0, 10);
    262       } else {
    263         length = 0;
    264       }
    265     }
    266 
    267     printf("Sending track:\n");
    268     printf("Codec:     %s\n", LIBMTP_Get_Filetype_Description(trackmeta->filetype));
    269     if (ptitle) {
    270       printf("Title:     %s\n", ptitle);
    271       trackmeta->title = strdup(ptitle);
    272     }
    273     if (palbum) {
    274       printf("Album:     %s\n", palbum);
    275       trackmeta->album = strdup(palbum);
    276       albuminfo->name = strdup(palbum);
    277     }
    278     if (palbumartist) {
    279       printf("Album artist:    %s\n", palbumartist);
    280       albuminfo->artist = strdup(palbumartist);
    281     }
    282     if (partist) {
    283       printf("Artist:    %s\n", partist);
    284       trackmeta->artist = strdup(partist);
    285       if (palbumartist == NULL)
    286       albuminfo->artist = strdup(partist);
    287     }
    288 
    289     if (pcomposer) {
    290       printf("Writer or Composer:    %s\n", pcomposer);
    291       trackmeta->composer = strdup(pcomposer);
    292       albuminfo->composer = strdup(pcomposer);
    293     }
    294     if (pgenre) {
    295       printf("Genre:     %s\n", pgenre);
    296       trackmeta->genre = strdup(pgenre);
    297       albuminfo->genre = strdup(pgenre);
    298     }
    299     if (year > 0) {
    300       char tmp[80];
    301       printf("Year:      %d\n", year);
    302       snprintf(tmp, sizeof(tmp)-1, "%4d0101T0000.0", year);
    303       tmp[sizeof(tmp)-1] = '\0';
    304       trackmeta->date = strdup(tmp);
    305     }
    306     if (tracknum > 0) {
    307       printf("Track no:  %d\n", tracknum);
    308       trackmeta->tracknumber = tracknum;
    309     }
    310     if (length > 0) {
    311       printf("Length:    %d\n", length);
    312       // Multiply by 1000 since this is in milliseconds
    313       trackmeta->duration = length * 1000;
    314     }
    315     // We should always have this
    316     if (filename != NULL) {
    317       trackmeta->filename = strdup(filename);
    318     }
    319     trackmeta->filesize = filesize;
    320     trackmeta->parent_id = parent_id;
    321     {
    322         int rc;
    323         char *desc = NULL;
    324         LIBMTP_devicestorage_t *pds = NULL;
    325 
    326         if ( 0 != (rc=LIBMTP_Get_Storage(device, LIBMTP_STORAGE_SORTBY_NOTSORTED)) )
    327         {
    328             perror("LIBMTP_Get_Storage()");
    329             exit(-1);
    330         }
    331         for (pds = device->storage; pds != NULL; pds = pds->next)
    332         {
    333             if (pds->id == storageid)
    334             {
    335                 desc = strdup(pds->StorageDescription);
    336                 break;
    337             }
    338         }
    339         if (NULL != desc)
    340         {
    341             printf("Storage ID: %s (%u)\n", desc, storageid);
    342             free(desc);
    343         }
    344         else
    345             printf("Storage ID: %u\n", storageid);
    346         trackmeta->storage_id = storageid;
    347     }
    348 
    349     printf("Sending track...\n");
    350     ret = LIBMTP_Send_Track_From_File(device, from_path, trackmeta, progress, NULL);
    351     printf("\n");
    352     if (ret != 0) {
    353       printf("Error sending track.\n");
    354       LIBMTP_Dump_Errorstack(device);
    355       LIBMTP_Clear_Errorstack(device);
    356     } else {
    357       printf("New track ID: %d\n", trackmeta->item_id);
    358     }
    359 
    360     /* Add here add to album call */
    361     if (palbum)
    362       ret = add_track_to_album(albuminfo, trackmeta);
    363 
    364     LIBMTP_destroy_album_t(albuminfo);
    365     LIBMTP_destroy_track_t(trackmeta);
    366 
    367     return 0;
    368   }
    369   return 0;
    370 }
    371 
    372 void sendtrack_command (int argc, char **argv) {
    373   int opt;
    374   extern int optind;
    375   extern char *optarg;
    376   char *partist = NULL;
    377   char *palbumartist = NULL;
    378   char *pcomposer = NULL;
    379   char *ptitle = NULL;
    380   char *pgenre = NULL;
    381   char *pcodec = NULL;
    382   char *palbum = NULL;
    383   uint16_t tracknum = 0;
    384   uint16_t length = 0;
    385   uint16_t year = 0;
    386   uint16_t quiet = 0;
    387   uint32_t storageid = 0;
    388   while ( (opt = getopt(argc, argv, "qD:t:a:A:w:l:c:g:n:d:y:s:")) != -1 ) {
    389     switch (opt) {
    390     case 't':
    391       ptitle = strdup(optarg);
    392       break;
    393     case 'a':
    394       partist = strdup(optarg);
    395       break;
    396     case 'A':
    397       palbumartist = strdup(optarg);
    398       break;
    399     case 'w':
    400       pcomposer = strdup(optarg);
    401       break;
    402     case 'l':
    403       palbum = strdup(optarg);
    404       break;
    405     case 'c':
    406       pcodec = strdup(optarg); // FIXME: DSM check for MP3, WAV or WMA
    407       break;
    408     case 'g':
    409       pgenre = strdup(optarg);
    410       break;
    411     case 'n':
    412       tracknum = atoi(optarg);
    413       break;
    414     case 's':
    415       storageid = (uint32_t) strtoul(optarg, NULL, 0);
    416       break;
    417     case 'd':
    418       length = atoi(optarg);
    419       break;
    420     case 'y':
    421       year = atoi(optarg);
    422       break;
    423     case 'q':
    424       quiet = 1;
    425       break;
    426     default:
    427       sendtrack_usage();
    428     }
    429   }
    430   argc -= optind;
    431   argv += optind;
    432 
    433   if ( argc != 2 ) {
    434     printf("You need to pass a filename and destination.\n");
    435     sendtrack_usage();
    436     return;
    437   }
    438 
    439   checklang();
    440 
    441   printf("%s,%s,%s,%s,%s,%s,%s,%s,%d%d,%d,%u\n",argv[0],argv[1],partist,palbumartist,ptitle,pgenre,palbum,pcomposer,tracknum, length, year, storageid);
    442   sendtrack_function(argv[0],argv[1],partist,palbumartist,ptitle,pgenre,palbum,pcomposer, tracknum, length, year, storageid);
    443 }
    444