add rhythmbox backend

This commit is contained in:
j 2012-09-08 19:37:51 +02:00
parent 1f2dd79517
commit 304675110a
6 changed files with 129 additions and 45 deletions

View File

@ -11,14 +11,24 @@ if os.path.exists(os.path.join(root, 'oxcd')):
sys.path.insert(0, root)
import oxcd
import oxcd.itunes
import oxcd.rhythmbox
if __name__ == '__main__':
parser = OptionParser()
parser.add_option('-p', '--port', dest='port', help='port', default=2681)
parser.add_option('-i', '--itunes', dest='itunes', help='iTunes xml', default=oxcd.itunes_path())
parser.add_option('-i', '--itunes', dest='itunes', help='iTunes xml', default=oxcd.itunes.path())
parser.add_option('-r', '--rhythmbox', dest='rhythmbox', help='Rhythmbox xml', default=oxcd.rhythmbox.path())
(opts, args) = parser.parse_args()
if None in (opts.port, opts.itunes):
print (opts.port, )
print not filter(None, (opts.itunes, opts.rhythmbox))
if None in (opts.port, ) or not filter(None, (opts.itunes, opts.rhythmbox)):
parser.print_help()
sys.exit()
oxcd.main(opts.port, opts.itunes)
if opts.itunes:
backend = oxcd.itunes.iTunes(opts.itunes)
elif opts.rhythmbox:
backend = oxcd.rhythmbox.Rhythmbox(opts.rhythmbox)
oxcd.main(opts.port, backend)

View File

@ -13,19 +13,9 @@ import api
from version import __version__
def itunes_path():
if sys.platform == 'darwin':
path = os.path.expanduser('~/Music/iTunes/iTunes Music Library.xml')
elif sys.platform == 'win32':
path = os.path.expanduser('~\\Music\\iTunes\\iTunes Music Library.xml')
else:
path = None
return path
def main(port, itunes):
def main(port, backend):
base = os.path.abspath(os.path.dirname(__file__))
print 'loading', itunes
backend = iTunes(itunes)
print 'loading', backend
root = Server(base, backend)
site = Site(root)
reactor.listenTCP(port, site)

View File

@ -6,6 +6,7 @@ import os
import re
from urllib import unquote
from threading import Thread
import sys
from plistlib import readPlist
@ -15,6 +16,9 @@ class iTunes(object):
self.xml = xml
t = Thread(target=self.parse_xml, args=[])
t.start()
def __repr__(self):
return self.xml
def parse_xml(self):
self.library = readPlist(self.xml)
@ -37,20 +41,36 @@ class iTunes(object):
]
for t in self.library['Tracks']:
track = self.library['Tracks'][t]
item = {}
for key in keys:
item[key] = track.get({
'id': 'Track ID',
'duration': 'Total Time',
}.get(
key,
re.sub(
'^(.)',
lambda m: m.groups(0)[0].capitalize(),
re.sub('([A-Z])', ' \\1', key)
)
), None)
if item[key] == None:
del item[key]
tracks.append(item)
if track.get('kind') in ('MPEG audio file') and not track.get('podcast'):
item = {}
for key in keys:
item[key] = track.get({
'id': 'Track ID',
'duration': 'Total Time',
}.get(
key,
re.sub(
'^(.)',
lambda m: m.groups(0)[0].capitalize(),
re.sub('([A-Z])', ' \\1', key)
)
), None)
if key == 'duration' and item[key]:
item[key] = item[key] / 1000
if item[key] == None:
del item[key]
tracks.append(item)
return tracks
def track(self, track_id):
track = self.library['Tracks'].get(track_id)
return track and track['Location'] or None
def path():
if sys.platform == 'darwin':
path = os.path.expanduser('~/Music/iTunes/iTunes Music Library.xml')
elif sys.platform == 'win32':
path = os.path.expanduser('~\\Music\\iTunes\\iTunes Music Library.xml')
else:
path = None
return path

67
oxcd/rhythmbox.py Normal file
View File

@ -0,0 +1,67 @@
# encoding: utf-8
# vi:si:et:sw=4:sts=4:ts=4
from __future__ import with_statement, division
import os
import re
from urllib import unquote
from threading import Thread
import sys
import ox
class Rhythmbox(object):
tracks = []
locations = {}
def __init__(self, xml):
self.xml = os.path.expanduser(xml)
t = Thread(target=self.parse_xml, args=[])
t.start()
def __repr__(self):
return self.xml
def parse_xml(self):
from lxml import etree
with open(self.xml) as f:
self.library = etree.fromstring(f.read())
self.tracks = self.load_tracks()
def load_tracks(self):
tracks = []
keys = [
'id', 'name', 'artist', 'album', 'kind', 'year', 'duration', 'size',
'sortArtist', 'albumArtist', 'sortAlbumArtist', 'compliation',
]
key_map = {
'title': 'name',
'file-size': 'size',
}
for e in self.library.xpath('//entry[@type="song"]'):
item = {}
path = e.find('location').text.split('file://')[-1]
path = unquote(path)
item['id'] = ox.oshash(path)
self.locations[item['id']] = path
for c in e:
if c.tag in keys + key_map.keys():
key = key_map.get(c.tag, c.tag)
if key == 'duration':
item[key] = int(c.text)
else:
item[key] = c.text
info = ox.avinfo(path)
metadata = info.get('metadata', {})
if 'date' in metadata:
item['year'] = metadata['date']
tracks.append(item)
return tracks
def track(self, track_id):
return self.locations.get(track_id)
def path():
path = os.path.expanduser('~/.local/share/rhythmbox/rhythmdb.xml')
if not os.path.exists(path):
path = None
return path

View File

@ -168,9 +168,8 @@ class Server(Resource):
if request.path.startswith('/track/'):
track_id = request.path.split('/')[-1].split('.')[0]
track = self.backend.library['Tracks'].get(track_id)
if track:
path = track['Location']
path = self.backend.track(track_id)
if path:
if os.path.exists(path):
request.headers['Access-Control-Allow-Origin'] = '*'
f = File(path, 'audio/mpeg')

View File

@ -233,7 +233,7 @@ Ox.load('UI', function() {
return $element;
};
app.utils.formatTime = function(duration) {
return Ox.formatDuration(duration / 1000).replace(/^00:/, '').replace(/^0/, '');
return Ox.formatDuration(duration).replace(/^00:/, '').replace(/^0/, '');
};
app.utils.formatTitle = function(title) {
return title.replace(/\[(.+)\]$/, '<span class="OxLight">($1)</span>');
@ -245,16 +245,14 @@ Ox.load('UI', function() {
var data = {playlists: [], tracks: []};
oxcd.api.library(function(result) {
Ox.forEach(result.data.tracks, function(track) {
if (track.kind == 'MPEG audio file' && !track.podcast) {
app.site.columns.map(function(column) {
return column.id;
}).forEach(function(key) {
if (!track[key]) {
track[key] = '';
}
})
data.tracks.push(track);
}
app.site.columns.map(function(column) {
return column.id;
}).forEach(function(key) {
if (!track[key]) {
track[key] = '';
}
})
data.tracks.push(track);
});
callback(data);
});