• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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@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@adebenham.com>
12   * Copyright (C) 2008 Nicolas Pennequin <nicolas.pennequin@free.fr>
13   * Copyright (C) 2008 Joseph Nahmias <joe@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  
sendtrack_usage(void)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  
prompt(const char * prompt,char * buffer,size_t bufsz,int required)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  
add_track_to_album(LIBMTP_album_t * albuminfo,LIBMTP_track_t * trackmeta)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  
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)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  
sendtrack_command(int argc,char ** argv)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