Archived
Django 1.7 and cleanups
This commit is contained in:
1 parent
dcae0e9048
commit
a46d07843e
30 files changed
+386
-415
No files matched your search
+3
-2
@@ -1,6 +1,7 @@
|
|||||||
*.pyc
|
*.pyc
|
||||||
*.swp
|
*.swp
|
||||||
*.swo
|
*.swo
|
||||||
settings.py
|
db.sqlite3
|
||||||
oliver_screen.sqlite3
|
local_settings.py
|
||||||
venv
|
venv
|
||||||
|
.idea
|
||||||
@@ -1,31 +1,16 @@
|
|||||||
Requirements
|
# Install
|
||||||
============
|
apt install python-virtualenv
|
||||||
* Django
|
virtualenv venv
|
||||||
* sudo apt-get install python-django
|
. venv/bin/activate
|
||||||
* mod\_wsgi
|
pip install -r requirements.txt
|
||||||
* sudo apt-get install libapache2-mod-wsgi
|
python manage.py migrate
|
||||||
* sudo a2enmod wsgi # enable it in apache.
|
python manage.py runserver
|
||||||
* pylast
|
|
||||||
* svn checkout http://pylast.googlecode.com/svn/trunk/ pylast-read-only
|
|
||||||
* cd pylast-read-only
|
|
||||||
* sudo python setup.py install
|
|
||||||
|
|
||||||
You will also need a LastFM account and a API account (http://www.last.fm/api/account).
|
* You will also need a LastFM account and a API account from http://www.last.fm/api/account
|
||||||
|
* Create a local_settings.py and set your own LASTFM\_APIKEY and LASTFM\_API\_SECRET
|
||||||
|
|
||||||
Install with Apache
|
# Usage
|
||||||
===================
|
* Create an admin user: python manage.py createsuperuser
|
||||||
* Get the code
|
* Goto /admin, login, then add a LastFMUser and make it active.
|
||||||
* $ git clone git://github.com/nikolaik/oliver\_screen.git
|
* Setup your music player (f.ex Spotify) to scrobble to that LastFM account.
|
||||||
* Make available static files under oliver\_screen/oliver\_screen/static by symlinking or setup a <Directory> and Alias in your Apache config.
|
|
||||||
* Then setup a WSGIScriptAlias in your apache config pointing to the full path of django.wsgi.
|
|
||||||
* sudo /etc/init.d/apache restart # load new Apache configuration settings
|
|
||||||
* Copy settings-sample.py to settings.py and edit to suit your needs.
|
|
||||||
* Set MEDIA\_URL to the URL where static files are served.
|
|
||||||
* Set LASTFM\_APIKEY and LASTFM\_API\_SECRET
|
|
||||||
* Create the database.
|
|
||||||
* $ python manage.py syncdb (creating an admin user)
|
|
||||||
* Make sure the files have correct permission (readable by www-data).
|
|
||||||
* If you created a sqlite database, make sure the file is writeable by www-data.
|
|
||||||
* Goto /admin and login with the admin user, then add a LastFMUser and make it active.
|
|
||||||
* Setup your music player (f.ex Spotify) to scrobble to that account Last.fm account.
|
|
||||||
* Goto / and you should be set :=)
|
* Goto / and you should be set :=)
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "oliversite.settings")
|
||||||
|
|
||||||
|
from django.core.management import execute_from_command_line
|
||||||
|
|
||||||
|
execute_from_command_line(sys.argv)
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
from django.contrib import admin
|
||||||
|
|
||||||
|
from oliver_screen.models import LastFMUser, YouTubeVideo
|
||||||
|
|
||||||
|
|
||||||
|
class LastFMAdmin(admin.ModelAdmin):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class VideoAdmin(admin.ModelAdmin):
|
||||||
|
pass
|
||||||
|
|
||||||
|
admin.site.register(LastFMUser, LastFMAdmin)
|
||||||
|
admin.site.register(YouTubeVideo, VideoAdmin)
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
import os
|
|
||||||
import sys
|
|
||||||
from os.path import dirname, join
|
|
||||||
|
|
||||||
def map_path(target_name=''):
|
|
||||||
'''Enables path names to be decided at runtime.'''
|
|
||||||
return join(dirname(__file__), target_name).replace('\\', '/')
|
|
||||||
|
|
||||||
os.environ['DJANGO_SETTINGS_MODULE'] = 'oliver_screen.settings'
|
|
||||||
|
|
||||||
path = map_path("..")
|
|
||||||
if path not in sys.path:
|
|
||||||
sys.path.append(path)
|
|
||||||
import django.core.handlers.wsgi
|
|
||||||
application = django.core.handlers.wsgi.WSGIHandler()
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
from django.db import models
|
|
||||||
|
|
||||||
# Create your models here.
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
"""
|
|
||||||
This file demonstrates two different styles of tests (one doctest and one
|
|
||||||
unittest). These will both pass when you run "manage.py test".
|
|
||||||
|
|
||||||
Replace these with more appropriate tests for your application.
|
|
||||||
"""
|
|
||||||
|
|
||||||
from django.test import TestCase
|
|
||||||
|
|
||||||
class SimpleTest(TestCase):
|
|
||||||
def test_basic_addition(self):
|
|
||||||
"""
|
|
||||||
Tests that 1 + 1 always equals 2.
|
|
||||||
"""
|
|
||||||
self.failUnlessEqual(1 + 1, 2)
|
|
||||||
|
|
||||||
__test__ = {"doctest": """
|
|
||||||
Another way to test that 1 + 1 is equal to 2.
|
|
||||||
|
|
||||||
>>> 1 + 1 == 2
|
|
||||||
True
|
|
||||||
"""}
|
|
||||||
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
from django.conf.urls.defaults import *
|
|
||||||
urlpatterns = patterns('oliver_screen.main.views',
|
|
||||||
(r'^$', 'index'),
|
|
||||||
)
|
|
||||||
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
from django.http import HttpResponse
|
|
||||||
from django.shortcuts import render_to_response, get_object_or_404
|
|
||||||
from django.template import RequestContext
|
|
||||||
|
|
||||||
# My views
|
|
||||||
def index(request):
|
|
||||||
return render_to_response('public/index.html', context_instance=RequestContext(request))
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
#!/usr/bin/python
|
|
||||||
from django.core.management import execute_manager
|
|
||||||
try:
|
|
||||||
import settings # Assumed to be in the same directory.
|
|
||||||
except ImportError:
|
|
||||||
import sys
|
|
||||||
sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n(If the file settings.py does indeed exist, it's causing an ImportError somehow.)\n" % __file__)
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
execute_manager(settings)
|
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import models, migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='CurrentTrack',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||||
|
('title', models.CharField(max_length=200)),
|
||||||
|
('artist', models.CharField(max_length=200)),
|
||||||
|
('image', models.CharField(max_length=200)),
|
||||||
|
('retries', models.IntegerField()),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
},
|
||||||
|
bases=(models.Model,),
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='LastFMUser',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||||
|
('name', models.CharField(max_length=200)),
|
||||||
|
('active', models.BooleanField(default=True)),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
},
|
||||||
|
bases=(models.Model,),
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='YouTubeVideo',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||||
|
('title', models.CharField(max_length=200)),
|
||||||
|
('artist', models.CharField(max_length=200)),
|
||||||
|
('video_id', models.CharField(max_length=200)),
|
||||||
|
('start', models.IntegerField()),
|
||||||
|
('active', models.BooleanField(default=True)),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
},
|
||||||
|
bases=(models.Model,),
|
||||||
|
),
|
||||||
|
]
|
||||||
File renamed without changes.
@@ -1,5 +1,6 @@
|
|||||||
from django.db import models
|
from django.db import models
|
||||||
|
|
||||||
|
|
||||||
class CurrentTrack(models.Model):
|
class CurrentTrack(models.Model):
|
||||||
title = models.CharField(max_length=200)
|
title = models.CharField(max_length=200)
|
||||||
artist = models.CharField(max_length=200)
|
artist = models.CharField(max_length=200)
|
||||||
@@ -9,24 +10,25 @@ class CurrentTrack(models.Model):
|
|||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return self.title + " - " + self.artist
|
return self.title + " - " + self.artist
|
||||||
|
|
||||||
|
|
||||||
class LastFMUser(models.Model):
|
class LastFMUser(models.Model):
|
||||||
name = models.CharField(max_length=200)
|
name = models.CharField(max_length=200)
|
||||||
active = models.BooleanField()
|
active = models.BooleanField(default=True)
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
if self.active:
|
if self.active:
|
||||||
return self.name + ": active"
|
return self.name + ": active"
|
||||||
return self.name + ": NOT active"
|
return self.name + ": NOT active"
|
||||||
|
|
||||||
|
|
||||||
class YouTubeVideo(models.Model):
|
class YouTubeVideo(models.Model):
|
||||||
title = models.CharField(max_length=200)
|
title = models.CharField(max_length=200)
|
||||||
artist = models.CharField(max_length=200)
|
artist = models.CharField(max_length=200)
|
||||||
videoId = models.CharField(max_length=200)
|
video_id = models.CharField(max_length=200) # FIXME: Update template
|
||||||
start = models.IntegerField()
|
start = models.IntegerField()
|
||||||
active = models.BooleanField()
|
active = models.BooleanField(default=True)
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
if self.active:
|
if self.active:
|
||||||
return self.artist + " - " + self.title + ": active"
|
return self.artist + " - " + self.title + ": active"
|
||||||
return self.artist +" - " + self.title + " : NOT active"
|
return self.artist + " - " + self.title + " : NOT active"
|
||||||
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
Django==1.3.7
|
|
||||||
pylast==0.5.11
|
|
||||||
|
|
||||||
@@ -1,107 +0,0 @@
|
|||||||
# Django settings for oliver_screen project.
|
|
||||||
|
|
||||||
from os.path import dirname, join
|
|
||||||
|
|
||||||
def map_path(target_name):
|
|
||||||
'''Enables path names to be decided at runtime.'''
|
|
||||||
return join(dirname(__file__), target_name).replace('\\', '/')
|
|
||||||
|
|
||||||
DEBUG = True
|
|
||||||
TEMPLATE_DEBUG = DEBUG
|
|
||||||
|
|
||||||
ADMINS = (
|
|
||||||
# ('EDB', 'nikolai@studentersamfundet.no'),
|
|
||||||
)
|
|
||||||
|
|
||||||
MANAGERS = ADMINS
|
|
||||||
|
|
||||||
DATABASES = {
|
|
||||||
'default': {
|
|
||||||
'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
|
|
||||||
'NAME': map_path('oliver_screen.sqlite3'), # Or path to database file if using sqlite3.
|
|
||||||
'USER': '', # Not used with sqlite3.
|
|
||||||
'PASSWORD': '', # Not used with sqlite3.
|
|
||||||
'HOST': '', # Set to empty string for localhost. Not used with sqlite3.
|
|
||||||
'PORT': '', # Set to empty string for default. Not used with sqlite3.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# Local time zone for this installation. Choices can be found here:
|
|
||||||
# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
|
|
||||||
# although not all choices may be available on all operating systems.
|
|
||||||
# On Unix systems, a value of None will cause Django to use the same
|
|
||||||
# timezone as the operating system.
|
|
||||||
# If running in a Windows environment this must be set to the same as your
|
|
||||||
# system time zone.
|
|
||||||
TIME_ZONE = 'Europe/Oslo'
|
|
||||||
|
|
||||||
# Language code for this installation. All choices can be found here:
|
|
||||||
# http://www.i18nguy.com/unicode/language-identifiers.html
|
|
||||||
LANGUAGE_CODE = 'en-us'
|
|
||||||
|
|
||||||
SITE_ID = 1
|
|
||||||
|
|
||||||
# If you set this to False, Django will make some optimizations so as not
|
|
||||||
# to load the internationalization machinery.
|
|
||||||
USE_I18N = True
|
|
||||||
|
|
||||||
# If you set this to False, Django will not format dates, numbers and
|
|
||||||
# calendars according to the current locale
|
|
||||||
USE_L10N = True
|
|
||||||
|
|
||||||
# Absolute path to the directory that holds media.
|
|
||||||
# Example: "/home/media/media.lawrence.com/"
|
|
||||||
MEDIA_ROOT = ''
|
|
||||||
|
|
||||||
# URL that handles the media served from MEDIA_ROOT. Make sure to use a
|
|
||||||
# trailing slash if there is a path component (optional in other cases).
|
|
||||||
# Examples: "http://media.lawrence.com", "http://example.com/media/"
|
|
||||||
MEDIA_URL = '/static/'
|
|
||||||
|
|
||||||
# URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a
|
|
||||||
# trailing slash.
|
|
||||||
# Examples: "http://foo.com/media/", "/media/".
|
|
||||||
ADMIN_MEDIA_PREFIX = '/media/'
|
|
||||||
|
|
||||||
# Make this unique, and don't share it with anybody.
|
|
||||||
SECRET_KEY = 'secretkey'
|
|
||||||
|
|
||||||
# List of callables that know how to import templates from various sources.
|
|
||||||
TEMPLATE_LOADERS = (
|
|
||||||
'django.template.loaders.filesystem.Loader',
|
|
||||||
'django.template.loaders.app_directories.Loader',
|
|
||||||
# 'django.template.loaders.eggs.Loader',
|
|
||||||
)
|
|
||||||
|
|
||||||
MIDDLEWARE_CLASSES = (
|
|
||||||
'django.middleware.common.CommonMiddleware',
|
|
||||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
|
||||||
'django.middleware.csrf.CsrfViewMiddleware',
|
|
||||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
|
||||||
'django.contrib.messages.middleware.MessageMiddleware',
|
|
||||||
)
|
|
||||||
|
|
||||||
ROOT_URLCONF = 'oliver_screen.urls'
|
|
||||||
|
|
||||||
TEMPLATE_DIRS = (
|
|
||||||
# Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
|
|
||||||
# Always use forward slashes, even on Windows.
|
|
||||||
# Don't forget to use absolute paths, not relative paths.
|
|
||||||
map_path('templates')
|
|
||||||
)
|
|
||||||
|
|
||||||
INSTALLED_APPS = (
|
|
||||||
'django.contrib.auth',
|
|
||||||
'django.contrib.contenttypes',
|
|
||||||
'django.contrib.sessions',
|
|
||||||
'django.contrib.sites',
|
|
||||||
'django.contrib.messages',
|
|
||||||
# Uncomment the next line to enable the admin:
|
|
||||||
'django.contrib.admin',
|
|
||||||
# Uncomment the next line to enable admin documentation:
|
|
||||||
# 'django.contrib.admindocs',
|
|
||||||
'oliver_screen.tracks',
|
|
||||||
'oliver_screen.main',
|
|
||||||
)
|
|
||||||
LASTFM_API_KEY = ''
|
|
||||||
LASTFM_API_SECRET = ''
|
|
||||||
@@ -1,27 +1,25 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
{% load staticfiles %}
|
||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
|
<!DOCTYPE html>
|
||||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>Current track</title>
|
<title>Current track</title>
|
||||||
<link rel="stylesheet" type="text/css" href="{{ MEDIA_URL }}screen.css" />
|
<link rel="stylesheet" type="text/css" href="{% static 'screen.css' %}" />
|
||||||
<script type="text/javascript" src="{{ MEDIA_URL }}jquery-1.6.1.min.js"></script>
|
<script type="text/javascript" src="{% static 'jquery-1.6.1.min.js' %}"></script>
|
||||||
<script type="text/javascript" src="{{ MEDIA_URL }}jquery.timers-1.2.js"></script>
|
<script type="text/javascript" src="{% static 'jquery.timers-1.2.js' %}"></script>
|
||||||
<script type="text/javascript" src="{{ MEDIA_URL }}falling-pieces.js"></script>
|
<script type="text/javascript" src="{% static 'falling-pieces.js' %}"></script>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
/* Update track and now playing */
|
/* Update track and now playing */
|
||||||
var get_last_track = function() {
|
var get_last_track = function() {
|
||||||
$( '#last_track' ).load(
|
$( '#last_track' ).load('{% url 'last-track' %}');
|
||||||
'{% url tracks.views.get_last_track %}');
|
|
||||||
};
|
};
|
||||||
var get_now_playing = function() {
|
var get_now_playing = function() {
|
||||||
$( '#now_playing' ).load(
|
$( '#now_playing' ).load('{% url 'now-playing' %}', function() {
|
||||||
'{% url tracks.views.get_now_playing %}', function() {
|
if( is_tetris_song() ) {
|
||||||
if( is_tetris_song() ) {
|
play_tetris();
|
||||||
play_tetris();
|
} else {
|
||||||
} else {
|
dont_play_tetris();
|
||||||
dont_play_tetris();
|
}
|
||||||
}
|
});
|
||||||
});
|
|
||||||
};
|
};
|
||||||
/* Initial update */
|
/* Initial update */
|
||||||
$( document ).ready( get_last_track );
|
$( document ).ready( get_last_track );
|
||||||
@@ -31,15 +29,17 @@
|
|||||||
$( document ).everyTime('10s', "now_playing", get_now_playing );
|
$( document ).everyTime('10s', "now_playing", get_now_playing );
|
||||||
|
|
||||||
/* Ajax spinner */
|
/* Ajax spinner */
|
||||||
$( document ).ajaxStart( function() {
|
$( document )
|
||||||
$( '#spinner' ).show();
|
.ajaxStart(function() {
|
||||||
}).ajaxStop( function() {
|
$( '#spinner' ).show();
|
||||||
|
})
|
||||||
|
.ajaxStop( function() {
|
||||||
$( '#spinner' ).hide();
|
$( '#spinner' ).hide();
|
||||||
});
|
});
|
||||||
|
|
||||||
/* Loads the YouTube IFrame Player API code asynchronously. */
|
/* Loads the YouTube IFrame Player API code asynchronously. */
|
||||||
var tag = document.createElement('script');
|
var tag = document.createElement('script');
|
||||||
tag.src = "http://www.youtube.com/player_api";
|
tag.src = "https://www.youtube.com/player_api";
|
||||||
var firstScriptTag = document.getElementsByTagName('script')[0];
|
var firstScriptTag = document.getElementsByTagName('script')[0];
|
||||||
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
|
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
|
||||||
|
|
||||||
@@ -82,7 +82,7 @@
|
|||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div id="spinner"><img src="{{ MEDIA_URL }}spinner.gif"/></div>
|
<div id="spinner"><img src="{% static 'spinner.gif' %}"/></div>
|
||||||
<div id="container">
|
<div id="container">
|
||||||
<div id="content">
|
<div id="content">
|
||||||
<div id="player"></div>
|
<div id="player"></div>
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
{% load staticfiles %}
|
||||||
{% if now_playing %}
|
{% if now_playing %}
|
||||||
{% if now_playing.video %}
|
{% if now_playing.video %}
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
@@ -27,11 +28,11 @@
|
|||||||
<img src="{{ now_playing.image}}" class="now_playing" /><br />
|
<img src="{{ now_playing.image}}" class="now_playing" /><br />
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<img src="{{ MEDIA_URL}}spectrum-analyzer.gif" /> {{ now_playing.artist}} - {{ now_playing.title }} ♪♫<br />
|
<img src="{% static 'spectrum-analyzer.gif' %}" /> {{ now_playing.artist}} - {{ now_playing.title }} ♪♫<br />
|
||||||
{% else %}
|
{% else %}
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
$("#player").delay(1000).hide();
|
$("#player").delay(1000).hide();
|
||||||
</script>
|
</script>
|
||||||
<img src="{{ MEDIA_URL}}no_music_makes_me_sick_by_sakgaa.jpg" /><br />
|
<img src="{% static 'no_music_makes_me_sick_by_sakgaa.jpg' %}" /><br />
|
||||||
:[
|
:[
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
# Create your tests here.
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
from oliver_screen.tracks.models import LastFMUser, YouTubeVideo
|
|
||||||
from django.contrib import admin
|
|
||||||
|
|
||||||
class LastFMAdmin(admin.ModelAdmin):
|
|
||||||
fieldsets = [
|
|
||||||
(None, {'fields': ['name','active']})
|
|
||||||
]
|
|
||||||
|
|
||||||
class VideoAdmin(admin.ModelAdmin):
|
|
||||||
fieldsets = [
|
|
||||||
(None, {'fields': ['artist', 'title', 'videoId', 'start', 'active']})
|
|
||||||
]
|
|
||||||
|
|
||||||
admin.site.register(LastFMUser, LastFMAdmin)
|
|
||||||
admin.site.register(YouTubeVideo, VideoAdmin)
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
"""
|
|
||||||
This file demonstrates two different styles of tests (one doctest and one
|
|
||||||
unittest). These will both pass when you run "manage.py test".
|
|
||||||
|
|
||||||
Replace these with more appropriate tests for your application.
|
|
||||||
"""
|
|
||||||
|
|
||||||
from django.test import TestCase
|
|
||||||
|
|
||||||
class SimpleTest(TestCase):
|
|
||||||
def test_basic_addition(self):
|
|
||||||
"""
|
|
||||||
Tests that 1 + 1 always equals 2.
|
|
||||||
"""
|
|
||||||
self.failUnlessEqual(1 + 1, 2)
|
|
||||||
|
|
||||||
__test__ = {"doctest": """
|
|
||||||
Another way to test that 1 + 1 is equal to 2.
|
|
||||||
|
|
||||||
>>> 1 + 1 == 2
|
|
||||||
True
|
|
||||||
"""}
|
|
||||||
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
from django.conf.urls.defaults import *
|
|
||||||
urlpatterns = patterns('oliver_screen.tracks.views',
|
|
||||||
(r'^last/$', 'get_last_track'),
|
|
||||||
(r'^now_playing/$', 'get_now_playing'),
|
|
||||||
)
|
|
||||||
|
|
||||||
@@ -1,119 +0,0 @@
|
|||||||
from django.http import HttpResponse
|
|
||||||
from django.shortcuts import render_to_response, get_object_or_404
|
|
||||||
from django.template import RequestContext
|
|
||||||
|
|
||||||
from oliver_screen.tracks.models import LastFMUser, YouTubeVideo, CurrentTrack
|
|
||||||
|
|
||||||
import pylast
|
|
||||||
from datetime import datetime
|
|
||||||
from oliver_screen import settings
|
|
||||||
|
|
||||||
network = pylast.LastFMNetwork(api_key = settings.LASTFM_API_KEY, api_secret = settings.LASTFM_API_SECRET)
|
|
||||||
|
|
||||||
def get_lastfmuser():
|
|
||||||
lastfmusers = LastFMUser.objects.filter(active=True)
|
|
||||||
if len(lastfmusers) != 1:
|
|
||||||
# default
|
|
||||||
return network.get_user('kakdns')
|
|
||||||
|
|
||||||
return network.get_user(lastfmusers[0].name)
|
|
||||||
|
|
||||||
def get_youtubevideo(artist, title):
|
|
||||||
videos = YouTubeVideo.objects.filter(artist=artist, title=title)
|
|
||||||
if len(videos) != 1:
|
|
||||||
# should only be one
|
|
||||||
return ""
|
|
||||||
return videos[0]
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# My views
|
|
||||||
def get_last_track(request):
|
|
||||||
user = get_lastfmuser()
|
|
||||||
playedtracks = user.get_recent_tracks(limit=2)
|
|
||||||
playback_date = datetime.strptime(playedtracks[0].playback_date, "%d %b %Y, %H:%M")
|
|
||||||
played = {'artist': playedtracks[0].track.get_artist().get_name(),
|
|
||||||
'title': playedtracks[0].track.get_title(),
|
|
||||||
'playback_date': playback_date,
|
|
||||||
# provide utcnow since lastfm servers are UTC
|
|
||||||
'utcnow': datetime.utcnow()
|
|
||||||
}
|
|
||||||
return render_to_response("public/tracks.html", {'played':played});
|
|
||||||
|
|
||||||
def get_now_playing(request):
|
|
||||||
user = get_lastfmuser()
|
|
||||||
track = user.get_now_playing()
|
|
||||||
now_playing = []
|
|
||||||
if not track is None:
|
|
||||||
artist = track.get_artist()
|
|
||||||
video = get_youtubevideo(artist.get_name(), track.get_title())
|
|
||||||
image = artist.get_cover_image(size=4)
|
|
||||||
|
|
||||||
if "The Shins" in artist.get_name():
|
|
||||||
image = 'http://nikolark.at.neuf.no/the_shins.jpg'
|
|
||||||
|
|
||||||
now_playing = {
|
|
||||||
'artist': artist.get_name(),
|
|
||||||
'title': track.get_title(),
|
|
||||||
'image': image,
|
|
||||||
'video': video
|
|
||||||
}
|
|
||||||
cache_current(now_playing)
|
|
||||||
else:
|
|
||||||
# No response from LastFM db?
|
|
||||||
now_playing = get_current_from_cache()
|
|
||||||
|
|
||||||
return render_to_response("public/now_playing.html", {'now_playing':now_playing}, context_instance=RequestContext(request));
|
|
||||||
|
|
||||||
def cache_current(now_playing):
|
|
||||||
# Fetch the one CurrentTrack entry in the db and update it with the current track.
|
|
||||||
current = []
|
|
||||||
try:
|
|
||||||
current = CurrentTrack.objects.get(pk=1)
|
|
||||||
except:
|
|
||||||
#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 get_current_from_cache():
|
|
||||||
current = []
|
|
||||||
try:
|
|
||||||
current = CurrentTrack.objects.get(pk=1)
|
|
||||||
except:
|
|
||||||
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 = current.retries + 1
|
|
||||||
current.save()
|
|
||||||
else:
|
|
||||||
current.artist = ""
|
|
||||||
current.title = ""
|
|
||||||
current.image = ""
|
|
||||||
current.save()
|
|
||||||
|
|
||||||
return now_playing
|
|
||||||
|
|
||||||
# Mock views
|
|
||||||
def dummy_get_last_track(request):
|
|
||||||
played = {'artist': 'The Album Leaf', 'title': 'Another Day (Revised)'}
|
|
||||||
|
|
||||||
return render_to_response("public/tracks.html", {'played':played});
|
|
||||||
|
|
||||||
def dummy_now_playing(request):
|
|
||||||
now_playing = { 'artist':'The Album Leaf', 'title': 'Over The Pond', 'image': 'http://userserve-ak.last.fm/serve/_/2857325/The+Album+Leaf+1155442304.jpg'}
|
|
||||||
|
|
||||||
return render_to_response("public/now_playing.html", {'now_playing':now_playing});
|
|
||||||
+6
-18
@@ -1,19 +1,7 @@
|
|||||||
from django.conf.urls.defaults import *
|
from django.conf.urls import patterns, url
|
||||||
|
|
||||||
# Uncomment the next two lines to enable the admin:
|
urlpatterns = patterns(
|
||||||
from django.contrib import admin
|
'oliver_screen.views',
|
||||||
admin.autodiscover()
|
url(r'^last/$', 'get_last_track', name='last-track'),
|
||||||
from os.path import dirname, join
|
url(r'^now_playing/$', 'get_now_playing', name='now-playing'),
|
||||||
|
)
|
||||||
def map_path(target_name):
|
|
||||||
'''Enables path names to be decided at runtime.'''
|
|
||||||
return join(dirname(__file__), target_name).replace('\\', '/')
|
|
||||||
|
|
||||||
urlpatterns = patterns('',
|
|
||||||
# static file serving for development (http://docs.djangoproject.com/en/dev/howto/static-files/)
|
|
||||||
(r'^static/(?P<path>.*)$', 'django.views.static.serve',
|
|
||||||
{'document_root': map_path('static')}),
|
|
||||||
(r'^admin/', include(admin.site.urls)),
|
|
||||||
(r'^tracks/', include('oliver_screen.tracks.urls')),
|
|
||||||
(r'^$', include('oliver_screen.main.urls')),
|
|
||||||
)
|
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
import pylast
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
|
from oliver_screen.models import CurrentTrack, LastFMUser, YouTubeVideo
|
||||||
|
|
||||||
|
|
||||||
|
def get_lastfmuser():
|
||||||
|
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)
|
||||||
|
|
||||||
|
|
||||||
|
def get_youtubevideo(artist, title):
|
||||||
|
videos = YouTubeVideo.objects.filter(artist=artist, title=title)
|
||||||
|
if len(videos) != 1:
|
||||||
|
# should only be one
|
||||||
|
return ""
|
||||||
|
|
||||||
|
return videos[0]
|
||||||
|
|
||||||
|
|
||||||
|
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:
|
||||||
|
# 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 get_current_from_cache():
|
||||||
|
try:
|
||||||
|
current = CurrentTrack.objects.get(pk=1)
|
||||||
|
except:
|
||||||
|
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
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
from datetime import datetime
|
||||||
|
from django.shortcuts import render
|
||||||
|
|
||||||
|
from oliver_screen import utils
|
||||||
|
|
||||||
|
|
||||||
|
def index(request):
|
||||||
|
return render(request, 'public/index.html')
|
||||||
|
|
||||||
|
|
||||||
|
def get_last_track(request):
|
||||||
|
user = utils.get_lastfmuser()
|
||||||
|
playedtracks = user.get_recent_tracks(limit=2)
|
||||||
|
playback_date = datetime.strptime(playedtracks[0].playback_date, "%d %b %Y, %H:%M")
|
||||||
|
played = {
|
||||||
|
'artist': playedtracks[0].track.get_artist().get_name(),
|
||||||
|
'title': playedtracks[0].track.get_title(),
|
||||||
|
'playback_date': playback_date,
|
||||||
|
'utcnow': datetime.utcnow() # provide utcnow since lastfm servers are UTC
|
||||||
|
}
|
||||||
|
return render(request, "public/tracks.html", {'played': played})
|
||||||
|
|
||||||
|
|
||||||
|
def get_now_playing(request):
|
||||||
|
user = utils.get_lastfmuser()
|
||||||
|
track = user.get_now_playing()
|
||||||
|
if track is not None:
|
||||||
|
artist = track.get_artist()
|
||||||
|
video = utils.get_youtubevideo(artist.get_name(), track.get_title())
|
||||||
|
image = artist.get_cover_image(size=4)
|
||||||
|
|
||||||
|
if "The Shins" in artist.get_name():
|
||||||
|
image = 'http://nikolark.at.neuf.no/the_shins.jpg'
|
||||||
|
|
||||||
|
now_playing = {
|
||||||
|
'artist': artist.get_name(),
|
||||||
|
'title': track.get_title(),
|
||||||
|
'image': image,
|
||||||
|
'video': video
|
||||||
|
}
|
||||||
|
utils.cache_current(now_playing)
|
||||||
|
else:
|
||||||
|
# No response from LastFM db?
|
||||||
|
now_playing = utils.get_current_from_cache()
|
||||||
|
|
||||||
|
return render(request, "public/now_playing.html", {'now_playing': now_playing})
|
||||||
|
|
||||||
|
|
||||||
|
# Mock views
|
||||||
|
def dummy_get_last_track(request):
|
||||||
|
played = {'artist': 'The Album Leaf', 'title': 'Another Day (Revised)'}
|
||||||
|
|
||||||
|
return render(request, "public/tracks.html", {'played': played})
|
||||||
|
|
||||||
|
|
||||||
|
def dummy_now_playing(request):
|
||||||
|
now_playing = {
|
||||||
|
'artist': 'The Album Leaf',
|
||||||
|
'title': 'Over The Pond',
|
||||||
|
'image': 'http://userserve-ak.last.fm/serve/_/2857325/The+Album+Leaf+1155442304.jpg'
|
||||||
|
}
|
||||||
|
|
||||||
|
return render(request, "public/now_playing.html", {'now_playing': now_playing})
|
||||||
File renamed without changes.
@@ -0,0 +1,98 @@
|
|||||||
|
"""
|
||||||
|
Django settings for oliversite project.
|
||||||
|
|
||||||
|
For more information on this file, see
|
||||||
|
https://docs.djangoproject.com/en/1.7/topics/settings/
|
||||||
|
|
||||||
|
For the full list of settings and their values, see
|
||||||
|
https://docs.djangoproject.com/en/1.7/ref/settings/
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
||||||
|
import os
|
||||||
|
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/
|
||||||
|
|
||||||
|
# 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'
|
||||||
|
|
||||||
|
# SECURITY WARNING: don't run with debug turned on in production!
|
||||||
|
DEBUG = True
|
||||||
|
|
||||||
|
TEMPLATE_DEBUG = True
|
||||||
|
|
||||||
|
ALLOWED_HOSTS = []
|
||||||
|
|
||||||
|
|
||||||
|
# Application definition
|
||||||
|
|
||||||
|
INSTALLED_APPS = (
|
||||||
|
'django.contrib.admin',
|
||||||
|
'django.contrib.auth',
|
||||||
|
'django.contrib.contenttypes',
|
||||||
|
'django.contrib.sessions',
|
||||||
|
'django.contrib.messages',
|
||||||
|
'django.contrib.staticfiles',
|
||||||
|
)
|
||||||
|
|
||||||
|
INSTALLED_APPS += (
|
||||||
|
'oliver_screen',
|
||||||
|
)
|
||||||
|
|
||||||
|
MIDDLEWARE_CLASSES = (
|
||||||
|
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||||
|
'django.middleware.common.CommonMiddleware',
|
||||||
|
'django.middleware.csrf.CsrfViewMiddleware',
|
||||||
|
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||||
|
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
|
||||||
|
'django.contrib.messages.middleware.MessageMiddleware',
|
||||||
|
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
||||||
|
)
|
||||||
|
|
||||||
|
ROOT_URLCONF = 'oliversite.urls'
|
||||||
|
|
||||||
|
WSGI_APPLICATION = 'oliversite.wsgi.application'
|
||||||
|
|
||||||
|
|
||||||
|
# Database
|
||||||
|
# https://docs.djangoproject.com/en/1.7/ref/settings/#databases
|
||||||
|
|
||||||
|
DATABASES = {
|
||||||
|
'default': {
|
||||||
|
'ENGINE': 'django.db.backends.sqlite3',
|
||||||
|
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Internationalization
|
||||||
|
# https://docs.djangoproject.com/en/1.7/topics/i18n/
|
||||||
|
|
||||||
|
LANGUAGE_CODE = 'en-us'
|
||||||
|
|
||||||
|
TIME_ZONE = 'Europe/Oslo'
|
||||||
|
|
||||||
|
USE_I18N = True
|
||||||
|
|
||||||
|
USE_L10N = True
|
||||||
|
|
||||||
|
USE_TZ = True
|
||||||
|
|
||||||
|
|
||||||
|
# Static files (CSS, JavaScript, Images)
|
||||||
|
# https://docs.djangoproject.com/en/1.7/howto/static-files/
|
||||||
|
|
||||||
|
STATIC_URL = '/static/'
|
||||||
|
|
||||||
|
LASTFM_DEFAULT_USERNAME = 'kakdns'
|
||||||
|
# Get these from http://www.last.fm/api/account
|
||||||
|
LASTFM_API_KEY = ''
|
||||||
|
LASTFM_API_SECRET = ''
|
||||||
|
|
||||||
|
# Local settings
|
||||||
|
try:
|
||||||
|
from local_settings import *
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
from django.conf.urls import patterns, include, url
|
||||||
|
from django.contrib import admin
|
||||||
|
|
||||||
|
urlpatterns = patterns(
|
||||||
|
'',
|
||||||
|
url(r'^$', 'oliver_screen.views.index', name='index'),
|
||||||
|
url(r'', include('oliver_screen.urls')),
|
||||||
|
url(r'^admin/', include(admin.site.urls)),
|
||||||
|
)
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
"""
|
||||||
|
WSGI config for oliversite project.
|
||||||
|
|
||||||
|
It exposes the WSGI callable as a module-level variable named ``application``.
|
||||||
|
|
||||||
|
For more information on this file, see
|
||||||
|
https://docs.djangoproject.com/en/1.7/howto/deployment/wsgi/
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "oliversite.settings")
|
||||||
|
|
||||||
|
from django.core.wsgi import get_wsgi_application
|
||||||
|
application = get_wsgi_application()
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
Django==1.7.4
|
||||||
|
pylast==1.1.0
|
||||||
|
|
||||||
Reference in new issue
Block a user