mirror of
https://github.com/clinton-hall/nzbToMedia.git
synced 2025-08-14 02:26:53 -07:00
Move common libs to libs/common
This commit is contained in:
parent
8dbb1a2451
commit
1f4bd41bcc
1612 changed files with 962 additions and 10 deletions
314
libs/common/beetsplug/web/static/beets.js
Normal file
314
libs/common/beetsplug/web/static/beets.js
Normal file
|
@ -0,0 +1,314 @@
|
|||
// Format times as minutes and seconds.
|
||||
var timeFormat = function(secs) {
|
||||
if (secs == undefined || isNaN(secs)) {
|
||||
return '0:00';
|
||||
}
|
||||
secs = Math.round(secs);
|
||||
var mins = '' + Math.floor(secs / 60);
|
||||
secs = '' + (secs % 60);
|
||||
if (secs.length < 2) {
|
||||
secs = '0' + secs;
|
||||
}
|
||||
return mins + ':' + secs;
|
||||
}
|
||||
|
||||
// jQuery extension encapsulating event hookups for audio element controls.
|
||||
$.fn.player = function(debug) {
|
||||
// Selected element should contain an HTML5 Audio element.
|
||||
var audio = $('audio', this).get(0);
|
||||
|
||||
// Control elements that may be present, identified by class.
|
||||
var playBtn = $('.play', this);
|
||||
var pauseBtn = $('.pause', this);
|
||||
var disabledInd = $('.disabled', this);
|
||||
var timesEl = $('.times', this);
|
||||
var curTimeEl = $('.currentTime', this);
|
||||
var totalTimeEl = $('.totalTime', this);
|
||||
var sliderPlayedEl = $('.slider .played', this);
|
||||
var sliderLoadedEl = $('.slider .loaded', this);
|
||||
|
||||
// Button events.
|
||||
playBtn.click(function() {
|
||||
audio.play();
|
||||
});
|
||||
pauseBtn.click(function(ev) {
|
||||
audio.pause();
|
||||
});
|
||||
|
||||
// Utilities.
|
||||
var timePercent = function(cur, total) {
|
||||
if (cur == undefined || isNaN(cur) ||
|
||||
total == undefined || isNaN(total) || total == 0) {
|
||||
return 0;
|
||||
}
|
||||
var ratio = cur / total;
|
||||
if (ratio > 1.0) {
|
||||
ratio = 1.0;
|
||||
}
|
||||
return (Math.round(ratio * 10000) / 100) + '%';
|
||||
}
|
||||
|
||||
// Event helpers.
|
||||
var dbg = function(msg) {
|
||||
if (debug)
|
||||
console.log(msg);
|
||||
}
|
||||
var showState = function() {
|
||||
if (audio.duration == undefined || isNaN(audio.duration)) {
|
||||
playBtn.hide();
|
||||
pauseBtn.hide();
|
||||
disabledInd.show();
|
||||
timesEl.hide();
|
||||
} else if (audio.paused) {
|
||||
playBtn.show();
|
||||
pauseBtn.hide();
|
||||
disabledInd.hide();
|
||||
timesEl.show();
|
||||
} else {
|
||||
playBtn.hide();
|
||||
pauseBtn.show();
|
||||
disabledInd.hide();
|
||||
timesEl.show();
|
||||
}
|
||||
}
|
||||
var showTimes = function() {
|
||||
curTimeEl.text(timeFormat(audio.currentTime));
|
||||
totalTimeEl.text(timeFormat(audio.duration));
|
||||
|
||||
sliderPlayedEl.css('width',
|
||||
timePercent(audio.currentTime, audio.duration));
|
||||
|
||||
// last time buffered
|
||||
var bufferEnd = 0;
|
||||
for (var i = 0; i < audio.buffered.length; ++i) {
|
||||
if (audio.buffered.end(i) > bufferEnd)
|
||||
bufferEnd = audio.buffered.end(i);
|
||||
}
|
||||
sliderLoadedEl.css('width',
|
||||
timePercent(bufferEnd, audio.duration));
|
||||
}
|
||||
|
||||
// Initialize controls.
|
||||
showState();
|
||||
showTimes();
|
||||
|
||||
// Bind events.
|
||||
$('audio', this).bind({
|
||||
playing: function() {
|
||||
dbg('playing');
|
||||
showState();
|
||||
},
|
||||
pause: function() {
|
||||
dbg('pause');
|
||||
showState();
|
||||
},
|
||||
ended: function() {
|
||||
dbg('ended');
|
||||
showState();
|
||||
},
|
||||
progress: function() {
|
||||
dbg('progress ' + audio.buffered);
|
||||
},
|
||||
timeupdate: function() {
|
||||
dbg('timeupdate ' + audio.currentTime);
|
||||
showTimes();
|
||||
},
|
||||
durationchange: function() {
|
||||
dbg('durationchange ' + audio.duration);
|
||||
showState();
|
||||
showTimes();
|
||||
},
|
||||
loadeddata: function() {
|
||||
dbg('loadeddata');
|
||||
},
|
||||
loadedmetadata: function() {
|
||||
dbg('loadedmetadata');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Simple selection disable for jQuery.
|
||||
// Cut-and-paste from:
|
||||
// http://stackoverflow.com/questions/2700000
|
||||
$.fn.disableSelection = function() {
|
||||
$(this).attr('unselectable', 'on')
|
||||
.css('-moz-user-select', 'none')
|
||||
.each(function() {
|
||||
this.onselectstart = function() { return false; };
|
||||
});
|
||||
};
|
||||
|
||||
$(function() {
|
||||
|
||||
// Routes.
|
||||
var BeetsRouter = Backbone.Router.extend({
|
||||
routes: {
|
||||
"item/query/:query": "itemQuery",
|
||||
},
|
||||
itemQuery: function(query) {
|
||||
var queryURL = query.split(/\s+/).map(encodeURIComponent).join('/');
|
||||
$.getJSON('item/query/' + queryURL, function(data) {
|
||||
var models = _.map(
|
||||
data['results'],
|
||||
function(d) { return new Item(d); }
|
||||
);
|
||||
var results = new Items(models);
|
||||
app.showItems(results);
|
||||
});
|
||||
}
|
||||
});
|
||||
var router = new BeetsRouter();
|
||||
|
||||
// Model.
|
||||
var Item = Backbone.Model.extend({
|
||||
urlRoot: 'item'
|
||||
});
|
||||
var Items = Backbone.Collection.extend({
|
||||
model: Item
|
||||
});
|
||||
|
||||
// Item views.
|
||||
var ItemEntryView = Backbone.View.extend({
|
||||
tagName: "li",
|
||||
template: _.template($('#item-entry-template').html()),
|
||||
events: {
|
||||
'click': 'select',
|
||||
'dblclick': 'play'
|
||||
},
|
||||
initialize: function() {
|
||||
this.playing = false;
|
||||
},
|
||||
render: function() {
|
||||
$(this.el).html(this.template(this.model.toJSON()));
|
||||
this.setPlaying(this.playing);
|
||||
return this;
|
||||
},
|
||||
select: function() {
|
||||
app.selectItem(this);
|
||||
},
|
||||
play: function() {
|
||||
app.playItem(this.model);
|
||||
},
|
||||
setPlaying: function(val) {
|
||||
this.playing = val;
|
||||
if (val)
|
||||
this.$('.playing').show();
|
||||
else
|
||||
this.$('.playing').hide();
|
||||
}
|
||||
});
|
||||
//Holds Title, Artist, Album etc.
|
||||
var ItemMainDetailView = Backbone.View.extend({
|
||||
tagName: "div",
|
||||
template: _.template($('#item-main-detail-template').html()),
|
||||
events: {
|
||||
'click .play': 'play',
|
||||
},
|
||||
render: function() {
|
||||
$(this.el).html(this.template(this.model.toJSON()));
|
||||
return this;
|
||||
},
|
||||
play: function() {
|
||||
app.playItem(this.model);
|
||||
}
|
||||
});
|
||||
// Holds Track no., Format, MusicBrainz link, Lyrics, Comments etc.
|
||||
var ItemExtraDetailView = Backbone.View.extend({
|
||||
tagName: "div",
|
||||
template: _.template($('#item-extra-detail-template').html()),
|
||||
render: function() {
|
||||
$(this.el).html(this.template(this.model.toJSON()));
|
||||
return this;
|
||||
}
|
||||
});
|
||||
// Main app view.
|
||||
var AppView = Backbone.View.extend({
|
||||
el: $('body'),
|
||||
events: {
|
||||
'submit #queryForm': 'querySubmit',
|
||||
},
|
||||
querySubmit: function(ev) {
|
||||
ev.preventDefault();
|
||||
router.navigate('item/query/' + encodeURIComponent($('#query').val()), true);
|
||||
},
|
||||
initialize: function() {
|
||||
this.playingItem = null;
|
||||
this.shownItems = null;
|
||||
|
||||
// Not sure why these events won't bind automatically.
|
||||
this.$('audio').bind({
|
||||
'play': _.bind(this.audioPlay, this),
|
||||
'pause': _.bind(this.audioPause, this),
|
||||
'ended': _.bind(this.audioEnded, this)
|
||||
});
|
||||
},
|
||||
showItems: function(items) {
|
||||
this.shownItems = items;
|
||||
$('#results').empty();
|
||||
items.each(function(item) {
|
||||
var view = new ItemEntryView({model: item});
|
||||
item.entryView = view;
|
||||
$('#results').append(view.render().el);
|
||||
});
|
||||
},
|
||||
selectItem: function(view) {
|
||||
// Mark row as selected.
|
||||
$('#results li').removeClass("selected");
|
||||
$(view.el).addClass("selected");
|
||||
|
||||
// Show main and extra detail.
|
||||
var mainDetailView = new ItemMainDetailView({model: view.model});
|
||||
$('#main-detail').empty().append(mainDetailView.render().el);
|
||||
|
||||
var extraDetailView = new ItemExtraDetailView({model: view.model});
|
||||
$('#extra-detail').empty().append(extraDetailView.render().el);
|
||||
},
|
||||
playItem: function(item) {
|
||||
var url = 'item/' + item.get('id') + '/file';
|
||||
$('#player audio').attr('src', url);
|
||||
$('#player audio').get(0).play();
|
||||
|
||||
if (this.playingItem != null) {
|
||||
this.playingItem.entryView.setPlaying(false);
|
||||
}
|
||||
item.entryView.setPlaying(true);
|
||||
this.playingItem = item;
|
||||
},
|
||||
|
||||
audioPause: function() {
|
||||
this.playingItem.entryView.setPlaying(false);
|
||||
},
|
||||
audioPlay: function() {
|
||||
if (this.playingItem != null)
|
||||
this.playingItem.entryView.setPlaying(true);
|
||||
},
|
||||
audioEnded: function() {
|
||||
this.playingItem.entryView.setPlaying(false);
|
||||
|
||||
// Try to play the next track.
|
||||
var idx = this.shownItems.indexOf(this.playingItem);
|
||||
if (idx == -1) {
|
||||
// Not in current list.
|
||||
return;
|
||||
}
|
||||
var nextIdx = idx + 1;
|
||||
if (nextIdx >= this.shownItems.size()) {
|
||||
// End of list.
|
||||
return;
|
||||
}
|
||||
this.playItem(this.shownItems.at(nextIdx));
|
||||
}
|
||||
});
|
||||
var app = new AppView();
|
||||
|
||||
// App setup.
|
||||
Backbone.history.start({pushState: false});
|
||||
|
||||
// Disable selection on UI elements.
|
||||
$('#entities ul').disableSelection();
|
||||
$('#header').disableSelection();
|
||||
|
||||
// Audio player setup.
|
||||
$('#player').player();
|
||||
|
||||
});
|
Loading…
Add table
Add a link
Reference in a new issue