Modified:
trunk/autoqueue.py
trunk/quodlibet_autoqueue.py
Log:
removed the hard limit of x days no play, instead it now depends on
the rating of a song, in the following manner:
if rating is the rating of the song with 0 < rating < 1 and bdays is
the number of days a song with 0.5 would not be played again:
block_days = rating**(log(bdays, 0.5))
also made some other simplifications because of this: no longer need
relaxors, just play a song more often or manually rate it higher to
hear it more often. Rate it lower/skip it to hear it less
often. Feedback loops ftw.
Modified: trunk/autoqueue.py
==============================================================================
--- trunk/autoqueue.py (original)
+++ trunk/autoqueue.py Sun Mar 15 09:21:35 2009
@@ -20,6 +20,7 @@
"""
from collections import deque
+from math import log
from datetime import datetime, timedelta
from time import strptime, sleep
import urllib
@@ -122,6 +123,7 @@
return result
return wrapper
+
class SongBase(object):
"""A wrapper object around player specific song objects."""
def __init__(self, song):
@@ -147,6 +149,23 @@
"""return length in seconds"""
return NotImplemented
+ def get_playcount(self):
+ """Return the number of times the song was played."""
+ return NotImplemented
+
+ def get_added(self):
+ """Return the date the song was added to the library."""
+ return NotImplemented
+
+ def get_last_played(self):
+ """Return the date the song was last played."""
+ return NotImplemented
+
+ def get_rating(self):
+ """Return the rating of the song."""
+ return NotImplemented
+
+
class AutoQueueBase(object):
"""Generic base class for autoqueue plugins."""
use_db = False
@@ -171,8 +190,7 @@
self.song = None
self._blocked_artists = deque([])
self._blocked_artists_times = deque([])
- self.relaxors = None
- self.restrictors = None
+ self.restrictions = None
self._artists_to_update = {}
self._tracks_to_update = {}
self.prune_artists = []
@@ -224,11 +242,6 @@
tags"""
return NotImplemented
- def player_construct_restrictions(
- self, track_block_time, relaxors, restrictors):
- """contstruct a search to further modify the searches"""
- return NotImplemented
-
def player_set_variables_from_config(self):
"""Initialize user settings from the configuration storage"""
return NotImplemented
@@ -299,6 +312,26 @@
return sqlite3.connect(
self.get_db_path(), timeout=5.0, isolation_level="immediate")
+ def disallowed(self, song):
+ if song.get_artist() in self.get_blocked_artists():
+ return True
+ try:
+ lastplayed = song.get_last_played()
+ except NotImplemented:
+ return False
+ now = datetime.now()
+ delta = now - datetime.fromtimestamp(lastplayed)
+ days_ago = delta.days
+ try:
+ rating = song.get_rating()
+ except NotImplemented:
+ return self.track_block_time > days_ago
+ bdays = max(1, self.track_block_time)
+ suggested = rating**(log(bdays, 0.5))
+ self.log("last played %s days ago" % repr(days_ago))
+ self.log("suggested play: after %s days" % suggested)
+ return suggested > days_ago
+
def on_song_started(self, song):
"""Should be called by the plugin when a new song starts. If
the right conditions apply, we start looking for new songs to
@@ -348,8 +381,6 @@
def queue_song(self):
"""Queue a single track"""
- restrictions = self.player_construct_restrictions(
- self.track_block_time, self.relaxors, self.restrictors)
self.unblock_artists()
found = None
generator = self.song_generator()
@@ -364,23 +395,20 @@
yield
score, result = item
self.log("looking for: %s, %s" % (score, repr(result)))
- search = self.player_construct_search(result, restrictions)
+ search = self.player_construct_search(result,
self.restrictions)
artist = result.get('artist')
if artist:
if artist in blocked:
continue
songs = self.player_search(search)
if songs:
- song = random.choice(songs)
- songs.remove(song)
- while (
- song.get_artist() in blocked
- and songs):
+ while songs:
song = random.choice(songs)
songs.remove(song)
+ if not self.disallowed(song):
+ found = song
+ break
yield
- if not song.get_artist() in blocked:
- found = song
elif self.weed:
self.prune_titles.append(result.get("title"))
except StopIteration:
@@ -755,8 +783,8 @@
cursor2, self.max_artist_match, scale_to,
offset=10000))
else:
generators.append(
- self.get_similar_artists_from_lastfm(artist_name,
artist_id)
- )
+ self.get_similar_artists_from_lastfm(
+ artist_name, artist_id))
else:
generators.append(
self.get_similar_artists_from_lastfm(artist_name,
artist_id))
Modified: trunk/quodlibet_autoqueue.py
==============================================================================
--- trunk/quodlibet_autoqueue.py (original)
+++ trunk/quodlibet_autoqueue.py Sun Mar 15 09:21:35 2009
@@ -68,12 +68,9 @@
'label': 'keep db clean'},
}
STR_SETTINGS = {
- 'restrictors' : {
+ 'restrictions' : {
'value': '',
'label': 'restrict',},
- 'relaxors' : {
- 'value': '',
- 'label': 'relax',},
}
def escape(the_string):
@@ -105,6 +102,18 @@
def get_length(self):
return self.song("~#length")
+ def get_playcount(self):
+ return self.song("~#playcount")
+
+ def get_added(self):
+ return self.song("~#added")
+
+ def get_last_played(self):
+ return self.song("~#lastplayed")
+
+ def get_rating(self):
+ return self.song("~#rating")
+
class AutoQueue(EventPlugin, AutoQueueBase):
"""The actual plugin class"""
@@ -280,16 +289,6 @@
if restrictions:
search = "&(%s, %s)" % (search, restrictions)
return search
-
- def player_construct_restrictions(
- self, track_block_time, relaxors, restrictors):
- """contstruct a search to further modify the searches"""
- restrictions = "#(laststarted > %s days)" % track_block_time
- if relaxors:
- restrictions = "|(%s, %s)" % (restrictions, relaxors)
- if restrictors:
- restrictions = "&(%s, %s)" % (restrictions, restrictors)
- return restrictions
def player_set_variables_from_config(self):
"""Initialize user settings from the configuration storage"""