-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathsimple_kivy.py
More file actions
154 lines (126 loc) · 4.68 KB
/
Copy pathsimple_kivy.py
File metadata and controls
154 lines (126 loc) · 4.68 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
"""
simple_kivy Example
====================================================
This example demonstrates a simple use of the AirplayListener and AirplayRemote.
It shows a window with the current artwork, song title, artist and album.
Additionally it displays five buttons to control the playback.
"""
import logging
loggers = ["ShairportLogger", "AirplayListenerLogger", "AirplayServiceListenerLogger"]
fh = logging.FileHandler("airplay2file.log")
fh.setLevel(logging.DEBUG)
for logger_name in loggers:
logger = logging.getLogger(logger_name)
logger.propagate = False
logger.addHandler(fh)
from kivy.app import App
from kivy.lang import Builder
from kivy.properties import StringProperty, ObjectProperty # pylint: disable=E0611
from kivy.uix.boxlayout import BoxLayout
from kivy.clock import mainthread
from shairportmetadatareader import AirplayUDPListener
Builder.load_string("""
#:import AirplayCommand shairportmetadatareader.AirplayCommand
<RootLayout>:
artist: "artist"
title: "title"
album: "album"
artwork: "" # for some reason this string must no be empty, otherwise changing the artwork crashes the app
orientation: 'vertical'
BoxLayout:
size_hint_y: 0.8
orientation: 'horizontal'
AsyncImage:
source: root.artwork
BoxLayout:
orientation: 'vertical'
Label:
text: root.title
Label:
text: root.artist
Label:
text: root.album
BoxLayout:
size_hint_y: 0.2
orientation: 'horizontal'
Button:
text: 'Play'
disabled: root.remote is None
on_press: root.remote.send_command(AirplayCommand.PLAY)
Button:
text: 'Pause'
disabled: root.remote is None
on_press: root.remote.send_command(AirplayCommand.PAUSE)
Button:
text: 'Stop'
disabled: root.remote is None
on_press: root.remote.send_command(AirplayCommand.STOP)
Button:
text: '<<'
disabled: root.remote is None
on_press: root.remote.send_command(AirplayCommand.PREVIOUS_SONG)
Button:
text: '>>'
disabled: root.remote is None
on_press: root.remote.send_command(AirplayCommand.NEXT_SONG)
""")
class RootLayout(BoxLayout):
"""
Main application layout containing the information and control widgets.
"""
# metadata information
title = StringProperty("")
artist = StringProperty("")
album = StringProperty("")
artwork = StringProperty("")
# remote to control airplay playback
remote = ObjectProperty(None, allownone=True)
def on_track_info(self, listener, info):
"""
Called when the current track information changes.
:param listener: airplaylistener instance
:param info: new track information
"""
# pylint: disable=W0613
self.title = info["itemname"] if "itemname" in info else "title"
self.album = info["songalbum"] if "songalbum" in info else "album"
self.artist = info["songartist"] if "songartist" in info else "artist"
@mainthread
def on_artwork(self, listener, artwork):
"""
Called when the current artwork changes.
:param listener: airplaylistener instance
:param artwork: path to new artwork file
"""
# pylint: disable=W0613
self.artwork = artwork
def on_has_remote(self, listener, has_remote):
"""
Called when all data to create an airplay remote is available.
:param listener: airplaylistener instance
:param has_remote: True if all remote data is available, False otherwise
"""
if has_remote:
# this might block the gui for 5 seconds
self.remote = listener.get_remote(timeout=5)
else:
self.remote = None
class MusicPlayer(App):
"""
Main kivy application to display shairport information and control the corresponding airplay device.
"""
listener = ObjectProperty(None)
def build(self):
self.root = RootLayout()
# start shairport-sync and listen for airplay events
self.listener = AirplayUDPListener()
self.listener.bind(track_info=self.root.on_track_info,
artwork=self.root.on_artwork,
has_remote_data=self.root.on_has_remote)
self.listener.start_listening()
return self.root
def on_stop(self):
# stop listening for events an close shairport-sync
self.listener.stop_listening()
if __name__ == '__main__':
MusicPlayer().run()