~ubuntu-branches/ubuntu/vivid/gpodder/vivid-proposed

« back to all changes in this revision

Viewing changes to src/gpodder/sync.py

  • Committer: Bazaar Package Importer
  • Author(s): tony mancill
  • Date: 2010-12-05 17:08:02 UTC
  • mfrom: (5.3.2 experimental) (5.2.10 sid)
  • Revision ID: james.westby@ubuntu.com-20101205170802-qbsq7r331j21np1i
Tags: 2.10-1
* New upstream release
* Upload to unstable.

Show diffs side-by-side

added added

removed removed

Lines of Context:
45
45
 
46
46
pymtp_available = True
47
47
try:
48
 
    import pymtp
 
48
    import gpodder.gpopymtp as pymtp
49
49
except:
50
50
    pymtp_available = False
51
 
    log('(gpodder.sync) Could not find pymtp.')
52
 
 
53
 
try:
54
 
    import mad
55
 
except:
56
 
    log('(gpodder.sync) Could not find pymad')
 
51
    log('(gpodder.sync) Could not load gpopymtp (libmtp not installed?).')
57
52
 
58
53
try:
59
54
    import eyeD3
66
61
    log('(gpodder.sync) Could not find Python Imaging Library (PIL)')
67
62
 
68
63
# Register our dependencies for the synchronization module
69
 
services.dependency_manager.depend_on(_('iPod synchronization'), _('Support synchronization of podcasts to Apple iPod devices via libgpod.'), ['gpod', 'mad', 'eyeD3'], [])
70
 
services.dependency_manager.depend_on(_('MTP device synchronization'), _('Support synchronization of podcasts to devices using the Media Transfer Protocol via pymtp.'), ['pymtp'], [])
 
64
services.dependency_manager.depend_on(_('iPod synchronization'), _('Support synchronization of podcasts to Apple iPod devices via libgpod.'), ['gpod', 'gst'], [])
71
65
services.dependency_manager.depend_on(_('iPod OGG converter'), _('Convert OGG podcasts to MP3 files on synchronization to iPods using oggdec and LAME.'), [], ['oggdec', 'lame'])
72
66
services.dependency_manager.depend_on(_('iPod video podcasts'), _('Detect video lengths via MPlayer, to synchronize video podcasts to iPods.'), [], ['mplayer'])
73
67
services.dependency_manager.depend_on(_('Rockbox cover art support'), _('Copy podcast cover art to filesystem-based MP3 players running Rockbox.org firmware. Needs Python Imaging.'), ['Image'], [])
77
71
import glob
78
72
import time
79
73
 
 
74
if pymtp_available:
 
75
    class MTP(pymtp.MTP):
 
76
        sep = os.path.sep
 
77
 
 
78
        def __init__(self):
 
79
            pymtp.MTP.__init__(self)
 
80
            self.folders = {}
 
81
 
 
82
        def connect(self):
 
83
            pymtp.MTP.connect(self)
 
84
            self.folders = self.unfold(self.mtp.LIBMTP_Get_Folder_List(self.device))
 
85
 
 
86
        def get_folder_list(self):
 
87
            return self.folders
 
88
 
 
89
        def unfold(self, folder, path=''):
 
90
            result = {}
 
91
            while folder:
 
92
                folder = folder.contents
 
93
                name = self.sep.join([path, folder.name]).lstrip(self.sep)
 
94
                result[name] = folder.folder_id
 
95
                if folder.child:
 
96
                    result.update(self.unfold(folder.child, name))
 
97
                folder = folder.sibling
 
98
            return result
 
99
 
 
100
        def mkdir(self, path):
 
101
            folder_id = 0
 
102
            prefix = []
 
103
            parts = path.split(self.sep)
 
104
            while parts:
 
105
                prefix.append(parts[0])
 
106
                tmpath = self.sep.join(prefix)
 
107
                if self.folders.has_key(tmpath):
 
108
                    folder_id = self.folders[tmpath]
 
109
                else:
 
110
                    folder_id = self.create_folder(parts[0], parent=folder_id)
 
111
                    # log('Creating subfolder %s in %s (id=%u)' % (parts[0], self.sep.join(prefix), folder_id))
 
112
                    tmpath = self.sep.join(prefix + [parts[0]])
 
113
                    self.folders[tmpath] = folder_id
 
114
                # log(">>> %s = %s" % (tmpath, folder_id))
 
115
                del parts[0]
 
116
            # log('MTP.mkdir: %s = %u' % (path, folder_id))
 
117
            return folder_id
80
118
 
81
119
def open_device(config):
82
120
    device_type = config.device_type
104
142
        log('Please install MPlayer for track length detection.')
105
143
 
106
144
    try:
107
 
        mad_info = mad.MadFile(filename)
108
 
        return int(mad_info.total_time())
109
 
    except:
110
 
        pass
111
 
    
112
 
    try:
113
145
        eyed3_info = eyeD3.Mp3AudioFile(filename)
114
146
        return int(eyed3_info.getPlayTime()*1000)
115
147
    except:
117
149
 
118
150
    return int(60*60*1000*3) # Default is three hours (to be on the safe side)
119
151
 
120
 
 
121
152
class SyncTrack(object):
122
153
    """
123
154
    This represents a track that is on a device. You need
306
337
            gpod.itdb_write(self.itdb, None)
307
338
            self.itdb = None
308
339
            
 
340
            if self._config.ipod_write_gtkpod_extended:
 
341
                self.notify('status', _('Writing extended gtkpod database'))
 
342
                ext_filename = os.path.join(self.mountpoint, 'iPod_Control', 'iTunes', 'iTunesDB.ext')
 
343
                idb_filename = os.path.join(self.mountpoint, 'iPod_Control', 'iTunes', 'iTunesDB')
 
344
                if os.path.exists(ext_filename) and os.path.exists(idb_filename):
 
345
                    try:
 
346
                        db = gpod.ipod.Database(self.mountpoint)
 
347
                        gpod.gtkpod.parse(ext_filename, db, idb_filename)
 
348
                        gpod.gtkpod.write(ext_filename, db, idb_filename)
 
349
                        db.close()
 
350
                    except:
 
351
                        log('Error when writing iTunesDB.ext', sender=self, traceback=True)
 
352
                else:
 
353
                    log('I could not find %s or %s. Will not update extended gtkpod DB.', ext_filename, idb_filename, sender=self)
 
354
            else:
 
355
                log('Not writing extended gtkpod DB. Set "ipod_write_gpod_extended" to True if I should write it.', sender=self)            
 
356
            
 
357
            
309
358
        Device.close(self)
310
359
        return True
311
360
 
440
489
        gpod.itdb_track_add(self.itdb, track, -1)
441
490
        gpod.itdb_playlist_add_track(self.master_playlist, track, -1)
442
491
        gpod.itdb_playlist_add_track(self.podcasts_playlist, track, -1)
443
 
        gpod.itdb_cp_track_to_ipod(track, str(local_filename), None)
 
492
        copied = gpod.itdb_cp_track_to_ipod(track, str(local_filename), None)
 
493
 
 
494
        if copied and gpodder.user_hooks is not None:
 
495
            gpodder.user_hooks.on_file_copied_to_ipod(self, local_filename)
444
496
 
445
497
        # If the file has been converted, delete the temporary file here
446
498
        if local_filename != original_filename:
551
603
        else:
552
604
            folder = self.destination
553
605
 
 
606
        folder = util.sanitize_encoding(folder)
 
607
 
554
608
        from_file = util.sanitize_encoding(self.convert_track(episode))
555
609
        filename_base = util.sanitize_filename(episode.sync_filename(self._config.custom_sync_name_enabled, self._config.custom_sync_name), self._config.mp3_player_max_filename_length)
556
610
 
562
616
        if os.path.splitext(to_file)[0] == '':
563
617
            to_file = os.path.basename(from_file)
564
618
 
565
 
        to_file = os.path.join(folder, to_file)
 
619
        to_file = util.sanitize_encoding(os.path.join(folder, to_file))
566
620
 
567
621
        if not os.path.exists(folder):
568
622
            try:
595
649
 
596
650
        if not os.path.exists(to_file):
597
651
            log('Copying %s => %s', os.path.basename(from_file), to_file.decode(util.encoding), sender=self)
598
 
            return self.copy_file_progress(from_file, to_file)
 
652
            copied = self.copy_file_progress(from_file, to_file)
 
653
            if copied and gpodder.user_hooks is not None:
 
654
                gpodder.user_hooks.on_file_copied_to_filesystem(self, from_file, to_file)
 
655
            return copied
599
656
 
600
657
        return True
601
658
 
775
832
        Device.__init__(self, config)
776
833
        self.__model_name = None
777
834
        try:
778
 
            self.__MTPDevice = pymtp.MTP()
 
835
            self.__MTPDevice = MTP()
779
836
        except NameError, e:
780
837
            # pymtp not available / not installed (see bug 924)
781
838
            log('pymtp not found: %s', str(e), sender=self)
900
957
    def add_track(self, episode):
901
958
        self.notify('status', _('Adding %s...') % episode.title)
902
959
        filename = str(self.convert_track(episode))
903
 
        log("sending " + filename + " (" + episode.title + ").", sender=self)
 
960
        log("sending %s (%s).", filename, episode.title, sender=self)
904
961
 
905
962
        try:
906
963
            # verify free space
920
977
            metadata.date = self.__date_to_mtp(episode.pubDate)
921
978
            metadata.duration = get_track_length(str(filename))
922
979
 
 
980
            folder_name = ''
 
981
            if episode.mimetype.startswith('audio/') and self._config.mtp_audio_folder:
 
982
                folder_name = self._config.mtp_audio_folder
 
983
            if episode.mimetype.startswith('video/') and self._config.mtp_video_folder:
 
984
                folder_name = self._config.mtp_video_folder
 
985
            if episode.mimetype.startswith('image/') and self._config.mtp_image_folder:
 
986
                folder_name = self._config.mtp_image_folder
 
987
 
 
988
            if folder_name != '' and self._config.mtp_podcast_folders:
 
989
                folder_name += os.path.sep + str(episode.channel.title)
 
990
 
 
991
            # log('Target MTP folder: %s' % folder_name)
 
992
 
 
993
            if folder_name == '':
 
994
                folder_id = 0
 
995
            else:
 
996
                folder_id = self.__MTPDevice.mkdir(folder_name)
 
997
 
923
998
            # send the file
924
 
            self.__MTPDevice.send_track_from_file(filename,
925
 
                    util.sanitize_filename(metadata.title)+episode.extension(),
926
 
                    metadata, 0, callback=self.__callback)
 
999
            to_file = util.sanitize_filename(metadata.title) + episode.extension()
 
1000
            self.__MTPDevice.send_track_from_file(filename, to_file,
 
1001
                    metadata, folder_id, callback=self.__callback)
 
1002
            if gpodder.user_hooks is not None:
 
1003
                gpodder.user_hooks.on_file_copied_to_mtp(self, filename, to_file)
927
1004
        except:
928
1005
            log('unable to add episode %s', episode.title, sender=self, traceback=True)
929
1006
            return False