#!/usr/bin/pythonw
#Copyright 2006 Jerry Stratton
#Released under the Gnu General Public License version 3

import appscript
import optparse
import locale

#en_US shouldn't be necessary, but Mac OS X does not appear to have a default set
locale.setlocale(locale.LC_NUMERIC, 'en_US')

parser = optparse.OptionParser()
parser.add_option("-a", "--next", dest="ahead", action="store_true", default=False)
parser.add_option("-b", "--prev", dest="back", action="store_true", default=False)
parser.add_option("-d", "--visuals", dest="displayvisuals", action="store_true", default=False)
parser.add_option("-e", "--extended", dest="extended", action="store_true", default=False, help="display extended info about the track")
parser.add_option("-f", "--find", dest="find", metavar='<text to search for>', help="find track matching text")
parser.add_option("-g", "--play", dest="go", action="store_true", default=False)
parser.add_option("-i", "--index", dest="index", metavar='<index of track>', help="play or show this track")
parser.add_option("-l", "--library", dest="library", metavar='<name of playlist>', help="switch to playing chosen playlist")
parser.add_option("-m", "--main", dest="main", help="search in main library rather than current playlist")
parser.add_option("-n", "--noplay", dest="noplay", action="store_true", default=False, help="do not play found track")
parser.add_option("-p", "--pause", dest="pause", action="store_true", default=False)
parser.add_option("-r", "--replay", dest="replay", action="store_true", default=False, help="return to start of track")
parser.add_option("-s", "--shuffle", dest="shuffle", action="store_true", default=False, help="shuffle or reshuffle current library")
parser.add_option("-u", "--upcoming", dest="upcoming", metavar='<number to show>')
parser.add_option("-v", "--volume", dest="volume", metavar='<0 to 100> or show')
parser.add_option("-w", "--where", dest="where", metavar='<title, artist, or album>', help="confine search to title, artist, or album")
(options, args) = parser.parse_args()

#reveal a different playlist
#tell application "iTunes"
#	set myList to playlists where name is "Limited A-List"
#	reveal first item of myList
#end tell

class smarterTrack:
	def __init__(self, track):
		self.track = track

	def name(self):
		return self.track.name().encode('utf_8', 'replace')
	
	def artist(self):
		return self.track.artist().encode('utf_8', 'replace')
	
	def album(self):
		return self.track.album().encode('utf_8', 'replace')
	
	def genre(self):
		return self.track.genre().encode('utf_8', 'replace')
	
	def time(self):
		return self.track.time()
	
	def year(self):
		return self.track.year()
	
	def played_date(self):
		date = self.track.played_date()
		if date == appscript.k.MissingValue:
			return "Never"
		else:
			return date

	def stars(self):
		rating = self.track.rating()/20
		rating = "*"*rating
		return rating
	
	def ID(self):
		return self.track.database_ID()

	def index(self):
		return self.track.index()

	def position(self):
		return self.track.index()

	def bug(self):
		title, artist, album, year, duration, rating = self.name(), self.artist(), self.album(), self.year(), self.time(), self.stars()
		
		print title.upper(), "(" + duration + ")"
		print "\t", artist, "("+ album + ", " + str(year) + ")"
		if extendedInfo:
			playlist = self.playlist()
			listCount = playlist.count(each=appscript.k.track)
    			listCount = locale.format("%i", listCount, True)
			print "\tGenre:", self.track.genre()
			print "\tLast Played:", self.played_date()
			print "\tPlaycount:", self.track.played_count()
			if self.isCurrent():
				print "\tRemaining Time:", self.ToGo()
			else:
				print "\tIndex:", self.index()
			print "\tPlaylist:", playlist.name(), "(" + listCount, "songs)"
		print "\t", rating

	def line(self):
		print "\t", self.position(), "-", self.name(), "by", self.artist(), "on", self.album(), "("+self.time()+")"

	def playlist(self):
		playlist = self.track.container()
		return playlist
	
	def next(self):
		myIndex = self.index()
		playlist = self.playlist()
		listCount = playlist.count(each=appscript.k.track)
		if myIndex < listCount:
			foundTrack = smarterTrack(playlist.tracks[myIndex+1])
			return foundTrack
		else:
			return None

	def previous(self):
		myIndex = self.track.index()
		if myIndex > 1:
			playlist = self.playlist()
			foundTrack = smarterTrack(playlist.tracks[myIndex-1])
			return foundTrack
		else:
			return None

	def isCurrent(self):
		currentTrack = iTunes.current_track()
		if self.track == currentTrack:
			return True
		else:
			return False

	def ToGo(self):
		myDuration = self.track.duration()
		currentPosition = iTunes.player_position()
		remaining = myDuration-currentPosition
		hours = int(remaining/3600)
		seconds = remaining-hours*3600
		minutes = int(seconds/60)
		seconds = seconds - minutes*60
		if hours:
			remaining = hours + ":"
		else:
			remaining = ""
		if minutes < 10 and hours:
			remaining += "0"
		remaining += str(minutes) + ":"
		if seconds < 10:
			remaining += "0"
		remaining += str(seconds)

		return remaining

	def upcoming(self, upCount):
		myIndex = self.track.index()
		playlist = self.playlist()
		listCount = playlist.count(each=appscript.k.track)
		if myIndex < listCount:
			startIndex = myIndex + 1
			endIndex = min(startIndex+upCount, listCount)
			for counter in range(startIndex, endIndex):
				nextTrack = smarterTrack(playlist.tracks[counter])
				nextTrack.line()
		else:
			print "Currently playing final track:"
			self.line()

iTunes = appscript.app("iTunes")
isPlaying = iTunes.player_state() == appscript.k.playing

showTrackInfo = True

if options.pause:
	if not isPlaying:
		print "iTunes is already not playing."
	else:
		iTunes.pause()
	showTrackInfo = False

if options.go:
	if isPlaying:
		print "iTunes is already playing."
	else:
		iTunes.play()
		isPlaying = iTunes.player_state() == appscript.k.playing

if options.displayvisuals:
	if iTunes.visuals_enabled():
		print "Turning visuals off"
		iTunes.visuals_enabled.set(False)
	else:
		print "Turning visuals on"
		iTunes.visuals.full_screen.set(True)
		iTunes.visuals_enabled.set(True)
	showTrackInfo = False

if options.shuffle:
	if iTunes.current_playlist.shuffle.get() == True:
		iTunes.current_playlist.shuffle.set(False)
	iTunes.current_playlist.shuffle.set(True)
	print "Shuffled."
	
if options.volume:
	showTrackInfo = False
	newVolume = options.volume
	currentVolume = iTunes.sound_volume()
	if newVolume == 'show':
		print "Volume is", currentVolume	
	else:
		if newVolume.isdigit():
			volume = int(newVolume)
			if volume > 0 and volume <= 100:
				if volume == currentVolume:
					print "Volume is already", currentVolume
				else:
					iTunes.sound_volume.set(volume)
					print "Set volume to", volume
			else:
				print "Volume must be between 1 and 100"
		else:
			print "Volume must be an integer between 1 and 100"

if options.replay:
	iTunes.back_track()

if options.extended:
	extendedInfo = True
else:
	extendedInfo = False

#if there is only one found track, should we play it?
playFoundTrack = True
if options.noplay:
	playFoundTrack = False

#should we look in the main library or the current playlist?
mainLibrary = False
if options.main:
	mainLibrary = True


if options.library:
	wantList = options.library
	if wantList == iTunes.current_playlist().name():
		print "Already listening to playlist", wantList
	else:
		playlist = iTunes.playlists[appscript.its.name == wantList].get()

		if len(playlist) > 1:
			print "For some reason, found multiple entries. This should never happen."
		elif len(playlist) == 0:
			print "Could not find a playlist named", wantList
			playlist = iTunes.playlists[appscript.its.name.contains(wantList)].get()
			if len(playlist) > 1:
				print "These playlists contain", wantList
				for playlist in playlist:
					print "\t", playlist.name()
				playlist = False
			elif len(playlist) == 1:
				playlist = playlist[0]
				print "Found", playlist.name(), "instead."
			showTrackInfo = False
		else:
			playlist = playlist[0]
		if playlist and not options.noplay:
			print "Switching to", playlist.name()
			playlist.play()

if options.ahead or options.back:
	if isPlaying:
		currentTrack = smarterTrack(iTunes.current_track())
		if options.ahead:
			otherTrack = currentTrack.next()
			trackname = "subsequent"
		else:
			otherTrack = currentTrack.previous()
			trackname = "previous"
		if otherTrack:
			if playFoundTrack:
				iTunes.play(otherTrack.track)
			else:
				otherTrack.bug()
				showTrackInfo = False
		else:
			print "No", trackname, "track."
			showTrackInfo = False
	else:
		print "iTunes is not currently playing anything"
		showTrackInfo = False

if options.upcoming:
	showTrackInfo = False
	if isPlaying:
		currentTrack = smarterTrack(iTunes.current_track())
	else:
		playlist = iTunes.browser_windows.view.get()[0]
		currentTrack = smarterTrack(playlist.tracks[1])

	currentTrack.upcoming(int(options.upcoming))


if options.index:
	trackNumber = int(options.index)
	if mainLibrary:
		playlist = iTunes.playlists[1]
	else:
		playlist = iTunes.current_playlist()
	foundTrack = smarterTrack(playlist.tracks[trackNumber])
	if playFoundTrack:
		iTunes.play(foundTrack.track)
	else:
		foundTrack.bug()
		showTrackInfo = False

if options.find:
	showTrackInfo = False
	if mainLibrary:
		playlist = iTunes.playlists[1]
	else:
		playlist = iTunes.current_playlist()
	searchText = options.find
	searchWhere = appscript.k.all
	if options.where:
		where = options.where
		if where == 'artist':
			searchWhere = appscript.k.artists
		elif where == 'title':
			searchWhere = appscript.k.songs
		elif where == 'album':
			searchWhere = appscript.k.albums
		else:
			print "I don't understand how to search in", where, "so I am going to search everything"

	foundList = iTunes.search(playlist, for_=searchText, only=searchWhere)
	
	#check the main library if it isn't in the current play list
	if len(foundList) == 0:
		print "No tracks found matching", searchText, "in", playlist.name()
		if playlist.name() != 'Library':
			#library_playlist doesn't currently work; but the first one in the list is the library
			playlist = iTunes.playlists[1]
			playFoundTrack = False
			foundList = iTunes.search(playlist, for_=searchText, only=searchWhere)
			if len(foundList) == 0:
				print "No tracks found in", playlist.name(), "either."
			else:
				print "But we did find it in", playlist.name()

	if len(foundList) == 1:
		foundTrack = foundList[0]
		if playFoundTrack:
			iTunes.play(foundTrack)
			showTrackInfo = True
		else:
			smarterTrack(foundTrack).bug()

	elif len(foundList) > 1:
		print "Found", len(foundList), "tracks in", playlist.name()
		for track in foundList:
			track = smarterTrack(track)
			track.line()

if showTrackInfo:
	if isPlaying:
		currentTrack = smarterTrack(iTunes.current_track())
		currentTrack.bug()
	else:
		print "iTunes is not currently playing anything"
