Refactor alot

- add django-redis-cache
- remove CurrentTrack db model
This commit is contained in:
nikolark committed 2016-04-06 22:16:32 +02:00
1 parent 531488d4a0
commit d4f862cb4a
9 files changed
+120 -141

No files matched your search

+3 -44
View File
@@ -1,55 +1,14 @@
from django.utils import timezone
from rest_framework.response import Response
from rest_framework.views import APIView
from django.contrib.humanize.templatetags.humanize import naturaltime
from dateutil import parser
from oliver_screen import lastfm, utils
from oliver_screen.lastfm import get_track_data, get_last_track_data
class LastTrackView(APIView):
def _get_playback_date(self, playback_date_string):
playback_date = parser.parse(playback_date_string)
return timezone.make_aware(playback_date, timezone.UTC()) # Last.fm API is in UTC
def _time_since(self, playback_date_string):
playback_date = self._get_playback_date(playback_date_string)
formatted = naturaltime(playback_date)
formatted = formatted.replace(u'\xa0', u' ') # remove non-breaking space (in latin1)
return formatted
def get(self, request, format=None):
user = lastfm.get_user()
playedtracks = user.get_recent_tracks(limit=2)
track_data = {
'artist': playedtracks[0].track.get_artist().get_name(),
'title': playedtracks[0].track.get_title(),
'playback_date': self._get_playback_date(playedtracks[0].playback_date),
'time_since': self._time_since(playedtracks[0].playback_date)
}
return Response({'track': track_data})
return Response({'track': get_last_track_data()})
class CurrentTrackView(APIView):
def get(self, request, format=None):
user = lastfm.get_user()
track = user.get_now_playing()
if track is None:
# No response from LastFM?
return Response({'track': utils.get_current_from_cache()})
artist = track.get_artist()
video = utils.get_youtubevideo(artist.get_name(), track.get_title())
image = artist.get_cover_image(size=4)
now_playing = {
'artist': artist.get_name(),
'title': track.get_title(),
'image': image,
'video': video
}
utils.cache_current(now_playing)
return Response({'track': now_playing})
return Response({'track': get_track_data()})
+2 -14
View File
@@ -1,9 +1,7 @@
from channels import Group
from channels.sessions import channel_session
from django.conf import settings
import json
from oliver_screen.models import ScreenConsumer
from oliver_screen.tasks import update_screens_task
@@ -17,21 +15,11 @@ def ws_connect(message):
g = Group(settings.OLIVER_WS_GROUP, channel_layer=message.channel_layer)
g.add(message.reply_channel)
active_consumers = ScreenConsumer.objects.filter(is_active=True)
# At last one
if active_consumers.exists():
screen_consumer = active_consumers.first()
else:
screen_consumer = ScreenConsumer.objects.create()
update_screens_task() # async
g.send({'text': json.dumps({'screen_consumer': {'uuid': str(screen_consumer.uuid)}})})
update_screens_task() # async
@channel_session
def ws_disconnect(message):
Group(settings.OLIVER_WS_GROUP, channel_layer=message.channel_layer).discard(message.reply_channel)
# FIXME: only set specific uuid inactive and only revoke is no more active screens
ScreenConsumer.objects.filter(is_active=True).update(is_active=False)
update_screens_task.revoke()
# update_screens_task.revoke()
+57 -5
View File
@@ -1,13 +1,65 @@
import pylast
from django.conf import settings
from django.utils import timezone
from django.contrib.humanize.templatetags.humanize import naturaltime
from dateutil import parser
from oliver_screen import utils
from oliver_screen.models import LastFMUser
def get_user():
network = pylast.LastFMNetwork(api_key=settings.LASTFM_API_KEY, api_secret=settings.LASTFM_API_SECRET)
lastfmusers = LastFMUser.objects.filter(active=True)
if len(lastfmusers) != 1:
# default
return network.get_user(settings.LASTFM_DEFAULT_USERNAME)
return network.get_user(lastfmusers[0].name)
lastfmusers = LastFMUser.objects.filter(active=True)
lastfm_username = lastfmusers[0].name if len(lastfmusers) == 1 else settings.LASTFM_DEFAULT_USERNAME
return network.get_user(lastfm_username)
def _get_playback_date(playback_date_string):
playback_date = parser.parse(playback_date_string)
return timezone.make_aware(playback_date, timezone.UTC()) # Last.fm API is in UTC
def _time_since(playback_date_string):
playback_date = _get_playback_date(playback_date_string)
formatted = naturaltime(playback_date)
formatted = formatted.replace(u'\xa0', u' ') # remove non-breaking space (in latin1)
return formatted
def get_last_track_data():
user = get_user()
playedtracks = user.get_recent_tracks(limit=2)
track_data = {
'artist': playedtracks[0].track.get_artist().get_name(),
'title': playedtracks[0].track.get_title(),
'playback_date': _get_playback_date(playedtracks[0].playback_date),
'time_since': _time_since(playedtracks[0].playback_date)
}
return track_data
def get_track_data():
user = get_user()
track = user.get_now_playing()
if track is None:
return utils.get_current_from_cache()
artist = track.get_artist()
image = artist.get_cover_image(size=4)
track_data = {
'artist': artist.get_name(),
'title': track.get_title(),
'image': image,
}
utils.cache_current(track_data)
return track_data
@@ -0,0 +1,17 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('oliver_screen', '0003_auto_20160403_1343'),
]
operations = [
migrations.DeleteModel(
name='CurrentTrack',
),
]
-10
View File
@@ -12,16 +12,6 @@ class ScreenConsumer(models.Model):
return str(self.uuid)
class CurrentTrack(models.Model):
title = models.CharField(max_length=200)
artist = models.CharField(max_length=200)
image = models.CharField(max_length=200)
retries = models.IntegerField()
def __str__(self):
return self.title + " - " + self.artist
class LastFMUser(models.Model):
name = models.CharField(max_length=200)
active = models.BooleanField(default=True)
+26 -27
View File
@@ -2,45 +2,44 @@ import json
import logging
from django.conf import settings
from django.core.cache import cache
from huey.contrib.djhuey import db_task
from channels import Group
from oliver_screen import utils, lastfm
from oliver_screen.models import ScreenConsumer
from oliver_screen import lastfm
logger = logging.getLogger(__name__)
LOCK_EXPIRE = 60 * 5 # Lock expires in 5 minutes
def acquire_lock(lock_id):
# cache.add fails if the key already exists
return cache.add(lock_id, 'true', LOCK_EXPIRE)
def release_lock(lock_id):
# memcache delete is very slow, but we have to use it to take advantage of using add() for atomic locking
return cache.delete(lock_id)
@db_task()
def update_screens_task():
screen_channel_group = Group(settings.OLIVER_WS_GROUP)
lock_id = '{0}-lock'.format(settings.OLIVER_WS_GROUP)
logger.debug('Updating screens')
if acquire_lock(lock_id):
try:
track_data = lastfm.get_track_data()
finally:
release_lock(lock_id)
user = lastfm.get_user()
track = user.get_now_playing()
if track is None:
track_data = utils.get_current_from_cache()
logger.debug("sending ", track_data, "to", screen_channel_group.name)
screen_channel_group.send({'track': json.dumps({'track': track_data})})
return
screen_channel_group.send({'text': json.dumps({'track': track_data})})
artist = track.get_artist()
image = artist.get_cover_image(size=4)
track_data = {
'artist': artist.get_name(),
'title': track.get_title(),
'image': image,
}
utils.cache_current(track_data)
logger.debug("sending ", track_data, "to", screen_channel_group.name)
screen_channel_group.send({'text': json.dumps({'track': track_data})})
# At least one active screen
if ScreenConsumer.objects.filter(is_active=True).exists():
update_screens_task.schedule(delay=settings.OLIVER_LASTFM_POLL_INTERVAL)
else:
logger.debug('No active screens, bailing')
return track_data
return track_data
logger.debug('Last.FM is already being polled, doing nothing.')
+6 -38
View File
@@ -1,4 +1,5 @@
from oliver_screen.models import CurrentTrack, YouTubeVideo
from django.core.cache import cache
from oliver_screen.models import YouTubeVideo
def get_youtubevideo(artist, title):
@@ -9,45 +10,12 @@ def get_youtubevideo(artist, title):
return videos[0]
CACHE_KEY = 'oliver-track'
def cache_current(now_playing):
# Fetch the one CurrentTrack entry in the db and update it with the current track.
try:
current = CurrentTrack.objects.get(pk=1)
except CurrentTrack.DoesNotExist:
# update
current = CurrentTrack(artist="", title="", image="", retries=0)
current.artist = now_playing['artist']
current.title = now_playing['title']
current.image = now_playing['image']
current.retries = 0
current.save()
def cache_current(track):
return cache.set(CACHE_KEY, track, 20) # in seconds
def get_current_from_cache():
try:
current = CurrentTrack.objects.get(pk=1)
except CurrentTrack.DoesNotExist:
current = CurrentTrack(artist="", title="", image="", retries=0)
current.save()
now_playing = {}
# try 3 times before clearing the cache
if current.artist != "" and current.retries < 3:
now_playing = {
'artist': current.artist,
'title': current.title,
'image': current.image
}
current.retries += 1
current.save()
else:
current.artist = ""
current.title = ""
current.image = ""
current.save()
return now_playing
return cache.get(CACHE_KEY)
+8 -3
View File
@@ -1,14 +1,12 @@
from __future__ import unicode_literals
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
import os
from huey import RedisHuey
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.7/howto/deployment/checklist/
# See https://docs.djangoproject.com/en/1.8/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = '#r65fsg)wsk&cs8m^i)@##7-wg=#z=*b_)a82#5z#4%&!j_9=6'
@@ -102,6 +100,13 @@ OLIVER_LASTFM_POLL_INTERVAL = 10 # seconds
HUEY = RedisHuey('oliverscreen', result_store=True)
CACHES = {
'default': {
'BACKEND': 'redis_cache.RedisCache',
'LOCATION': 'localhost:6379',
}
}
# Local settings
try:
from .local_settings import *
+1
View File
@@ -3,6 +3,7 @@ channels==0.10.3
Django>=1.8,<1.9
django-extensions==1.6.1
django-flat-theme==1.1.3
django-redis-cache==1.6.5
djangorestframework==3.3.3
gevent==1.1.0
gunicorn==19.4.5