8
8
logging .basicConfig (level = logging .DEBUG )
9
9
log = logging .getLogger ('overcast-sonos' )
10
10
11
+ list_active_episodes_in_root = True
12
+ allow_all_active_episodes_as_playlist = True
13
+
14
+
15
+ class customSOAPHandler (SOAPHandler ):
16
+
17
+ def do_GET (self ):
18
+ log .debug ('PATH ==> %s' , self .path )
19
+ if self .path == '/presentation_map' :
20
+ self .send_response (200 )
21
+ self .send_header ('Content-type' , 'text/xml' )
22
+ self .end_headers ()
23
+ self .wfile .write ('''<?xml version="1.0" encoding="UTF-8"?>
24
+ <Presentation>
25
+ <PresentationMap type="DisplayType">
26
+ <RootNodeDisplayType>
27
+ <DisplayMode>LIST</DisplayMode>
28
+ </RootNodeDisplayType>
29
+ </PresentationMap>
30
+ </Presentation>
31
+ ''' )
32
+ return
33
+ else :
34
+ return SOAPHandler .do_GET (self )
35
+
36
+
11
37
dispatcher = SoapDispatcher ('overcast-sonos' ,
12
38
location = 'http://localhost:8140/' ,
13
39
namespace = 'http://www.sonos.com/Services/1.1' ,
@@ -63,30 +89,51 @@ def getSessionId(username, password):
63
89
###
64
90
65
91
66
- def getMetadata (id , index , count ):
67
- log .debug ('at=getMetadata id=%s index=%s count=%s' , id , index , count )
92
+ def getMetadata (id , index , count , recursive = False ):
93
+ log .debug ('at=getMetadata id=%s index=%s count=%s recursive=%s ' , id , index , count , recursive )
68
94
69
95
if id == 'root' :
70
- response = {'getMetadataResult' : [
71
- {'index' : 0 , 'count' : 2 , 'total' : 2 },
72
- {'mediaCollection' : {
73
- 'id' : 'episodes' ,
74
- 'title' : 'All Active Episodes' ,
75
- 'itemType' : 'container' ,
76
- 'canPlay' : False ,
77
- 'albumArtURI' : 'http://is2.mzstatic.com/image/thumb/Purple62/v4/22/c7/93/22c793a7-55a8-e72b-756c-90641e7b96d4/source/175x175bb.jpg' ,
78
- }},
96
+ response = {'getMetadataResult' : []}
97
+ response ['getMetadataResult' ].append (
79
98
{'mediaCollection' : {
80
99
'id' : 'podcasts' ,
81
100
'title' : 'Podcasts' ,
82
- 'itemType' : 'container ' ,
101
+ 'itemType' : 'albumList ' ,
83
102
'canPlay' : False ,
84
103
'albumArtURI' : 'http://is2.mzstatic.com/image/thumb/Purple62/v4/22/c7/93/22c793a7-55a8-e72b-756c-90641e7b96d4/source/175x175bb.jpg' ,
85
- }},
86
- ]}
104
+ }})
105
+ response ['getMetadataResult' ].append (
106
+ {'mediaCollection' : {
107
+ 'id' : 'episodes' ,
108
+ 'title' : 'All Active Episodes' ,
109
+ 'itemType' : 'playlist' ,
110
+ 'canPlay' : allow_all_active_episodes_as_playlist ,
111
+ 'albumArtURI' : 'http://is2.mzstatic.com/image/thumb/Purple62/v4/22/c7/93/22c793a7-55a8-e72b-756c-90641e7b96d4/source/175x175bb.jpg' ,
112
+ }})
113
+ if list_active_episodes_in_root :
114
+ all_episodes = overcast .get_active_episodes ()
115
+ episodes = all_episodes [index :index + count ]
116
+ response ['getMetadataResult' ].append ({'index' : index , 'count' : len (episodes ) + 2 , 'total' : len (all_episodes ) + 2 })
117
+ for episode in episodes :
118
+ response ['getMetadataResult' ].append ({
119
+ 'mediaMetadata' : {
120
+ 'id' : 'episodes/' + episode ['id' ],
121
+ 'title' : episode ['podcast_title' ] + " - " + episode ['title' ],
122
+ 'mimeType' : episode ['audio_type' ],
123
+ 'itemType' : 'track' ,
124
+ 'trackMetadata' : {
125
+ 'artist' : episode ['podcast_title' ],
126
+ 'album' : episode ['podcast_title' ],
127
+ 'albumArtist' : episode ['podcast_title' ],
128
+ 'albumArtURI' : episode ['albumArtURI' ],
129
+ 'genreId' : 'podcast' ,
130
+ 'canResume' : True ,
131
+ }
132
+ }
133
+ })
87
134
88
135
elif id == 'episodes' :
89
- all_episodes = overcast .get_active_episodes ()
136
+ all_episodes = overcast .get_active_episodes (get_details = recursive )
90
137
episodes = all_episodes [index :index + count ]
91
138
response = {'getMetadataResult' : [{'index' : index , 'count' : len (episodes ), 'total' : len (all_episodes )}]}
92
139
for episode in episodes :
@@ -101,6 +148,7 @@ def getMetadata(id, index, count):
101
148
'albumArtist' : episode ['podcast_title' ],
102
149
'albumArtURI' : episode ['albumArtURI' ],
103
150
'genreId' : 'podcast' ,
151
+ 'duration' : episode ['duration' ],
104
152
'canResume' : True ,
105
153
}
106
154
}
@@ -115,7 +163,7 @@ def getMetadata(id, index, count):
115
163
'id' : 'podcasts/' + podcast ['id' ],
116
164
'title' : podcast ['title' ],
117
165
'albumArtURI' : podcast ['albumArtURI' ],
118
- 'itemType' : 'container ' ,
166
+ 'itemType' : 'album ' ,
119
167
'canPlay' : False ,
120
168
}})
121
169
@@ -152,7 +200,7 @@ def getMetadata(id, index, count):
152
200
dispatcher .register_function (
153
201
'getMetadata' , getMetadata ,
154
202
returns = {'getMetadataResult' : {'index' : int , 'count' : int , 'total' : int , 'mediaCollection' : mediaCollection }},
155
- args = {'id' : str , 'index' : int , 'count' : int }
203
+ args = {'id' : str , 'index' : int , 'count' : int , 'recursive' : bool }
156
204
)
157
205
158
206
###
@@ -161,6 +209,7 @@ def getMetadata(id, index, count):
161
209
def getMediaMetadata (id ):
162
210
log .debug ('at=getMediaMetadata id=%s' , id )
163
211
_ , episode_id = id .rsplit ('/' , 1 )
212
+ log .debug ('at=getMediaMetadata episode_id=%s' , episode_id )
164
213
episode = overcast .get_episode_detail (episode_id )
165
214
response = {'getMediaMetadataResult' : {
166
215
'mediaMetadata' : {
@@ -204,7 +253,7 @@ def getMediaURI(id):
204
253
'offsetMillis' : episode ['offsetMillis' ]
205
254
},
206
255
}
207
- log .debug ('at=getMediaMetadata response=%s' , response )
256
+ log .debug ('at=getMediaURI response=%s' , response )
208
257
return response
209
258
210
259
@@ -246,7 +295,7 @@ def reportPlaySeconds(id, seconds, offsetMillis, contextId):
246
295
)
247
296
248
297
249
- def reportPlayStatus (id , status , contextId , offsetMillis ):
298
+ def reportPlayStatus (id , status , offsetMillis , contextId ):
250
299
episode_id = id .rsplit ('/' , 1 )[- 1 ]
251
300
log .debug ('at=reportPlayStatus and id=%s, status=%s, contextId=%s, offsetMillis=%d, episode_id=%s' , id , status , contextId , offsetMillis , episode_id )
252
301
episode = overcast .get_episode_detail (episode_id )
@@ -273,8 +322,9 @@ def setPlayedSeconds(id, seconds, offsetMillis, contextId):
273
322
args = {'id' : str , 'seconds' : int , 'offsetMillis' : int , 'contextId' : str }
274
323
)
275
324
325
+
276
326
if __name__ == '__main__' :
277
327
log .info ('at=start' )
278
- httpd = HTTPServer (("" , 8140 ), SOAPHandler )
328
+ httpd = HTTPServer (("" , 8140 ), customSOAPHandler )
279
329
httpd .dispatcher = dispatcher
280
330
httpd .serve_forever ()
0 commit comments