serve itunes library directly and import js frontend
This commit is contained in:
parent
56d92d1d3d
commit
866174e47e
4 changed files with 281 additions and 19 deletions
|
@ -155,6 +155,10 @@ class Server(Resource):
|
||||||
return f
|
return f
|
||||||
if request.path == '/api/':
|
if request.path == '/api/':
|
||||||
return self
|
return self
|
||||||
|
if request.path == '/library.xml':
|
||||||
|
f = File(self.backend.xml)
|
||||||
|
f.isLeaf = True
|
||||||
|
return f
|
||||||
if request.path.startswith('/track/'):
|
if request.path.startswith('/track/'):
|
||||||
track_id = request.path.split('/')[-1].split('.')[0]
|
track_id = request.path.split('/')[-1].split('.')[0]
|
||||||
track = self.backend.library['Tracks'].get(track_id)
|
track = self.backend.library['Tracks'].get(track_id)
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<title>0xcd</title>
|
<title>0xcd</title>
|
||||||
<link rel="shortcut icon" type="image/png" href="/png/icon16.png"/>
|
<link rel="shortcut icon" type="image/png" href="/png/icon16.png"/>
|
||||||
<script type="text/javascript" src="/oxjs/build/Ox.js"></script>
|
<script type="text/javascript" src="/oxjs/build/Ox.js"></script>
|
||||||
<script type="text/javascript" src="/js/site.js"></script>
|
<script type="text/javascript" src="/js/index.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
</body>
|
</body>
|
||||||
|
|
276
oxcd/static/js/index.js
Normal file
276
oxcd/static/js/index.js
Normal file
|
@ -0,0 +1,276 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
Ox.load('UI', function() {
|
||||||
|
var app = {
|
||||||
|
$ui: {},
|
||||||
|
data: {},
|
||||||
|
site: {
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
format: function(value) {
|
||||||
|
return value ? $('<img>').addClass('symbol').attr({
|
||||||
|
src: Ox.UI.getImageURL('symbolMute')
|
||||||
|
}) : '';
|
||||||
|
},
|
||||||
|
id: 'playing',
|
||||||
|
operator: '-',
|
||||||
|
removable: false,
|
||||||
|
resizable: false,
|
||||||
|
title: 'Playing',
|
||||||
|
titleImage: 'mute',
|
||||||
|
visible: true,
|
||||||
|
width: 16
|
||||||
|
},
|
||||||
|
{
|
||||||
|
format: function(value) {
|
||||||
|
return value ? '' : $('<img>').addClass('symbol').attr({
|
||||||
|
src: Ox.UI.getImageURL('symbolCheck')
|
||||||
|
});
|
||||||
|
},
|
||||||
|
id: 'disabled',
|
||||||
|
operator: '+',
|
||||||
|
removable: false,
|
||||||
|
resizable: false,
|
||||||
|
title: 'Enabled',
|
||||||
|
titleImage: 'check',
|
||||||
|
visible: true,
|
||||||
|
width: 16
|
||||||
|
},
|
||||||
|
{
|
||||||
|
format: function(value) {
|
||||||
|
return app.utils.formatTitle(value);
|
||||||
|
},
|
||||||
|
id: 'name',
|
||||||
|
operator: '+',
|
||||||
|
removable: false,
|
||||||
|
title: 'Name',
|
||||||
|
visible: true,
|
||||||
|
width: 192
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'artist',
|
||||||
|
operator: '+',
|
||||||
|
sort: function(value, data) {
|
||||||
|
return data.albumArtist ? data.sortAlbumArtist || data.albumArtist
|
||||||
|
: data.compilation ? ''
|
||||||
|
: data.sortArtist || data.artist || '';
|
||||||
|
},
|
||||||
|
title: 'Artist',
|
||||||
|
visible: true,
|
||||||
|
width: 192
|
||||||
|
},
|
||||||
|
{
|
||||||
|
format: function(value) {
|
||||||
|
return app.utils.formatTitle(value);
|
||||||
|
},
|
||||||
|
id: 'album',
|
||||||
|
operator: '+',
|
||||||
|
title: 'Album',
|
||||||
|
visible: true,
|
||||||
|
width: 192
|
||||||
|
},
|
||||||
|
{
|
||||||
|
align: 'right',
|
||||||
|
id: 'year',
|
||||||
|
operator: '+',
|
||||||
|
title: 'Year',
|
||||||
|
visible: true,
|
||||||
|
width: 64
|
||||||
|
},
|
||||||
|
{
|
||||||
|
align: 'right',
|
||||||
|
format: function(value) {
|
||||||
|
return app.utils.formatTime(value);
|
||||||
|
},
|
||||||
|
id: 'totalTime',
|
||||||
|
operator: '-',
|
||||||
|
title: 'Time',
|
||||||
|
visible: true,
|
||||||
|
width: 64
|
||||||
|
},
|
||||||
|
{
|
||||||
|
align: 'right',
|
||||||
|
format: function(value) {
|
||||||
|
return Ox.formatValue(value, 'B');
|
||||||
|
},
|
||||||
|
id: 'size',
|
||||||
|
operator: '-',
|
||||||
|
title: 'Size',
|
||||||
|
visible: true,
|
||||||
|
width: 64,
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
user: {
|
||||||
|
library: '/library.xml',
|
||||||
|
sort: [
|
||||||
|
{key: 'artist', operator: '+'},
|
||||||
|
{key: 'year', operator: '+'},
|
||||||
|
{key: 'album', operator: '+'},
|
||||||
|
{key: 'discNumber', operator: '+'},
|
||||||
|
{key: 'trackNumber', operator: '+'}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
ui: {},
|
||||||
|
utils: {}
|
||||||
|
};
|
||||||
|
app.load = function() {
|
||||||
|
app.$ui.appPanel = app.ui.appPanel().appendTo(Ox.$body);
|
||||||
|
app.utils.parseLibrary(function(data) {
|
||||||
|
app.user.music = data;
|
||||||
|
app.loaded = true;
|
||||||
|
app.$ui.appPanel.replaceElement(1, app.$ui.list = app.ui.list());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
app.ui.appPanel = function() {
|
||||||
|
var $element = Ox.SplitPanel({
|
||||||
|
elements: [
|
||||||
|
{element: app.$ui.toolbar = app.ui.toolbar(), size: 24},
|
||||||
|
{element: app.$ui.list = app.ui.list()},
|
||||||
|
{element: app.$ui.statusbar = app.ui.statusbar(), size: 24}
|
||||||
|
],
|
||||||
|
orientation: 'vertical'
|
||||||
|
});
|
||||||
|
return $element;
|
||||||
|
};
|
||||||
|
app.ui.toolbar = function() {
|
||||||
|
var $element = Ox.Bar({size: 24});
|
||||||
|
return $element;
|
||||||
|
};
|
||||||
|
app.ui.list = function() {
|
||||||
|
var $element = !app.loaded ? Ox.Element() : Ox.TableList({
|
||||||
|
columns: app.site.columns,
|
||||||
|
columnsRemovable: true,
|
||||||
|
columnsVisible: true,
|
||||||
|
items: app.user.music.tracks,
|
||||||
|
keys: ['albumArtist', 'compilation', 'sortAlbumArtist', 'sortArtist'],
|
||||||
|
/*
|
||||||
|
query: {
|
||||||
|
conditions: [
|
||||||
|
{key: 'artist', operator: '==', value: 'Mary Lou Lord'},
|
||||||
|
{key: 'artist', operator: '==', value: 'Liz Phair'}
|
||||||
|
],
|
||||||
|
operator: '|'
|
||||||
|
},
|
||||||
|
*/
|
||||||
|
scrollbarVisible: true,
|
||||||
|
sort: app.user.sort,
|
||||||
|
sums: ['size', 'totalTime'],
|
||||||
|
unique: 'trackID'
|
||||||
|
})
|
||||||
|
.bindEvent({
|
||||||
|
init: function(data) {
|
||||||
|
app.$ui.statusbar.update(data);
|
||||||
|
},
|
||||||
|
open: function(data) {
|
||||||
|
app.utils.play(data.ids[0]);
|
||||||
|
},
|
||||||
|
openpreview: function(data) {
|
||||||
|
$element.closePreview();
|
||||||
|
app.utils.play(data.ids[0]);
|
||||||
|
},
|
||||||
|
select: function(data) {
|
||||||
|
app.$ui.statusbar.update(data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return $element;
|
||||||
|
};
|
||||||
|
app.ui.statusbar = function() {
|
||||||
|
var $status = $('<div>').attr({id: 'status'}),
|
||||||
|
$element = Ox.Bar({size: 24})
|
||||||
|
.append($status);
|
||||||
|
$element.update = function(data) {
|
||||||
|
var items;
|
||||||
|
if (data) {
|
||||||
|
if (data.items) {
|
||||||
|
app.data.status = data;
|
||||||
|
} else if (data.ids && data.ids.length > 1) {
|
||||||
|
var items = app.user.music.tracks.filter(function(track) {
|
||||||
|
return Ox.contains(data.ids, track.trackID);
|
||||||
|
});
|
||||||
|
data.selected = data.ids.length;
|
||||||
|
['size', 'totalTime'].forEach(function(key) {
|
||||||
|
data[key] = items.reduce(function(p, c) {
|
||||||
|
return p + c[key];
|
||||||
|
}, 0);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$status.html(
|
||||||
|
data ? (data.selected ? data.selected + ' of ' : '')
|
||||||
|
+ Ox.formatNumber(app.data.status.items) + ' item'
|
||||||
|
+ (app.data.status.items == 1 ? '' : 's') + ', '
|
||||||
|
+ app.utils.formatTime(data.totalTime || app.data.status.totalTime) + ' total time, '
|
||||||
|
+ Ox.formatValue(data.size || app.data.status.size, 'B')
|
||||||
|
: 'Loading...'
|
||||||
|
);
|
||||||
|
};
|
||||||
|
$element.update();
|
||||||
|
return $element;
|
||||||
|
};
|
||||||
|
app.utils.formatTime = function(duration) {
|
||||||
|
return Ox.formatDuration(duration / 1000).replace(/^00:/, '').replace(/^0/, '');
|
||||||
|
};
|
||||||
|
app.utils.formatTitle = function(title) {
|
||||||
|
return title.replace(/\[(.+)\]$/, '<span class="OxLight">($1)</span>');
|
||||||
|
};
|
||||||
|
app.utils.parseKey = function(key) {
|
||||||
|
return key[0].toLowerCase() + key.substr(1).replace(/ /g, '');
|
||||||
|
};
|
||||||
|
app.utils.parseLibrary = function(callback) {
|
||||||
|
Ox.get(app.user.library, function(xml) {
|
||||||
|
var data = {playlists: [], tracks: []},
|
||||||
|
library = app.utils.parseXML($(xml).children()[0]);
|
||||||
|
Ox.forEach(library.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);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
callback(data);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
app.utils.parseXML = function(xml) {
|
||||||
|
var type = xml.nodeName.toLowerCase(), value;
|
||||||
|
if (type == 'array') {
|
||||||
|
value = [];
|
||||||
|
$(xml).children().each(function(k, v) {
|
||||||
|
value.push(app.utils.parseXML(v));
|
||||||
|
});
|
||||||
|
} else if (type == 'data') {
|
||||||
|
value = xml.innerHTML.replace(/(\n|\t)/g, '');
|
||||||
|
} else if (type == 'date') {
|
||||||
|
value = xml.innerHTML;
|
||||||
|
} else if (type == 'dict') {
|
||||||
|
value = {};
|
||||||
|
$(xml).children('key').each(function(k, v) {
|
||||||
|
value[app.utils.parseKey(v.innerHTML)] = app.utils.parseXML($(v).next()[0]);
|
||||||
|
});
|
||||||
|
} else if (type == 'false') {
|
||||||
|
value = false;
|
||||||
|
} else if (type == 'integer') {
|
||||||
|
value = parseInt(xml.innerHTML);
|
||||||
|
} else if (type == 'string') {
|
||||||
|
value = xml.innerHTML;
|
||||||
|
} else if (type == 'true') {
|
||||||
|
value = true;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
};
|
||||||
|
app.utils.play = function(id) {
|
||||||
|
if (app.user.playing) {
|
||||||
|
app.$ui.list.value(app.user.playing, 'playing', false);
|
||||||
|
}
|
||||||
|
if (id != app.user.playing) {
|
||||||
|
app.user.playing = id;
|
||||||
|
app.$ui.list.value(app.user.playing, 'playing', true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
app.load();
|
||||||
|
});
|
|
@ -1,18 +0,0 @@
|
||||||
Ox.load('UI', function() {
|
|
||||||
window.oxcd = Ox.App({
|
|
||||||
name: 'oxcd',
|
|
||||||
url: '/api/'
|
|
||||||
}).bindEvent({
|
|
||||||
load: function(data) {
|
|
||||||
oxcd.api.library(function(result) {
|
|
||||||
var items = Ox.values(result.data.Tracks),
|
|
||||||
element = Ox.Element();
|
|
||||||
items.forEach(function(item) {
|
|
||||||
element.append($('<div>').html('<a href="/track/'+item['Track ID']+'.mp3">'+item['Track ID'] + ': '+item.Name+'</a>'))
|
|
||||||
console.log('<a href="/track/'+item['Track ID']+'.mp3">'+item['Track ID'] + ':'+item.Name+'</a>');
|
|
||||||
});
|
|
||||||
Ox.UI.$body.append(element);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
Loading…
Add table
Reference in a new issue