source: trunk/StreamVision/StreamVision.py@ 234

Last change on this file since 234 was 234, checked in by Nicholas Riley, 16 years ago

StreamVision.py: switch to Stations playlist if we're viewing the iPod read-only or something equally useless

File size: 6.5 KB
Line 
1#!/usr/bin/pythonw
2# -*- coding: utf-8 -*-
3
4from appscript import app, k, its, CommandError
5from AppKit import NSApplication, NSBeep, NSSystemDefined, NSURL, NSWorkspace
6from Foundation import NSDistributedNotificationCenter
7from PyObjCTools import AppHelper
8from Carbon.CarbonEvt import RegisterEventHotKey, GetApplicationEventTarget
9from Carbon.Events import cmdKey, shiftKey, controlKey
10import struct
11import scrape
12import HotKey
13
14GROWL_APP_NAME = 'StreamVision'
15NOTIFICATION_TRACK_INFO = 'iTunes Track Info'
16NOTIFICATIONS_ALL = [NOTIFICATION_TRACK_INFO]
17
18kEventHotKeyPressedSubtype = 6
19kEventHotKeyReleasedSubtype = 9
20
21growl = app('GrowlHelperApp')
22
23growl.register(
24 as_application=GROWL_APP_NAME,
25 all_notifications=NOTIFICATIONS_ALL,
26 default_notifications=NOTIFICATIONS_ALL,
27 icon_of_application='iTunes.app')
28 # if we leave off the .app, we can get Classic iTunes's icon
29
30def growlNotify(title, description, **kw):
31 growl.notify(
32 with_name=NOTIFICATION_TRACK_INFO,
33 title=title,
34 description=description,
35 application_name=GROWL_APP_NAME,
36 **kw)
37
38def radioParadiseURL():
39 session = scrape.Session()
40 session.go('http://www2.radioparadise.com/nowplay_b.php')
41 return session.region.firsttag('a')['href']
42
43def cleanStreamTitle(title):
44 if title == k.MissingValue:
45 return ''
46 title = title.split(' [')[0] # XXX move to description
47 title = title.replace('`', u'’')
48 return title
49
50def cleanStreamTrackName(name):
51 name = name.split('. ')[0]
52 name = name.split(': ')[0]
53 name = name.split(' - ')
54 if len(name) > 1:
55 name = ' - '.join(name[:-1])
56 else:
57 name = name[0]
58 return name
59
60def iTunesApp(): return app(id='com.apple.iTunes')
61def XTensionApp(): return app(creator='SHEx')
62
63HAVE_XTENSION = False
64try:
65 XTensionApp()
66 HAVE_XTENSION = True
67except:
68 pass
69
70class StreamVision(NSApplication):
71
72 hotKeyActions = {}
73 hotKeys = []
74
75 def displayTrackInfo(self):
76 iTunes = iTunesApp()
77
78 trackClass = iTunes.current_track.class_.get()
79 trackName = ''
80 if trackClass != k.Property:
81 trackName = iTunes.current_track.name.get()
82
83 if iTunes.player_state.get() != k.playing:
84 growlNotify('iTunes is not playing.', trackName)
85 return
86 if trackClass == k.URL_track:
87 growlNotify(cleanStreamTitle(iTunes.current_stream_title.get()),
88 cleanStreamTrackName(trackName))
89 return
90 if trackClass == k.Property:
91 growlNotify('iTunes is playing.', '')
92 return
93 kw = {}
94 # XXX iTunes doesn't let you get artwork for shared tracks
95 if trackClass != k.shared_track:
96 artwork = iTunes.current_track.artworks.get()
97 if artwork:
98 kw['pictImage'] = artwork[0].data.get()
99 growlNotify(trackName + ' ' +
100 '★' * (iTunes.current_track.rating.get() / 20),
101 iTunes.current_track.album.get() + "\n" +
102 iTunes.current_track.artist.get(),
103 **kw)
104
105 def goToSite(self):
106 iTunes = iTunesApp()
107 if iTunes.player_state.get() == k.playing:
108 url = iTunes.current_stream_URL.get()
109 if url:
110 if 'radioparadise.com' in url:
111 url = radioParadiseURL()
112 NSWorkspace.sharedWorkspace().openURL_(NSURL.URLWithString_(url))
113 return
114 NSBeep()
115
116 def registerHotKey(self, func, keyCode, mods=0):
117 hotKeyRef = RegisterEventHotKey(keyCode, mods, (0, 0),
118 GetApplicationEventTarget(), 0)
119 self.hotKeys.append(hotKeyRef)
120 self.hotKeyActions[HotKey.HotKeyAddress(hotKeyRef)] = func
121
122 def incrementRatingBy(self, increment):
123 iTunes = iTunesApp()
124 rating = iTunes.current_track.rating.get()
125 rating += increment
126 if rating < 0:
127 rating = 0
128 NSBeep()
129 elif rating > 100:
130 rating = 100
131 NSBeep()
132 iTunes.current_track.rating.set(rating)
133
134 def playPause(self):
135 iTunes = iTunesApp()
136 was_playing = (iTunes.player_state.get() == k.playing)
137 iTunes.playpause()
138 if not was_playing and iTunes.player_state.get() == k.stopped:
139 # most likely, we're focused on the iPod, so playing does nothing
140 iTunes.browser_windows[1].view.set(iTunes.user_playlists.filter(its.name=='Stations')[1].get())
141 iTunes.play()
142 if HAVE_XTENSION:
143 if iTunes.player_state.get() == k.playing:
144 XTensionApp().turnon('Stereo')
145 else:
146 XTensionApp().turnoff('Stereo')
147
148 def zoomWindow(self):
149 systemEvents = app(id='com.apple.systemEvents')
150 frontName = systemEvents.processes.filter(its.frontmost)[1].name()
151 if frontName == 'iTunes':
152 systemEvents.processes['iTunes'].menu_bars[1]. \
153 menu_bar_items['Window'].menus.menu_items['Zoom'].click()
154 return
155 try:
156 zoomed = app(frontName).windows[1].zoomed
157 zoomed.set(not zoomed())
158 except CommandError:
159 systemEvents.processes[frontName].windows. \
160 filter(its.subrole == 'AXStandardWindow').windows[1]. \
161 buttons.filter(its.subrole == 'AXZoomButton').buttons[1].click()
162
163 def finishLaunching(self):
164 super(StreamVision, self).finishLaunching()
165 self.registerHotKey(self.displayTrackInfo, 100) # F8
166 self.registerHotKey(self.goToSite, 100, cmdKey) # cmd-F8
167 self.registerHotKey(self.playPause, 101) # F9
168 self.registerHotKey(lambda: iTunesApp().previous_track(), 109) # F10
169 self.registerHotKey(lambda: iTunesApp().next_track(), 103) # F11
170 self.registerHotKey(lambda: self.incrementRatingBy(-20), 109, shiftKey) # shift-F10
171 self.registerHotKey(lambda: self.incrementRatingBy(20), 103, shiftKey) # shift-F11
172 self.registerHotKey(self.zoomWindow, 42, cmdKey | controlKey) # cmd-ctrl-\
173 NSDistributedNotificationCenter.defaultCenter().addObserver_selector_name_object_(self, self.displayTrackInfo, 'com.apple.iTunes.playerInfo', None)
174
175 def sendEvent_(self, theEvent):
176 if theEvent.type() == NSSystemDefined and \
177 theEvent.subtype() == kEventHotKeyPressedSubtype:
178 self.hotKeyActions[theEvent.data1()]()
179 super(StreamVision, self).sendEvent_(theEvent)
180
181if __name__ == "__main__":
182 AppHelper.runEventLoop()
Note: See TracBrowser for help on using the repository browser.