# ContentsHandler.py # # Copyright (c) 2006 INdT (Instituto Nokia de Technologia) # # Author: Kenneth Rohde Christiansen # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License as # published by the Free Software Foundation; either version 2 of the # License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 # USA import urllib import ID3 import M4ATags import os import sys import gtk import Utils import PlaylistParserPLS def remove_playlist_if_exists(playlist_name, device_path): pathname = Utils.append_os_path(device_path, "Music/") if os.path.exists(os.path.join(pathname, playlist_name + ".pls")): ## Code that removes existing playlist and deleted the files ## not in use by other playlists on the device. ## ## The algorithm is as follows: ## ## o read files from playlist - put in dictionary ## o delete playlist ## o read remote playlists again (not without that deleted playlist) ## o iterate through the playlists and look up in the hash and remove if found ## ## Now we will have a hash only consisting of the songs that are not in other ## playlists and that we can safely delete. old_pls = open(os.path.join(pathname, playlist_name + ".pls"), "r") ## 1: read files from playlist - put in dictionary songs_to_delete = {} lines = old_pls.readlines()[:] for line in lines: if line.startswith ("File"): song_location = pathname + line.split("=")[1].strip("\n") if not os.path.exists(song_location): continue songs_to_delete[song_location] = True ## 2: delete playlist os.remove (pathname + playlist_name + ".pls") os.remove (pathname + playlist_name + ".m3u") ## 3: read remote playlists again (not without that deleted playlist) playlists_left = PlaylistParserPLS.parse_playlists(device_path) ## 4: iterate through the playlists and look up in the hash and remove if found for remote_playlist in playlists_left: for song_location in remote_playlist[2]: songs_to_delete[song_location] = False for song_location in songs_to_delete.keys(): if songs_to_delete[song_location] == True: os.remove(song_location) album_dir = os.path.dirname(song_location) artist_dir = os.path.split(album_dir)[0] #print album_dir, artist_dir # if empty if not os.listdir(album_dir): os.rmdir(album_dir) if not os.listdir(artist_dir): os.rmdir(artist_dir) def get_song_info_as_text(song_path): temp1 = song_path.rsplit("/", 1)[-1] temp2 = temp1.rsplit(".", 1) filename = temp2[0] fileext = temp2[-1] (artist, title, album, track_no, length) = get_song_info(song_path) return "%s - %s" % (artist, title) def add_playlist(parent, view, playlist, playlist_name, device_path): print "Transferring playlist %s" % playlist_name songnumber = 0 playlist_error = False; pathname = Utils.append_os_path(device_path, "Music/") if not os.path.exists(pathname): os.makedirs (pathname) remove_playlist_if_exists(playlist_name, device_path) # create new playlist to fill: playlist_data = [] for song in playlist[2]: if view.model.stop_transfer == True: break location = song[0] songnumber += 1 temp1 = location.rsplit("/", 1)[-1] temp2 = temp1.rsplit(".", 1) filename = temp2[0] fileext = temp2[-1] (artist, title, album, track_no, length) = get_song_info(location) if track_no != -1: remote_filename = u"%s/%s/%s. %s.%s" % (artist, album, track_no, title, fileext) else: remote_filename = u"%s/%s/%s.%s" % (artist, album, title, fileext) remote_filename = Utils.to_os_path(remote_filename) playlist_data_file = remote_filename playlist_data_title = "%s - %s\n" % (artist, title) playlist_data_length = length rel_pathname = "Music/%s/%s" % (artist, album) pathname = Utils.append_os_path(device_path, rel_pathname) rel_filename = "Music/%s" % (remote_filename) filename = Utils.append_os_path(device_path, rel_filename) # Remove illegal chars filename = filename.replace(":", "_") if not os.path.exists(pathname): os.makedirs (pathname) try: if os.path.getsize(location) / 1024 < Utils.freespace(device_path): view.model.transferred_data += (os.path.getsize(location) / 1024) + 100 #gtk.gdk.threads_enter() view.progress_dialog.set_theme_icon("audio-x-generic") view.progress_dialog.set_text("Transferring " + playlist_name + "...") #gtk.gdk.threads_leave() print "Transfering %s (%s)" % (filename, location.split("/")[-1]) Utils.transfer_file(location, filename) #gtk.gdk.threads_enter() view.progress_dialog.set_progress(view.model.transferred_data, view.model.space_required) #gtk.gdk.threads_leave() view.refresh_freespace() else: print " WARNING: Ran out of space, ignoring current song (%s - %s)" % (artist, title) songnumber -= 1 except IOError, e: raise e songnumber -= 1 break playlist_data.append( (playlist_data_file, playlist_data_title, playlist_data_length) ) playlist_error = write_pls_playlist(playlist_name, playlist_data, device_path) if not playlist_error: playlist_error = write_m3u_playlist(playlist_name, playlist_data, device_path) if playlist_error: dialog = gtk.MessageDialog(parent, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_ERROR, gtk.BUTTONS_CLOSE, "Device ran out of space, playlist not updated") dialog.set_title("No space left on device") dialog.show() def write_m3u_playlist(playlist_name, playlist_data, device_path): pathname = Utils.append_os_path(device_path, "Music/") playlist_error = False try: m3u = open(pathname + ".tmp-" + playlist_name + ".m3u", "w") m3u.write("#EXTM3U\n") songnumber = 1 for playlist_entry in playlist_data: line = "#EXTINF:%s,%s\n" % ("-1", playlist_entry[1].strip()) line += "%s\n" % (playlist_entry[0].strip()) m3u.write(line) m3u.flush() songnumber += 1 m3u.close(); if not os.path.exists(pathname + ".tmp-" + playlist_name + ".m3u"): playlist_error = True if not Utils.BUFFER_SIZE < Utils.freespace (device_path): playlist_error = True if not os.path.getsize(pathname + ".tmp-" + playlist_name + ".m3u") < Utils.freespace (device_path): playlist_error = True Utils.transfer_file(pathname + ".tmp-" + playlist_name + ".m3u", pathname + playlist_name + ".m3u") except IOError, e: playlist_error = True return playlist_error def write_pls_playlist(playlist_name, playlist_data, device_path): pathname = Utils.append_os_path(device_path, "Music/") playlist_error = False try: pls = open(pathname + ".tmp-" + playlist_name + ".pls", "w") pls.write("[playlist]\n") songnumber = 1 for playlist_entry in playlist_data: line = "File%s=%s\n" % (songnumber, playlist_entry[0].strip()) line += "Title%s=%s\n" % (songnumber, playlist_entry[1].strip()) line += "Length%s:%s\n" % (songnumber, playlist_entry[2]) pls.write(line) pls.flush() songnumber += 1 pls.write("NumberOfEntries=%s\nVersion=2" % songnumber) pls.close(); if not os.path.exists(pathname + ".tmp-" + playlist_name + ".pls"): playlist_error = True if not Utils.BUFFER_SIZE < Utils.freespace (device_path): playlist_error = True if not os.path.getsize(pathname + ".tmp-" + playlist_name + ".pls") < Utils.freespace (device_path): playlist_error = True Utils.transfer_file(pathname + ".tmp-" + playlist_name + ".pls", pathname + playlist_name + ".pls") except IOError, e: playlist_error = True return playlist_error def remove_photoalbum_if_exists(photoalbum_name, device_path): pathname = Utils.append_os_path(device_path, "Photos/") if os.path.exists(pathname + photoalbum_name): for current_file in os.listdir(pathname + photoalbum_name): os.remove(pathname + photoalbum_name + "/" + current_file) os.rmdir(pathname + photoalbum_name) def add_photoalbum(parent, view, photoalbum, photoalbum_name, device_path): songnumber = 0 pathname = Utils.append_os_path(device_path, "Photos/") if not os.path.exists(pathname): os.makedirs (pathname) if os.path.exists(pathname + photoalbum_name): remove_photoalbum_if_exists(photoalbum_name, device_path) os.makedirs(pathname + photoalbum_name) else: os.makedirs(pathname + photoalbum_name) for basepath in os.listdir(photoalbum[2]): if view.model.stop_transfer == True: break current_path = os.path.join(photoalbum[2], basepath) # F-Spot uses subdirs with the day number # code should be made more general if os.path.isdir(current_path): for basepath in os.listdir(current_path): if view.model.stop_transfer == True: break source = os.path.join(current_path, basepath) target = os.path.join(pathname + photoalbum_name, basepath) copy_photo(view, photoalbum_name, source, target, device_path) else: source = current_path target = os.path.join(pathname + photoalbum_name, basepath) copy_photo(view, photoalbum_name, source, target, device_path) def copy_photo(view, photoalbum_name, source, target, device_path): try: if os.path.getsize(source) / 1024 < Utils.freespace(device_path): view.model.transferred_data += (os.path.getsize(source) / 1024) #gtk.gdk.threads_enter() view.progress_dialog.set_theme_icon("image-x-generic") view.progress_dialog.set_text("Transferring " + photoalbum_name + "...") #gtk.gdk.threads_leave() Utils.transfer_file(source, target) #gtk.gdk.threads_enter() view.progress_dialog.set_progress(view.model.transferred_data, view.model.space_required) #gtk.gdk.threads_leave() view.refresh_freespace() else: print " WARNING: Ran out of space, ignoring current photo (%s - %s)" % (artist, title) except IOError, e: print "error" def get_song_info(location): tracknumber = -1 length = -1 if location.endswith('m4a'): info = M4ATags.M4ATags(location) artist = info.get('Artist') title = info.get('Title') album = info.get('Album') else: try: info = ID3.ID3(location) try: artist = Utils.unicodify(info.artist) except AttributeError, e: artist = u"Unknown" try: album = Utils.unicodify(info.album) except AttributeError, e: album = u"Unknown" try: title = Utils.unicodify(info.title) except AttributeError, e: title = Utils.unicodify(filename) except ID3.InvalidTagError, e: artist = u"Unknown" album = u"Unknown" title = u"Unknown" if artist == "": artist = u"Unknown" if album == "": album = u"Unknown" if title == "": title = u"Unknown" return (artist, title, album, tracknumber, length)