All pastes #253392 Raw Edit

Something

public text v1 · immutable
#253392 ·published 2006-11-20 18:45 UTC
rendered paste body
# ContentsHandler.py 
#  
#  Copyright (c) 2006 INdT (Instituto Nokia de Technologia)
#  
#  Author: Kenneth Rohde Christiansen <kenneth.christiansen@gmail.com>
# 
#  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 <i>" + playlist_name + "</i>...")
				#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 <i>" + photoalbum_name + "</i>...")
			#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)