Merge lp:~thisfred/autoqueue/lp-777351 into lp:autoqueue

Proposed by Eric Casteleijn
Status: Merged
Approved by: Eric Casteleijn
Approved revision: 322
Merged at revision: 321
Proposed branch: lp:~thisfred/autoqueue/lp-777351
Merge into: lp:autoqueue
Diff against target: 305 lines (+62/-45)
3 files modified
autoqueue/__init__.py (+25/-34)
autoqueue/tests/test_autoqueue.py (+4/-0)
rhythmbox_autoqueue/__init__.py (+33/-11)
To merge this branch: bzr merge lp:~thisfred/autoqueue/lp-777351
Reviewer Review Type Date Requested Status
Eric Casteleijn Pending
Review via email: mp+60205@code.launchpad.net

Commit message

fixed rhythmbox support

Description of the change

fixed rhythmbox support

To post a comment you must log in.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'autoqueue/__init__.py'
--- autoqueue/__init__.py 2011-05-06 00:03:33 +0000
+++ autoqueue/__init__.py 2011-05-06 15:33:27 +0000
@@ -24,6 +24,7 @@
24import os24import os
25import random25import random
2626
27from abc import ABCMeta, abstractmethod
27from dbus.mainloop.glib import DBusGMainLoop28from dbus.mainloop.glib import DBusGMainLoop
28from collections import deque29from collections import deque
29from datetime import datetime, timedelta30from datetime import datetime, timedelta
@@ -45,51 +46,49 @@
45class SongBase(object):46class SongBase(object):
46 """A wrapper object around player specific song objects."""47 """A wrapper object around player specific song objects."""
4748
49 __metaclass__ = ABCMeta
50
48 def __init__(self, song):51 def __init__(self, song):
49 self.song = song52 self.song = song
5053
51 def __str__(self):54 def __str__(self):
52 return "<Song: %s - %s>" % (self.get_artist(), self.get_title())55 return "<Song: %s - %s>" % (self.get_artist(), self.get_title())
5356
57 @abstractmethod
54 def get_artist(self):58 def get_artist(self):
55 """Return lowercase UNICODE name of artist."""59 """Return lowercase UNICODE name of artist."""
56 return NotImplemented
5760
61 @abstractmethod
58 def get_artists(self):62 def get_artists(self):
59 """Return lowercase UNICODE name of artists and performers."""63 """Return lowercase UNICODE name of artists and performers."""
60 return NotImplemented
6164
65 @abstractmethod
62 def get_title(self):66 def get_title(self):
63 """Return lowercase UNICODE title of song."""67 """Return lowercase UNICODE title of song."""
64 return NotImplemented
6568
69 @abstractmethod
66 def get_tags(self):70 def get_tags(self):
67 """Return a list of tags for the song."""71 """Return a list of tags for the song."""
68 return []
6972
73 @abstractmethod
70 def get_filename(self):74 def get_filename(self):
71 """Return filename for the song."""75 """Return filename for the song."""
72 return NotImplemented
7376
77 @abstractmethod
74 def get_length(self):78 def get_length(self):
75 """Return length in seconds."""79 """Return length in seconds."""
76 return NotImplemented
7780
81 @abstractmethod
78 def get_last_started(self):82 def get_last_started(self):
79 """Return the datetime the song was last played."""83 """Return the datetime the song was last played."""
80 return NotImplemented
8184
85 @abstractmethod
82 def get_rating(self):86 def get_rating(self):
83 """Return the rating of the song."""87 """Return the rating of the song."""
84 return NotImplemented
8588
89 @abstractmethod
86 def get_playcount(self):90 def get_playcount(self):
87 """Return the playcount of the song."""91 """Return the playcount of the song."""
88 return NotImplemented
89
90 def get_added(self):
91 """Return the datetime the song was added to the library."""
92 return NotImplemented
9392
94 def get_play_frequency(self):93 def get_play_frequency(self):
95 """Return the play frequency of the song (plays / day)."""94 """Return the play frequency of the song (plays / day)."""
@@ -124,27 +123,19 @@
124class AutoQueueBase(object):123class AutoQueueBase(object):
125 """Generic base class for autoqueue plugins."""124 """Generic base class for autoqueue plugins."""
126125
126 __metaclass__ = ABCMeta
127
127 def __init__(self):128 def __init__(self):
128 self.artist_block_time = 1129 self.artist_block_time = 1
129 self._blocked_artists = deque([])130 self._blocked_artists = deque([])
130 self._blocked_artists_times = deque([])131 self._blocked_artists_times = deque([])
131 self._cache_dir = None132 self._cache_dir = None
132 self.desired_queue_length = 0133 self.desired_queue_length = 15 * 60
133 self.cached_misses = deque([])134 self.cached_misses = deque([])
134 self.by_mirage = False
135 self.by_tracks = True
136 self.by_artists = True
137 self.by_tags = True
138 self.running = False135 self.running = False
139 self.verbose = False136 self.verbose = False
140 self.weed = False
141 self.song = None137 self.song = None
142 self.restrictions = None138 self.restrictions = None
143 self.prune_artists = []
144 self.prune_titles = []
145 self.prune_filenames = []
146 self._rows = []
147 self._nrows = []
148 self.player_set_variables_from_config()139 self.player_set_variables_from_config()
149 self.get_blocked_artists_pickle()140 self.get_blocked_artists_pickle()
150 self.last_songs = []141 self.last_songs = []
@@ -249,45 +240,45 @@
249 song.get_filename() for song in self.player_search(search)])240 song.get_filename() for song in self.player_search(search)])
250 return filenames241 return filenames
251242
243 @abstractmethod
252 def player_construct_file_search(self, filename, restrictions=None):244 def player_construct_file_search(self, filename, restrictions=None):
253 """Construct a search that looks for songs with this artist and title.245 """Construct a search that looks for songs with this artist and title.
254246
255 """247 """
256 return NotImplemented
257248
249 @abstractmethod
258 def player_construct_track_search(self, artist, title, restrictions=None):250 def player_construct_track_search(self, artist, title, restrictions=None):
259 """Construct a search that looks for songs with this artist251 """Construct a search that looks for songs with this artist
260 and title.252 and title.
261 """253 """
262 return NotImplemented
263254
255 @abstractmethod
264 def player_construct_artist_search(self, artist, restrictions=None):256 def player_construct_artist_search(self, artist, restrictions=None):
265 """Construct a search that looks for songs with this artist."""257 """Construct a search that looks for songs with this artist."""
266 return NotImplemented
267258
259 @abstractmethod
268 def player_construct_tag_search(self, tags, restrictions=None):260 def player_construct_tag_search(self, tags, restrictions=None):
269 """Construct a search that looks for songs with these tags."""261 """Construct a search that looks for songs with these tags."""
270 return NotImplemented
271262
263 @abstractmethod
272 def player_set_variables_from_config(self):264 def player_set_variables_from_config(self):
273 """Initialize user settings from the configuration storage."""265 """Initialize user settings from the configuration storage."""
274 return NotImplemented
275266
267 @abstractmethod
276 def player_get_queue_length(self):268 def player_get_queue_length(self):
277 """Get the current length of the queue."""269 """Get the current length of the queue."""
278 return 0
279270
271 @abstractmethod
280 def player_enqueue(self, song):272 def player_enqueue(self, song):
281 """Put the song at the end of the queue."""273 """Put the song at the end of the queue."""
282 return NotImplemented
283274
275 @abstractmethod
284 def player_search(self, search):276 def player_search(self, search):
285 """Perform a player search."""277 """Perform a player search."""
286 return NotImplemented
287278
279 @abstractmethod
288 def player_get_songs_in_queue(self):280 def player_get_songs_in_queue(self):
289 """Return (wrapped) song objects for the songs in the queue."""281 """Return (wrapped) song objects for the songs in the queue."""
290 return []
291282
292 def player_execute_async(self, method, *args, **kwargs):283 def player_execute_async(self, method, *args, **kwargs):
293 """Override this if the player has a way to execute methods284 """Override this if the player has a way to execute methods
@@ -418,7 +409,7 @@
418 return song409 return song
419 self.cached_misses.append((artist, title, filename, tags))410 self.cached_misses.append((artist, title, filename, tags))
420 while len(self.cached_misses) > 1000:411 while len(self.cached_misses) > 1000:
421 print self.cached_misses.popleft()412 self.cached_misses.popleft()
422413
423 def fill_queue(self):414 def fill_queue(self):
424 """Search for appropriate songs and put them in the queue."""415 """Search for appropriate songs and put them in the queue."""
425416
=== modified file 'autoqueue/tests/test_autoqueue.py'
--- autoqueue/tests/test_autoqueue.py 2011-05-06 00:03:33 +0000
+++ autoqueue/tests/test_autoqueue.py 2011-05-06 15:33:27 +0000
@@ -213,6 +213,10 @@
213 artist_name,213 artist_name,
214 len(self._blocked_artists)))214 len(self._blocked_artists)))
215215
216 def player_set_variables_from_config(self):
217 """Set configuration variables."""
218 pass
219
216 def player_construct_file_search(self, filename, restrictions=None):220 def player_construct_file_search(self, filename, restrictions=None):
217 """Construct a search that looks for songs with this artist221 """Construct a search that looks for songs with this artist
218 and title.222 and title.
219223
=== modified file 'rhythmbox_autoqueue/__init__.py'
--- rhythmbox_autoqueue/__init__.py 2010-08-12 12:20:37 +0000
+++ rhythmbox_autoqueue/__init__.py 2011-05-06 15:33:27 +0000
@@ -1,3 +1,5 @@
1"""Rhythmbox version of the autoqueue plugin."""
2
1# Copyright (C) 2007-2008 - Eric Casteleijn, Alexandre Rosenfeld3# Copyright (C) 2007-2008 - Eric Casteleijn, Alexandre Rosenfeld
2#4#
3# This program is free software; you can redistribute it and/or modify5# This program is free software; you can redistribute it and/or modify
@@ -16,24 +18,29 @@
1618
17import urllib19import urllib
18from time import time20from time import time
19import gconf, gobject21import gconf
22import gobject
20from gtk import gdk23from gtk import gdk
21import rb, rhythmdb24import rb
25import rhythmdb
22from collections import deque26from collections import deque
23from autoqueue import AutoQueueBase, SongBase27from autoqueue import AutoQueueBase, SongBase
2428
25GCONFPATH = '/apps/rhythmbox/plugins/autoqueue/'29GCONFPATH = '/apps/rhythmbox/plugins/autoqueue/'
2630
31
27class Song(SongBase):32class Song(SongBase):
28 """A wrapper object around rhythmbox song objects."""33 """A wrapper object around rhythmbox song objects."""
29 def __init__(self, song, db):34
35 def __init__(self, song, db): # pylint: disable=W0231
30 self.song = song36 self.song = song
31 self.db = db37 self.db = db
3238
33 def get_artist(self):39 def get_artist(self):
34 """return lowercase UNICODE name of artist"""40 """return lowercase UNICODE name of artist"""
35 return unicode(41 return unicode(
36 self.db.entry_get(self.song, rhythmdb.PROP_ARTIST).lower(), 'utf-8')42 self.db.entry_get(self.song, rhythmdb.PROP_ARTIST).lower(),
43 'utf-8')
3744
38 def get_artists(self):45 def get_artists(self):
39 return [self.get_artist()]46 return [self.get_artist()]
@@ -59,8 +66,18 @@
59 def get_last_started(self):66 def get_last_started(self):
60 return self.db.entry_get(self.song, rhythmdb.PROP_LAST_PLAYED)67 return self.db.entry_get(self.song, rhythmdb.PROP_LAST_PLAYED)
6168
69 def get_rating(self):
70 """Return the rating of the song."""
71 return 5.0 / self.db.entry_get(self.song, rhythmdb.PROP_RATING)
72
73 def get_playcount(self):
74 """Return the playcount of the song."""
75 return self.db.entry_get(self.song, rhythmdb.PROP_PLAY_COUNT)
76
6277
63class AutoQueuePlugin(rb.Plugin, AutoQueueBase):78class AutoQueuePlugin(rb.Plugin, AutoQueueBase):
79 """Plugin implementation."""
80
64 def __init__(self):81 def __init__(self):
65 rb.Plugin.__init__(self)82 rb.Plugin.__init__(self)
66 AutoQueueBase.__init__(self)83 AutoQueueBase.__init__(self)
@@ -69,21 +86,27 @@
69 self.by_mirage = True86 self.by_mirage = True
70 self.log("initialized")87 self.log("initialized")
71 self._generators = deque()88 self._generators = deque()
89 self.pec_id = None
90 self.rdb = None
91 self.shell = None
7292
73 def activate(self, shell):93 def activate(self, shell):
94 """Called on activation of the plugin."""
74 self.shell = shell95 self.shell = shell
75 self.rdb = shell.get_property('db')96 self.rdb = shell.get_property('db')
76 sp = shell.get_player ()97 sp = shell.get_player()
77 self.pec_id = sp.connect(98 self.pec_id = sp.connect(
78 'playing-song-changed', self.playing_entry_changed)99 'playing-song-changed', self.playing_entry_changed)
79100
80 def deactivate(self, shell):101 def deactivate(self, shell):
102 """Called on deactivation of the plugin."""
81 self.rdb = None103 self.rdb = None
82 self.shell = None104 self.shell = None
83 sp = shell.get_player()105 sp = shell.get_player()
84 sp.disconnect(self.pec_id)106 sp.disconnect(self.pec_id)
85107
86 def _idle_callback(self):108 def _idle_callback(self):
109 """Callback that performs task asynchronously."""
87 gdk.threads_enter()110 gdk.threads_enter()
88 while self._generators:111 while self._generators:
89 if self._generators[0] is None:112 if self._generators[0] is None:
@@ -97,24 +120,23 @@
97 return False120 return False
98121
99 def player_execute_async(self, method, *args, **kwargs):122 def player_execute_async(self, method, *args, **kwargs):
100 """Override this if the player has a way to execute methods123 """Execute method asynchronously."""
101 asynchronously, like the copooling in autoqueue.
102
103 """
104 add_callback = False124 add_callback = False
105 if not self._generators:125 if not self._generators:
106 add_callback = True126 add_callback = True
107 self._generators.append(method(*args, **kwargs))127 self._generators.append(method(*args, **kwargs))
108 if add_callback:128 if add_callback:
109 gobject.idle_add(self._idle_callback)129 gobject.idle_add(self._idle_callback)
110130
111 def log(self, msg):131 def log(self, msg):
112 """print debug messages"""132 """Print debug messages."""
133 # TODO: replace with real logging
113 if not self.verbose:134 if not self.verbose:
114 return135 return
115 print msg136 print msg
116137
117 def playing_entry_changed(self, sp, entry):138 def playing_entry_changed(self, sp, entry):
139 """Handler for song change."""
118 if entry:140 if entry:
119 self.on_song_started(Song(entry, self.rdb))141 self.on_song_started(Song(entry, self.rdb))
120142

Subscribers

People subscribed via source and target branches

to all changes: