Lines 5-21
Link Here
|
5 |
# Copyright 2007, Frank Scholz <coherence@beebits.net> |
5 |
# Copyright 2007, Frank Scholz <coherence@beebits.net> |
6 |
|
6 |
|
7 |
import rhythmdb |
7 |
import rhythmdb |
8 |
import louie |
8 |
import coherence.extern.louie as louie |
9 |
import urllib |
9 |
import urllib |
10 |
from coherence.upnp.core import DIDLLite |
10 |
from coherence.upnp.core import DIDLLite |
11 |
|
11 |
|
12 |
from coherence import log |
12 |
from coherence.backend import BackendItem, BackendStore |
13 |
|
13 |
|
14 |
ROOT_CONTAINER_ID = 0 |
14 |
ROOT_CONTAINER_ID = 0 |
15 |
AUDIO_CONTAINER = 10 |
15 |
AUDIO_CONTAINER = 100 |
16 |
AUDIO_ALL_CONTAINER_ID = 11 |
16 |
AUDIO_ALL_CONTAINER_ID = 101 |
17 |
AUDIO_ARTIST_CONTAINER_ID = 12 |
17 |
AUDIO_ARTIST_CONTAINER_ID = 102 |
18 |
AUDIO_ALBUM_CONTAINER_ID = 13 |
18 |
AUDIO_ALBUM_CONTAINER_ID = 103 |
19 |
|
19 |
|
20 |
CONTAINER_COUNT = 10000 |
20 |
CONTAINER_COUNT = 10000 |
21 |
|
21 |
|
Lines 23-29
Link Here
|
23 |
|
23 |
|
24 |
# most of this class is from Coherence, originally under the MIT licence |
24 |
# most of this class is from Coherence, originally under the MIT licence |
25 |
|
25 |
|
26 |
class Container(log.Loggable): |
26 |
class Container(BackendItem): |
27 |
|
27 |
|
28 |
logCategory = 'rb_media_store' |
28 |
logCategory = 'rb_media_store' |
29 |
|
29 |
|
Lines 46-52
Link Here
|
46 |
|
46 |
|
47 |
def get_children(self,start=0,request_count=0): |
47 |
def get_children(self,start=0,request_count=0): |
48 |
if callable(self.children): |
48 |
if callable(self.children): |
49 |
children = self.children() |
49 |
children = self.children(self.id) |
50 |
else: |
50 |
else: |
51 |
children = self.children |
51 |
children = self.children |
52 |
|
52 |
|
Lines 57-69
Link Here
|
57 |
return children[start:request_count] |
57 |
return children[start:request_count] |
58 |
|
58 |
|
59 |
def get_child_count(self): |
59 |
def get_child_count(self): |
|
|
60 |
return len(self.get_children()) |
60 |
|
61 |
|
61 |
if callable(self.children): |
62 |
def get_item(self, parent_id=None): |
62 |
return len(self.children()) |
|
|
63 |
else: |
64 |
return len(self.children) |
65 |
|
66 |
def get_item(self): |
67 |
self.item.childCount = self.get_child_count() |
63 |
self.item.childCount = self.get_child_count() |
68 |
return self.item |
64 |
return self.item |
69 |
|
65 |
|
Lines 74-84
Link Here
|
74 |
return self.id |
70 |
return self.id |
75 |
|
71 |
|
76 |
|
72 |
|
77 |
class Album(log.Loggable): |
73 |
class Album(BackendItem): |
78 |
|
74 |
|
79 |
logCategory = 'rb_media_store' |
75 |
logCategory = 'rb_media_store' |
80 |
|
76 |
|
81 |
def __init__(self, store, title, id): |
77 |
def __init__(self, store, title, id, parent_id): |
82 |
self.id = id |
78 |
self.id = id |
83 |
self.title = title |
79 |
self.title = title |
84 |
self.store = store |
80 |
self.store = store |
Lines 103-109
Link Here
|
103 |
def collate (model, path, iter): |
99 |
def collate (model, path, iter): |
104 |
self.info("Album get_children %r %r %r" %(model, path, iter)) |
100 |
self.info("Album get_children %r %r %r" %(model, path, iter)) |
105 |
id = model.get(iter, 0)[0] |
101 |
id = model.get(iter, 0)[0] |
106 |
children.append(Track(self.store,id)) |
102 |
children.append(Track(self.store,id,self.id)) |
107 |
|
103 |
|
108 |
self.tracks_per_album_query.foreach(collate) |
104 |
self.tracks_per_album_query.foreach(collate) |
109 |
|
105 |
|
Lines 117-124
Link Here
|
117 |
def get_child_count(self): |
113 |
def get_child_count(self): |
118 |
return len(self.get_children()) |
114 |
return len(self.get_children()) |
119 |
|
115 |
|
120 |
def get_item(self): |
116 |
def get_item(self, parent_id = AUDIO_ALBUM_CONTAINER_ID): |
121 |
item = DIDLLite.MusicAlbum(self.id, AUDIO_ALBUM_CONTAINER_ID, self.title) |
117 |
item = DIDLLite.MusicAlbum(self.id, parent_id, self.title) |
122 |
return item |
118 |
return item |
123 |
|
119 |
|
124 |
def get_id(self): |
120 |
def get_id(self): |
Lines 131-141
Link Here
|
131 |
return self.cover |
127 |
return self.cover |
132 |
|
128 |
|
133 |
|
129 |
|
134 |
class Artist(log.Loggable): |
130 |
class Artist(BackendItem): |
135 |
|
131 |
|
136 |
logCategory = 'rb_media_store' |
132 |
logCategory = 'rb_media_store' |
137 |
|
133 |
|
138 |
def __init__(self, store, name, id): |
134 |
def __init__(self, store, name, id, parent_id): |
139 |
self.id = id |
135 |
self.id = id |
140 |
self.name = name |
136 |
self.name = name |
141 |
self.store = store |
137 |
self.store = store |
Lines 173-180
Link Here
|
173 |
def get_child_count(self): |
169 |
def get_child_count(self): |
174 |
return len(self.get_children()) |
170 |
return len(self.get_children()) |
175 |
|
171 |
|
176 |
def get_item(self): |
172 |
def get_item(self, parent_id = AUDIO_ARTIST_CONTAINER_ID): |
177 |
item = DIDLLite.MusicArtist(self.id, AUDIO_ARTIST_CONTAINER_ID, self.name) |
173 |
item = DIDLLite.MusicArtist(self.id, parent_id, self.name) |
178 |
return item |
174 |
return item |
179 |
|
175 |
|
180 |
def get_id(self): |
176 |
def get_id(self): |
Lines 184-199
Link Here
|
184 |
return self.name |
180 |
return self.name |
185 |
|
181 |
|
186 |
|
182 |
|
187 |
class Track(log.Loggable): |
183 |
class Track(BackendItem): |
188 |
|
184 |
|
189 |
logCategory = 'rb_media_store' |
185 |
logCategory = 'rb_media_store' |
190 |
|
186 |
|
191 |
def __init__(self, store, id): |
187 |
def __init__(self, store, id, parent_id): |
192 |
self.store = store |
188 |
self.store = store |
193 |
if type(id) == int: |
189 |
if type(id) == int: |
194 |
self.id = id |
190 |
self.id = id |
195 |
else: |
191 |
else: |
196 |
self.id = self.store.db.entry_get (id, rhythmdb.PROP_ENTRY_ID) |
192 |
self.id = self.store.db.entry_get (id, rhythmdb.PROP_ENTRY_ID) |
|
|
193 |
self.parent_id = parent_id |
197 |
|
194 |
|
198 |
def get_children(self, start=0, request_count=0): |
195 |
def get_children(self, start=0, request_count=0): |
199 |
return [] |
196 |
return [] |
Lines 201-209
Link Here
|
201 |
def get_child_count(self): |
198 |
def get_child_count(self): |
202 |
return 0 |
199 |
return 0 |
203 |
|
200 |
|
204 |
def get_item(self): |
201 |
def get_item(self, parent_id=None): |
205 |
|
202 |
|
206 |
self.info("Track get_item %r" %(self.id)) |
203 |
self.info("Track get_item %r @ %r" %(self.id,self.parent_id)) |
207 |
|
204 |
|
208 |
host = "" |
205 |
host = "" |
209 |
|
206 |
|
Lines 226-234
Link Here
|
226 |
mimetype = "audio/mpeg" |
223 |
mimetype = "audio/mpeg" |
227 |
size = self.store.db.entry_get(entry, rhythmdb.PROP_FILE_SIZE) |
224 |
size = self.store.db.entry_get(entry, rhythmdb.PROP_FILE_SIZE) |
228 |
|
225 |
|
|
|
226 |
album = self.store.db.entry_get(entry, rhythmdb.PROP_ALBUM) |
227 |
if self.parent_id == None: |
228 |
try: |
229 |
self.parent_id = self.store.albums[album].id |
230 |
except: |
231 |
pass |
232 |
|
229 |
# create item |
233 |
# create item |
230 |
item = DIDLLite.MusicTrack(self.id + TRACK_COUNT) |
234 |
item = DIDLLite.MusicTrack(self.id + TRACK_COUNT,self.parent_id) |
231 |
item.album = self.store.db.entry_get(entry, rhythmdb.PROP_ALBUM) |
235 |
item.album = album |
|
|
236 |
|
232 |
item.artist = self.store.db.entry_get(entry, rhythmdb.PROP_ARTIST) |
237 |
item.artist = self.store.db.entry_get(entry, rhythmdb.PROP_ARTIST) |
233 |
#item.date = |
238 |
#item.date = |
234 |
item.genre = self.store.db.entry_get(entry, rhythmdb.PROP_GENRE) |
239 |
item.genre = self.store.db.entry_get(entry, rhythmdb.PROP_GENRE) |
Lines 239-251
Link Here
|
239 |
#self.warning("cover for %r is %r", item.title, cover) |
244 |
#self.warning("cover for %r is %r", item.title, cover) |
240 |
#item.albumArtURI = ## can we somehow store art in the upnp share?? |
245 |
#item.albumArtURI = ## can we somehow store art in the upnp share?? |
241 |
|
246 |
|
242 |
# add internal resource |
|
|
243 |
#res = DIDLLite.Resource(location, 'internal:%s:%s:*' % (host, mimetype)) |
244 |
#res.size = size |
245 |
#res.duration = duration |
246 |
#res.bitrate = bitrate |
247 |
#item.res.append(res) |
248 |
|
249 |
# add http resource |
247 |
# add http resource |
250 |
res = DIDLLite.Resource(self.get_url(), 'http-get:*:%s:*' % mimetype) |
248 |
res = DIDLLite.Resource(self.get_url(), 'http-get:*:%s:*' % mimetype) |
251 |
if size > 0: |
249 |
if size > 0: |
Lines 256-261
Link Here
|
256 |
res.bitrate = str(bitrate) |
254 |
res.bitrate = str(bitrate) |
257 |
item.res.append(res) |
255 |
item.res.append(res) |
258 |
|
256 |
|
|
|
257 |
# add internal resource |
258 |
res = DIDLLite.Resource('track-%d' % self.id, 'rhythmbox:%s:%s:*' % (self.store.server.coherence.hostname, mimetype)) |
259 |
if size > 0: |
260 |
res.size = size |
261 |
if duration > 0: |
262 |
res.duration = str(duration) |
263 |
if bitrate > 0: |
264 |
res.bitrate = str(bitrate) |
265 |
item.res.append(res) |
266 |
|
259 |
return item |
267 |
return item |
260 |
|
268 |
|
261 |
def get_id(self): |
269 |
def get_id(self): |
Lines 280-296
Link Here
|
280 |
|
288 |
|
281 |
return location |
289 |
return location |
282 |
|
290 |
|
283 |
class MediaStore(log.Loggable): |
291 |
class MediaStore(BackendStore): |
284 |
|
292 |
|
285 |
logCategory = 'rb_media_store' |
293 |
logCategory = 'rb_media_store' |
286 |
implements = ['MediaServer'] |
294 |
implements = ['MediaServer'] |
287 |
|
295 |
|
288 |
def __init__(self, server, **kwargs): |
296 |
def __init__(self, server, **kwargs): |
289 |
print "creating UPnP MediaStore" |
297 |
self.warning("__init__ MediaStore %r", kwargs) |
290 |
self.server = server |
298 |
self.server = server |
291 |
self.db = kwargs['db'] |
299 |
self.db = kwargs['db'] |
292 |
self.plugin = kwargs['plugin'] |
300 |
self.plugin = kwargs['plugin'] |
293 |
|
301 |
|
|
|
302 |
self.wmc_mapping.update({'4': lambda : self.get_by_id(AUDIO_ALL_CONTAINER_ID), # all tracks |
303 |
'7': lambda : self.get_by_id(AUDIO_ALBUM_CONTAINER_ID), # all albums |
304 |
'6': lambda : self.get_by_id(AUDIO_ARTIST_CONTAINER_ID), # all artists |
305 |
}) |
306 |
|
294 |
self.update_id = 0 |
307 |
self.update_id = 0 |
295 |
|
308 |
|
296 |
self.next_id = CONTAINER_COUNT |
309 |
self.next_id = CONTAINER_COUNT |
Lines 340-350
Link Here
|
340 |
def get_by_id(self,id): |
353 |
def get_by_id(self,id): |
341 |
|
354 |
|
342 |
self.info("looking for id %r", id) |
355 |
self.info("looking for id %r", id) |
343 |
id = int(id) |
356 |
id = id.split('@',1) |
344 |
if id < TRACK_COUNT: |
357 |
item_id = id[0] |
345 |
item = self.containers[id] |
358 |
item_id = int(item_id) |
|
|
359 |
if item_id < TRACK_COUNT: |
360 |
try: |
361 |
item = self.containers[item_id] |
362 |
except KeyError: |
363 |
item = None |
346 |
else: |
364 |
else: |
347 |
item = Track(self, (id - TRACK_COUNT)) |
365 |
item = Track(self, (item_id - TRACK_COUNT),None) |
348 |
|
366 |
|
349 |
return item |
367 |
return item |
350 |
|
368 |
|
Lines 356-379
Link Here
|
356 |
def upnp_init(self): |
374 |
def upnp_init(self): |
357 |
if self.server: |
375 |
if self.server: |
358 |
self.server.connection_manager_server.set_variable(0, 'SourceProtocolInfo', [ |
376 |
self.server.connection_manager_server.set_variable(0, 'SourceProtocolInfo', [ |
359 |
#'internal:%s:*:*' % self.name, |
377 |
'rhythmbox:%s:*:*' % self.server.coherence.hostname, |
360 |
'http-get:*:audio/mpeg:*', |
378 |
'http-get:*:audio/mpeg:*', |
361 |
]) |
379 |
]) |
|
|
380 |
self.warning("__init__ MediaStore initialized") |
381 |
|
362 |
|
382 |
|
363 |
def children_tracks(self): |
383 |
def children_tracks(self, parent_id): |
364 |
tracks = [] |
384 |
tracks = [] |
365 |
|
385 |
|
366 |
def track_cb (entry): |
386 |
def track_cb (entry): |
367 |
if self.db.entry_get (entry, rhythmdb.PROP_HIDDEN): |
387 |
if self.db.entry_get (entry, rhythmdb.PROP_HIDDEN): |
368 |
return |
388 |
return |
369 |
id = self.db.entry_get (entry, rhythmdb.PROP_ENTRY_ID) |
389 |
id = self.db.entry_get (entry, rhythmdb.PROP_ENTRY_ID) |
370 |
track = Track(self, id) |
390 |
track = Track(self, id, parent_id) |
371 |
tracks.append(track) |
391 |
tracks.append(track) |
372 |
|
392 |
|
373 |
self.db.entry_foreach_by_type (self.db.entry_type_get_by_name('song'), track_cb) |
393 |
self.db.entry_foreach_by_type (self.db.entry_type_get_by_name('song'), track_cb) |
374 |
return tracks |
394 |
return tracks |
375 |
|
395 |
|
376 |
def children_albums(self): |
396 |
def children_albums(self,parent_id): |
377 |
albums = {} |
397 |
albums = {} |
378 |
|
398 |
|
379 |
self.info('children_albums') |
399 |
self.info('children_albums') |
Lines 389-395
Link Here
|
389 |
self.info("children_albums collate %r %r", name, priority) |
409 |
self.info("children_albums collate %r %r", name, priority) |
390 |
if priority is False: |
410 |
if priority is False: |
391 |
id = self.get_next_container_id() |
411 |
id = self.get_next_container_id() |
392 |
album = Album(self, name, id) |
412 |
album = Album(self, name, id,parent_id) |
393 |
self.containers[id] = album |
413 |
self.containers[id] = album |
394 |
albums[name] = album |
414 |
albums[name] = album |
395 |
|
415 |
|
Lines 401-407
Link Here
|
401 |
albums.sort(cmp=album_sort) |
421 |
albums.sort(cmp=album_sort) |
402 |
return albums |
422 |
return albums |
403 |
|
423 |
|
404 |
def children_artists(self,killbug=False): |
424 |
def children_artists(self,parent_id): |
405 |
artists = [] |
425 |
artists = [] |
406 |
|
426 |
|
407 |
self.info('children_artists') |
427 |
self.info('children_artists') |
Lines 411-417
Link Here
|
411 |
priority = model.get(iter, 1)[0] |
431 |
priority = model.get(iter, 1)[0] |
412 |
if priority is False: |
432 |
if priority is False: |
413 |
id = self.get_next_container_id() |
433 |
id = self.get_next_container_id() |
414 |
artist = Artist(self,name, id) |
434 |
artist = Artist(self,name, id,parent_id) |
415 |
self.containers[id] = artist |
435 |
self.containers[id] = artist |
416 |
artists.append(artist) |
436 |
artists.append(artist) |
417 |
|
437 |
|