source: trunk/StreamVision/StreamVision.py @ 234

Last change on this file since 234 was 234, checked in by Nicholas Riley, 15 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.