Skip to content

Commit

Permalink
Added relative playlist date support
Browse files Browse the repository at this point in the history
  • Loading branch information
plamere committed Feb 21, 2016
1 parent e7b61be commit ccc7d6f
Show file tree
Hide file tree
Showing 7 changed files with 198 additions and 46 deletions.
6 changes: 6 additions & 0 deletions server/compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ def convert_val_to_type(val, type, program):
return OK, val
elif type == 'optional_date':
return OK, val
elif type == 'optional_rel_date':
return OK, val
elif type == 'uri':
return OK, str(val)
elif type == 'uri_list':
Expand Down Expand Up @@ -146,6 +148,10 @@ def compile_object(objname, program):
symbols[objname] = obj
hsymbols[obj] = objname
return OK, obj
except pbl.PBLException as e:
#traceback.print_exc()
print 'e reason', e.reason
raise pbl.PBLException(None, e.reason, objname)
except:
traceback.print_exc()
if debug_exceptions:
Expand Down
76 changes: 75 additions & 1 deletion server/components.py
Original file line number Diff line number Diff line change
Expand Up @@ -836,6 +836,79 @@
},
}
},
{
"name" : "RelativeDatedSpotifyPlaylist",
"class": plugs.RelativeDatedPlaylistSource,
"type" : "source",
"display": "playlist (rel date)",
"description": "loads tracks from the given spotify playlist, potentially ordered and filtered by the relative track added date",

"help" : """ This component will generate a stream of tracks from the given Spotify
playlist. If you specify a Spotify playlist <b>URI</b>, that playlist will
be loaded. If you omit the URI but specify a <b>user</b> and a
<b>name</b>, the user's public playlists will be searched for the playlist with the
given name. If no user is specified, the most popular playlist with
the given <b>name</b> will be used.
<p>
By default tracks are generated in playlist order. If <b>Order by
date added</b> is set, tracks are returned in order of the date they
were added to the playlist.
<p>
By setting relative dates <b>tracks added before</b> and/or <b> tracks added since</b>
you can restrict tracks generated to just those that were added in
the given period.
<p> Examples of relative dates:
<ul>
<li> 5 days
<li> 1 year, 2 months and 3 days
<li> last week
<li> two weeks ago
</ul>
More examples can be found on the <a href="about.html"> about
page</a>
""",

"title": "$name (rel date filtered)",
"params": {
"name": {
"type" : "string",
"optional" : False,
"description": "the name of the playlist",
"default" : "Your favorite coffeehouse"
},
"user": {
"type" : "string",
"optional" : True,
"description": "the owner of the playlist",
},
"uri": {
"type" : "string",
"optional" : True,
"description": "the uri of the playlist",
},
"order_by_date_added": {
"type" : "bool",
"optional" : True,
"default" : False,
"display": "Order by date added",
"description": "if true, tracks are ordered by the date added to the playlist",
},
"tracks_added_since": {
"type" : "string",
"display": "Include only tracks added since",
"optional" : True,
"default" : "",
"description": "If set, only tracks added since this relative date are generated",
},
"tracks_added_before": {
"type" : "string",
"display": "Include only tracks added before",
"optional" : True,
"default" : "",
"description": "If set, only tracks added before this relative date are generated",
},
}
},
{
"name" : "DatedSpotifyPlaylist",
"class": plugs.DatedPlaylistSource,
Expand Down Expand Up @@ -1886,7 +1959,8 @@ def check_components():

def is_valid_param_type(type):
valid_types = set(['number', 'string', 'port', 'bool',
'uri', 'uri_list', 'string_list', 'time', 'any', 'optional_date'])
'uri', 'uri_list', 'string_list', 'time', 'any', 'optional_date',
'optional_rel_date'])
if type in valid_types:
return True
if type in inventory['types']:
Expand Down
103 changes: 65 additions & 38 deletions server/plugs.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from pbl import spotify_plugs
import simplejson as json
import time
import reltime

cache = SimpleCache()

Expand Down Expand Up @@ -741,15 +742,6 @@ def _get_uri_from_name_and_user(self, name, user):
results = None
return None

def _parse_date(self, sdate):
try:
date = datetime.datetime.strptime(sdate, "%Y-%m-%dT%H:%M:%SZ")
return int(date.strftime("%s"))
except ValueError:
return -1
except:
return -1

def _get_more_tracks(self):
_,_,user,_,playlist_id = self.uri.split(':')
try:
Expand All @@ -762,7 +754,7 @@ def _get_more_tracks(self):
for item in results['items']:
self.track_count += 1
good_track = True
ts = self._parse_date(item['added_at'])
ts = parse_date(item['added_at'])
if self.tracks_added_before >= 0 and ts >= 0 and ts > self.tracks_added_before:
good_track = False
if self.tracks_added_since >=0 and ts >=0 and ts < self.tracks_added_since:
Expand Down Expand Up @@ -819,35 +811,42 @@ class RelativeDatedPlaylistSource(object):
:param uri: the uri of the playlist
:param user: the owner of the playlist
:param order_by_date_added: if true, tracks are ordered by the date they were added to the playlist
:param tracks_added_since: if not None, only tracks added after this
relative time (given in seconds in the past from now)
:param tracks_added_before: if not None, only tracks added before this
relative time (given in seconds in the past from now)
:param tracks_added_since: if not None or empty, only tracks added after this
relative time are generated
:param tracks_added_before: if not None or empty, only tracks added before this
relative time are generated
'''

def __init__(self, name, uri=None, user=None,
order_by_date_added=False,
tracks_added_since=None,
tracks_added_before=None):
def __init__(self, name, uri=None, user=None, order_by_date_added=False,
tracks_added_since=None, tracks_added_before=None):

self.name = name
self.uri = spotify_plugs.normalize_uri(uri)
self.user = user
self.order_by_date_added = order_by_date_added

if tracks_added_before != None:
delta_tracks_added_before = datetime.timedelta(seconds=abs(tracks_added_before))
self.tracks_added_before = date_to_epoch(now() - delta_tracks_added_before)
if tracks_added_before != None and len(tracks_added_before) > 0:
try:
delta = reltime.parse_to_rel_time(tracks_added_before)
self.tracks_added_before = date_to_epoch(now()) - delta
except ValueError as e:
raise pbl.PBLException('bad relative time format', str(e))
else:
self.tracks_added_before = -1

if tracks_added_since != None:
delta_tracks_added_since = datetime.timedelta(seconds=abs(tracks_added_since))
self.tracks_added_since = date_to_epoch(now() - delta_tracks_added_since)
if tracks_added_since != None and len(tracks_added_since) > 0:
try:
delta = reltime.parse_to_rel_time(tracks_added_since)
self.tracks_added_since = date_to_epoch(now()) - delta
except ValueError as e:
raise pbl.PBLException(self, 'bad relative time format ' + str(e))
else:
self.tracks_added_since = -1

#print "since", tracks_added_since, self.tracks_added_since, date_to_epoch(now())
#print "before", tracks_added_before, self.tracks_added_before, date_to_epoch(now())

self.next_offset = 0
self.limit = 100

Expand Down Expand Up @@ -876,14 +875,6 @@ def _get_uri_from_name_and_user(self, name, user):
results = None
return None

def _parse_date(self, sdate):
try:
date = datetime.datetime.strptime(sdate, "%Y-%m-%dT%H:%M:%SZ")
return int(date.strftime("%s"))
except ValueError:
return -1
except:
return -1

def _get_more_tracks(self):
_,_,user,_,playlist_id = self.uri.split(':')
Expand All @@ -897,12 +888,13 @@ def _get_more_tracks(self):
for item in results['items']:
self.track_count += 1
good_track = True
ts = self._parse_date(item['added_at'])
ts = parse_date(item['added_at'])
if self.tracks_added_before >= 0 and ts >= 0 and ts > self.tracks_added_before:
good_track = False
if self.tracks_added_since >=0 and ts >=0 and ts < self.tracks_added_since:
if self.tracks_added_since >= 0 and ts >=0 and ts < self.tracks_added_since:
good_track = False
track = item['track']
# print good_track, ts, self.tracks_added_before, self.tracks_added_since, track['name']
if good_track and ts >= 0 and track and 'id' in track:
self.tracks.append( (track['id'], ts) )
spotify_plugs._add_track(self.name, track)
Expand Down Expand Up @@ -1087,8 +1079,6 @@ def next_track(self):
else:
return None

def now():
return datetime.datetime.now()

def get_day_of_week():
days = ['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'monday']
Expand Down Expand Up @@ -1225,8 +1215,23 @@ def next_track(self):
else:
return None

def now():
return datetime.datetime.now()

def date_to_epoch(date):
return date - datetime.datetime(1970,1,1).total_seconds()
return (date - datetime.datetime(1970,1,1)).total_seconds()

def parse_date(sdate):
try:
date = datetime.datetime.strptime(sdate, "%Y-%m-%dT%H:%M:%SZ")
return date_to_epoch(date)
except ValueError:
return -1
except:
return -1




if __name__ == '__main__':

Expand Down Expand Up @@ -1257,7 +1262,7 @@ def date_to_epoch(date):
src = pbl.PlaylistSource("extender test", None, 'plamere')
pbl.show_source(src)

if True:
if False:
print 'weighted source'

print 'factor', 1
Expand All @@ -1284,3 +1289,25 @@ def date_to_epoch(date):
src = pbl.PlaylistSource("extender test", None, 'plamere')
src = WeightedShuffler(src, .01)
pbl.show_source(src)

if True:
sixmonths = 60 * 60 * 24 * 30 * 6
onemonth = 60 * 60 * 24 * 30 * 1

print "older than six months"
src = RelativeDatedPlaylistSource("extender test", None, 'plamere',
order_by_date_added=False,
tracks_added_since=None, tracks_added_before="6 months")
pbl.show_source(src)

print "new than six months"
src = RelativeDatedPlaylistSource("extender test", None, 'plamere',
order_by_date_added=False,
tracks_added_since="six mnths", tracks_added_before="")
pbl.show_source(src)

print "new than six months, older than one month"
src = RelativeDatedPlaylistSource("extender test", None, 'plamere',
order_by_date_added=False,
tracks_added_since="six months", tracks_added_before="1 month")
pbl.show_source(src)
7 changes: 3 additions & 4 deletions server/program_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ def execute_program(self, auth_code, pid, save_playlist):
pbl.engine.setEnv('spotify_user_id', token['user_id'])

print 'executing', user, pid
#print 'executing', json.dumps(program, indent=4)
print '# executing', json.dumps(program, indent=4)
status, obj = compiler.compile(program)
print 'compiled in', time.time() - start, 'secs'

Expand Down Expand Up @@ -281,13 +281,12 @@ def execute_program(self, auth_code, pid, save_playlist):
except pbl.PBLException as e:
results['status'] = 'error'
results['message'] = e.reason
if e.component:
cname = program['hsymbols'][e.component]
if e.component and e.component.name in program['hsymbols']:
cname = program['hsymbols'][e.component.name]
else:
cname = e.cname
results['component'] = cname
print 'PBLException', json.dumps(results, indent=4)

traceback.print_exc()
if debug_exceptions:
raise
Expand Down
31 changes: 30 additions & 1 deletion web/about.html
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,32 @@ <h3 class="list-group-item-heading">The playlist component is
</p>
</li>

<li class="list-group-item">
<h3 class="list-group-item-heading">What's the relative date
syntax?
</h3>
<p class="list-group-item-text">
Some components, like <a href="info.html?component=RelativeDatedSpotifyPlaylist">
playlist (rel date) </a> support relative dates. Some examples of these
dates are:
<ul>
<li>1 month</li>
<li>2 days 2 hours</li>
<li>3 years 2 months 2 days</li>
<li>3 years 2 months and 2 days ago</li>
<li>3 years, 2 months and 22 days ago!</li>
<li>1 h 3 w 2 d</li>
<li>last week</li>
<li>last month</li>
<li>last year and three weeks ago</li>
<li>six weeks</li>
<li>a week ago</li>
<li>twenty days ago</li>
<li>6 mnths, 2 wks</li>
</ul>
</p>
</li>

<li class="list-group-item">
<h3 class="list-group-item-heading">How do I save my program?
</h3>
Expand Down Expand Up @@ -249,7 +275,7 @@ <h2> Available Components</h2>
<div class="container-fluid col-sm-offset-2 col-sm-8">
<h2> Version Info </h2>

<h3> Alpha V3.3 - February 15-20 2016 </h3>
<h3> Alpha V3.3 - February 15-25 2016 </h3>
<ul>
<li> Added component detail page (accessible via the about page) </li>
<li> Added Artist De-Dup component</li>
Expand All @@ -259,6 +285,9 @@ <h3> Alpha V3.3 - February 15-20 2016 </h3>
<li> Added 'by name' param to TrackFilter </li>
<li> Added invert param to ArtistFilter </li>
<li> Sort programs by last run time on the program page</li>
<li> Added <b>playlist (rel date)</b> support, allowing for
retrieving tracks from playlists based on when they were added
to the playlist, supports relative dates.
</ul>
<h3> Alpha V3.2 - February 14, 2016 </h3>
<ul>
Expand Down
16 changes: 16 additions & 0 deletions web/editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,22 @@ var createEditor = function(canvasElem, inventory, types, isReadOnly) {
return parseTime(val);
}

function secsToRelativeTimeString(secs) {
if (secs == -1) {
return "";
} else {
return secs.toString();
}
}

function relativeTimeStringToSecs(val) {
if (val.length == 0) {
return -1;
} else {
return parseInt(val);
}
}

function clearComponentErrors() {
$("#errors").empty(200);
_.each(nameToRect, function(rect, name) {
Expand Down
Loading

0 comments on commit ccc7d6f

Please sign in to comment.