');
this.regionManager.addRegion(addonViewId, '#' + addonViewId);
return this[addonViewId].show(addonView);
};
List.ListSet = (function(_super1) {
__extends(ListSet, _super1);
function ListSet() {
return ListSet.__super__.constructor.apply(this, arguments);
}
ListSet.prototype.className = "search-set landing-set";
ListSet.prototype.initialize = function() {
this.setOptions();
return this.createModel();
};
ListSet.prototype.setOptions = function() {
if (this.options.more && this.options.query) {
return this.options.more = this.themeLink(t.gettext('Show more'), 'search/' + this.options.entity + '/' + this.options.query);
}
};
return ListSet;
})(App.Views.SetLayoutView);
return ListLayout;
})(App.Views.LayoutView);
return List.Sidebar = (function(_super) {
__extends(Sidebar, _super);
function Sidebar() {
return Sidebar.__super__.constructor.apply(this, arguments);
}
Sidebar.prototype.template = 'apps/search/list/search_sidebar';
Sidebar.prototype.className = "search-sidebar";
Sidebar.prototype.onRender = function() {
var $list, active, item, link, links, query, type, _ref, _results;
query = encodeURIComponent(this.options.query);
_ref = this.options.links;
_results = [];
for (type in _ref) {
links = _ref[type];
if (links.length === 0) {
_results.push($('.sidebar-section-' + type, this.$el).remove());
} else {
$list = $('.search-' + type + '-links', this.$el);
_results.push((function() {
var _i, _len, _results1;
_results1 = [];
for (_i = 0, _len = links.length; _i < _len; _i++) {
item = links[_i];
active = helpers.url.arg(1) === item.id ? 'active' : '';
link = this.themeLink(t.gettext(item.title), 'search/' + item.id + '/' + query, {
className: active
});
_results1.push($list.append(this.themeTag('li', {}, link)));
}
return _results1;
}).call(this));
}
}
return _results;
};
return Sidebar;
})(App.Views.LayoutView);
});
this.Kodi.module("SearchApp", function(SearchApp, App, Backbone, Marionette, $, _) {
var API;
SearchApp.Router = (function(_super) {
__extends(Router, _super);
function Router() {
return Router.__super__.constructor.apply(this, arguments);
}
Router.prototype.appRoutes = {
"search": "view",
"search/:media/:query": "list"
};
return Router;
})(App.Router.Base);
API = {
keyUpTimeout: 2000,
externalSearchUrls: {
google: 'https://www.google.com/webhp?#q=[QUERY]',
imdb: 'http://www.imdb.com/find?s=all&q=[QUERY]',
tmdb: 'https://www.themoviedb.org/search?query=[QUERY]',
tvdb: 'http://thetvdb.com/?searchseriesid=&tab=listseries&function=Search&string=[QUERY]',
soundcloud: 'https://soundcloud.com/search?q=[QUERY]',
youtube: 'https://www.youtube.com/results?search_query=[QUERY]'
},
list: function(media, query) {
App.navigate("search/" + media + "/" + query);
$('#search').val(query);
return new SearchApp.List.Controller({
query: query,
media: media
});
},
view: function() {
return new SearchApp.Show.Controller();
},
searchBind: function() {
return $('#search').on('keyup', function(e) {
var media, val;
$('#search-region').removeClass('pre-search');
val = $('#search').val();
media = helpers.url.arg(0) === 'search' ? helpers.url.arg(1) : 'all';
clearTimeout(App.searchAllTimeout);
if (e.which === 13) {
return API.list(media, val);
} else {
$('#search-region').addClass('pre-search');
return App.searchAllTimeout = setTimeout((function() {
$('#search-region').removeClass('pre-search');
return API.list(media, val);
}), API.keyUpTimeout);
}
});
}
};
App.commands.setHandler('search:go', function(type, query, provider) {
var url;
if (provider == null) {
provider = 'all';
}
if (type === 'internal') {
return App.navigate("search/" + provider + "/" + query, {
trigger: true
});
} else if (API.externalSearchUrls[provider]) {
url = API.externalSearchUrls[provider].replace('[QUERY]', encodeURIComponent(query));
return window.open(url);
}
});
App.on("before:start", function() {
return new SearchApp.Router({
controller: API
});
});
return App.addInitializer(function() {
return App.vent.on("shell:ready", function() {
return API.searchBind();
});
});
});
this.Kodi.module("SearchApp.Show", function(Show, App, Backbone, Marionette, $, _) {
return Show.Controller = (function(_super) {
__extends(Controller, _super);
function Controller() {
return Controller.__super__.constructor.apply(this, arguments);
}
Controller.prototype.initialize = function(options) {
this.landing = this.getLanding();
this.listenTo(this.landing, "show", (function(_this) {
return function() {
return $('#search').focus();
};
})(this));
return App.regionContent.show(this.landing);
};
Controller.prototype.getLanding = function() {
return new Show.Landing();
};
return Controller;
})(App.Controllers.Base);
});
this.Kodi.module("SearchApp.Show", function(Show, App, Backbone, Marionette, $, _) {
return Show.Landing = (function(_super) {
__extends(Landing, _super);
function Landing() {
return Landing.__super__.constructor.apply(this, arguments);
}
Landing.prototype.template = 'apps/search/show/landing';
return Landing;
})(App.Views.ItemView);
});
this.Kodi.module("Selected", function(Selected, App, Backbone, Marionette, $, _) {
Selected.List = (function(_super) {
__extends(List, _super);
function List() {
return List.__super__.constructor.apply(this, arguments);
}
List.prototype.items = [];
List.prototype.media = '';
List.prototype.type = '';
List.prototype.getItems = function() {
return this.items;
};
List.prototype.getCollection = function(callback) {
var collection, idProp, ids;
if (helpers.global.inArray(this.type, ['song', 'artist', 'album'])) {
ids = _.pluck(this.items, 'id');
idProp = this.type + 'id';
return App.request("song:custom:entities", idProp, ids, function(collection) {
return callback(collection);
});
} else {
collection = App.request(this.type + ":build:collection", this.items);
return callback(collection);
}
};
List.prototype.updateItems = function(op, model) {
this.items = _.filter(this.items, function(item) {
return item.uid !== model.uid;
});
if (op === 'add') {
this.items.push(model);
this.type = model.type;
this.media = helpers.global.inArray(this.type, ['song', 'album', 'artist']) ? 'audio' : 'video';
}
this.updateUi();
return this;
};
List.prototype.clearItems = function() {
this.items = [];
this.updateUi();
return this;
};
List.prototype.setMedia = function(media) {
this.media = media;
return this;
};
List.prototype.getType = function() {
return this.type;
};
List.prototype.getMedia = function() {
return this.media;
};
List.prototype.updateUi = function() {
var $selectedRegion, selectedText;
selectedText = this.items.length + ' ' + t.ngettext("item selected", "items selected", this.items.length);
$('#selected-count').html(selectedText);
$selectedRegion = $('#selected-region');
$selectedRegion.removeClassStartsWith('media-');
$selectedRegion.addClass('media-' + this.media);
if (this.items.length === 0) {
$selectedRegion.hide();
return $('.selected').removeClass('selected');
} else {
return $selectedRegion.show();
}
};
return List;
})(Marionette.Object);
App.addInitializer(function() {
return App.selected = new Selected.List;
});
App.reqres.setHandler("selected:get:items", function() {
return App.selected.getItems();
});
App.reqres.setHandler("selected:get:media", function() {
return App.selected.getMedia();
});
App.commands.setHandler("selected:update:items", function(op, model) {
return App.selected.updateItems(op, model);
});
App.commands.setHandler("selected:clear:items", function() {
return App.selected.clearItems();
});
App.commands.setHandler("selected:set:media", function(media) {
return App.selected.setMedia(media);
});
App.commands.setHandler("selected:action:play", function() {
return App.selected.getCollection(function(collection) {
var kodiPlaylist;
kodiPlaylist = App.request("command:kodi:controller", App.selected.getMedia(), 'PlayList');
kodiPlaylist.playCollection(collection);
return App.selected.clearItems();
});
});
App.commands.setHandler("selected:action:add", function() {
return App.selected.getCollection(function(collection) {
var kodiPlaylist;
kodiPlaylist = App.request("command:kodi:controller", App.selected.getMedia(), 'PlayList');
kodiPlaylist.addCollection(collection);
return App.selected.clearItems();
});
});
return App.commands.setHandler("selected:action:localadd", function() {
var idProp, ids, items;
items = App.selected.getItems();
ids = _.pluck(items, 'id');
idProp = App.selected.getType() + 'id';
App.execute("localplaylist:addentity", idProp, ids);
return App.selected.clearItems();
});
});
this.Kodi.module("SettingsApp", function(SettingsApp, App, Backbone, Marionette, $, _) {
var API;
SettingsApp.Router = (function(_super) {
__extends(Router, _super);
function Router() {
return Router.__super__.constructor.apply(this, arguments);
}
Router.prototype.appRoutes = {
"settings/web": "local",
"settings/kodi": "kodi",
"settings/kodi/:section": "kodi",
"settings/addons": "addons",
"settings/nav": "navMain",
"settings/search": "search"
};
return Router;
})(App.Router.Base);
API = {
subNavId: 'settings/web',
local: function() {
return new SettingsApp.Show.Local.Controller();
},
addons: function() {
return new SettingsApp.Show.Addons.Controller();
},
navMain: function() {
return new SettingsApp.Show.navMain.Controller();
},
search: function() {
return new SettingsApp.Show.Search.Controller();
},
kodi: function(section, category) {
return new SettingsApp.Show.Kodi.Controller({
section: section,
category: category
});
},
getSubNav: function() {
var collection, sidebarView;
collection = App.request("settings:kodi:entities", {
type: 'sections'
});
sidebarView = new SettingsApp.Show.Sidebar();
App.listenTo(sidebarView, "show", (function(_this) {
return function() {
var settingsNavView;
App.execute("when:entity:fetched", collection, function() {
var kodiSettingsView;
kodiSettingsView = App.request("navMain:collection:show", collection, t.gettext('Kodi settings'));
return sidebarView.regionKodiNav.show(kodiSettingsView);
});
settingsNavView = App.request("navMain:children:show", API.subNavId, 'General');
return sidebarView.regionLocalNav.show(settingsNavView);
};
})(this));
return sidebarView;
}
};
App.on("before:start", function() {
return new SettingsApp.Router({
controller: API
});
});
return App.reqres.setHandler('settings:subnav', function() {
return API.getSubNav();
});
});
this.Kodi.module("SettingsApp.Show.Base", function(SettingsBase, App, Backbone, Marionette, $, _) {
return SettingsBase.Controller = (function(_super) {
__extends(Controller, _super);
function Controller() {
return Controller.__super__.constructor.apply(this, arguments);
}
Controller.prototype.initialize = function() {
this.layout = this.getLayoutView();
this.listenTo(this.layout, "show", (function(_this) {
return function() {
_this.getSubNav();
return _this.getForm();
};
})(this));
return App.regionContent.show(this.layout);
};
Controller.prototype.getLayoutView = function() {
return new App.SettingsApp.Show.Layout();
};
Controller.prototype.getSubNav = function() {
var subNav;
subNav = App.request('settings:subnav');
return this.layout.regionSidebarFirst.show(subNav);
};
Controller.prototype.getForm = function() {
return this.getCollection((function(_this) {
return function(collection) {
var form, options;
options = {
form: _this.getStructure(collection),
formState: [],
config: {
attributes: {
"class": 'settings-form'
},
callback: function(formState, formView) {
return _this.saveCallback(formState, formView);
},
onShow: function() {
return _this.onReady();
}
}
};
form = App.request("form:wrapper", options);
return _this.layout.regionContent.show(form);
};
})(this));
};
Controller.prototype.getCollection = function(callback) {
var res;
res = {};
return callback(res);
};
Controller.prototype.getStructure = function(collection) {
return [];
};
Controller.prototype.saveCallback = function(formState, formView) {};
Controller.prototype.onReady = function() {
return this.layout;
};
return Controller;
})(App.Controllers.Base);
});
this.Kodi.module("SettingsApp.Show.Addons", function(Addons, App, Backbone, Marionette, $, _) {
return Addons.Controller = (function(_super) {
__extends(Controller, _super);
function Controller() {
return Controller.__super__.constructor.apply(this, arguments);
}
Controller.prototype.initialize = function() {
this.layout = this.getLayoutView();
this.listenTo(this.layout, "show", (function(_this) {
return function() {
_this.getSubNav();
return _this.getForm();
};
})(this));
return App.regionContent.show(this.layout);
};
Controller.prototype.getLayoutView = function() {
return new App.SettingsApp.Show.Layout();
};
Controller.prototype.getSubNav = function() {
var subNav;
subNav = App.request('settings:subnav');
return this.layout.regionSidebarFirst.show(subNav);
};
Controller.prototype.addonController = function() {
return App.request("command:kodi:controller", 'auto', 'AddOn');
};
Controller.prototype.getAllAddons = function(callback) {
return this.addonController().getAllAddons(callback);
};
Controller.prototype.getForm = function() {
return this.getAllAddons((function(_this) {
return function(addons) {
var form, options;
options = {
form: _this.getStructure(addons),
formState: [],
config: {
attributes: {
"class": 'settings-form'
},
callback: function(data, formView) {
return _this.saveCallback(data, formView);
}
}
};
form = App.request("form:wrapper", options);
return _this.layout.regionContent.show(form);
};
})(this));
};
Controller.prototype.getStructure = function(addons) {
var addon, el, elements, enabled, form, i, type, types;
form = [];
types = [];
for (i in addons) {
addon = addons[i];
types[addon.type] = true;
}
for (type in types) {
enabled = types[type];
elements = _.where(addons, {
type: type
});
for (i in elements) {
el = elements[i];
elements[i] = $.extend(el, {
id: el.addonid,
name: el.addonid,
type: 'checkbox',
defaultValue: el.enabled,
title: el.name
});
}
form.push({
title: type,
id: type,
children: elements
});
}
return form;
};
Controller.prototype.saveCallback = function(data, formView) {
var updating;
updating = [];
return this.getAllAddons(function(addons) {
var addon, addonid, commander, commands, key, val;
for (key in addons) {
addon = addons[key];
addonid = addon.addonid;
if (addon.enabled === !data[addonid]) {
updating[addonid] = data[addonid];
}
}
commander = App.request("command:kodi:controller", 'auto', 'Commander');
commands = [];
for (key in updating) {
val = updating[key];
commands.push({
method: 'Addons.SetAddonEnabled',
params: [key, val]
});
}
return commander.multipleCommands(commands, (function(_this) {
return function(resp) {
return Kodi.execute("notification:show", 'Toggled ' + commands.length + ' addons');
};
})(this));
});
};
return Controller;
})(App.Controllers.Base);
});
this.Kodi.module("SettingsApp.Show.Kodi", function(Kodi, App, Backbone, Marionette, $, _) {
return Kodi.Controller = (function(_super) {
var API;
__extends(Controller, _super);
function Controller() {
return Controller.__super__.constructor.apply(this, arguments);
}
API = {
optionLookups: {
'lookandfeel.skin': 'xbmc.gui.skin',
'locale.language': 'kodi.resource.language',
'screensaver.mode': 'xbmc.ui.screensaver',
'musiclibrary.albumsscraper': 'xbmc.metadata.scraper.albums',
'musiclibrary.artistsscraper': 'xbmc.metadata.scraper.artists',
'musicplayer.visualisation': 'xbmc.player.musicviz',
'services.webskin': 'xbmc.webinterface',
'subtitles.tv': 'xbmc.subtitle.module',
'subtitles.movie': 'xbmc.subtitle.module',
'audiocds.encoder': 'kodi.audioencoder'
},
actionLookups: {
"musiclibrary.cleanup": "command:kodi:audio:clean",
"videolibrary.cleanup": "command:kodi:video:clean"
},
parseOptions: function(options) {
var out;
out = {};
$(options).each(function(i, option) {
return out[option.value] = option.label;
});
return out;
},
labelRewrites: function(item) {
if (item.id.lastIndexOf('videolibrary', 0) === 0) {
item.title += ' (video)';
}
if (item.id.lastIndexOf('musiclibrary', 0) === 0) {
item.title += ' (music)';
}
return item;
}
};
Controller.prototype.initialize = function(options) {
this.layout = this.getLayoutView();
this.listenTo(this.layout, "show", (function(_this) {
return function() {
_this.getSubNav();
if (options.section) {
return _this.getSettingsForm(options.section);
}
};
})(this));
return App.regionContent.show(this.layout);
};
Controller.prototype.getLayoutView = function() {
return new App.SettingsApp.Show.Layout();
};
Controller.prototype.getSubNav = function() {
var subNav;
subNav = App.request('settings:subnav');
return this.layout.regionSidebarFirst.show(subNav);
};
Controller.prototype.getSettingsForm = function(section) {
var categoryCollection, formStructure;
formStructure = [];
categoryCollection = App.request("settings:kodi:entities", {
type: 'categories',
section: section
});
return App.execute("when:entity:fetched", categoryCollection, (function(_this) {
return function() {
var categories, categoryNames;
categoryNames = categoryCollection.pluck("id");
categories = categoryCollection.toJSON();
return App.request("settings:kodi:filtered:entities", {
type: 'settings',
section: section,
categories: categoryNames,
callback: function(categorySettings) {
$(categories).each(function(i, category) {
var items;
items = _this.mapSettingsToElements(categorySettings[category.id]);
if (items.length > 0) {
return formStructure.push({
title: category.title,
id: category.id,
children: items
});
}
});
return _this.getForm(section, formStructure);
}
});
};
})(this));
};
Controller.prototype.getForm = function(section, formStructure) {
var form, options;
options = {
form: formStructure,
config: {
attributes: {
"class": 'settings-form'
},
callback: (function(_this) {
return function(data, formView) {
return _this.saveCallback(data, formView);
};
})(this)
}
};
form = App.request("form:wrapper", options);
return this.layout.regionContent.show(form);
};
Controller.prototype.getAddonOptions = function(elId, value) {
var addon, addons, filteredAddons, i, lookup, mappedType, options;
mappedType = API.optionLookups[elId];
options = [];
lookup = {};
if (mappedType) {
addons = App.request('addon:enabled:addons');
filteredAddons = _.where(addons, {
type: mappedType
});
for (i in filteredAddons) {
addon = filteredAddons[i];
options.push({
value: addon.addonid,
label: addon.name
});
lookup[addon.addonid] = true;
}
if (!lookup[value]) {
options.push({
value: value,
label: value
});
}
return options;
}
return false;
};
Controller.prototype.mapSettingsToElements = function(items) {
var elements;
elements = [];
$(items).each((function(_this) {
return function(i, item) {
var options, type;
type = null;
switch (item.type) {
case 'boolean':
type = 'checkbox';
break;
case 'path':
type = 'textfield';
break;
case 'addon':
options = _this.getAddonOptions(item.id, item.value);
if (options) {
item.options = options;
} else {
type = 'textfield';
}
break;
case 'integer':
type = 'textfield';
break;
case 'string':
type = 'textfield';
break;
case 'action':
if (API.actionLookups[item.id]) {
type = 'button';
item.value = item.label;
item.trigger = API.actionLookups[item.id];
} else {
type = 'hide';
}
break;
default:
type = 'hide';
}
if (item.options) {
type = 'select';
item.options = API.parseOptions(item.options);
}
item = API.labelRewrites(item);
if (type === 'hide') {
return console.log('no setting to field mapping for: ' + item.type + ' -> ' + item.id);
} else {
item.type = type;
item.defaultValue = item.value;
return elements.push(item);
}
};
})(this));
return elements;
};
Controller.prototype.saveCallback = function(data, formView) {
return App.execute("settings:kodi:save:entities", data, (function(_this) {
return function(resp) {
App.execute("notification:show", t.gettext("Saved Kodi settings"));
App.vent.trigger("config:local:updated", {});
return App.vent.trigger("config:kodi:updated", data);
};
})(this));
};
return Controller;
})(App.Controllers.Base);
});
this.Kodi.module("SettingsApp.Show.Kodi", function(Kodi, App, Backbone, Marionette, $, _) {});
this.Kodi.module("SettingsApp.Show.Local", function(Local, App, Backbone, Marionette, $, _) {
return Local.Controller = (function(_super) {
__extends(Controller, _super);
function Controller() {
return Controller.__super__.constructor.apply(this, arguments);
}
Controller.prototype.initialize = function() {
this.layout = this.getLayoutView();
this.listenTo(this.layout, "show", (function(_this) {
return function() {
_this.getSubNav();
return _this.getForm();
};
})(this));
return App.regionContent.show(this.layout);
};
Controller.prototype.getLayoutView = function() {
return new App.SettingsApp.Show.Layout();
};
Controller.prototype.getSubNav = function() {
var subNav;
subNav = App.request('settings:subnav');
return this.layout.regionSidebarFirst.show(subNav);
};
Controller.prototype.getForm = function() {
var form, options;
options = {
form: this.getStructure(),
formState: this.getState(),
config: {
attributes: {
"class": 'settings-form'
},
callback: (function(_this) {
return function(data, formView) {
return _this.saveCallback(data, formView);
};
})(this)
}
};
form = App.request("form:wrapper", options);
return this.layout.regionContent.show(form);
};
Controller.prototype.getStructure = function() {
return [
{
title: 'General options',
id: 'general',
children: [
{
id: 'lang',
title: tr("Language"),
type: 'select',
options: helpers.translate.getLanguages(),
defaultValue: 'en',
description: tr('Preferred language, need to refresh browser to take effect')
}, {
id: 'defaultPlayer',
title: tr("Default player"),
type: 'select',
options: {
auto: 'Auto',
kodi: 'Kodi',
local: 'Local'
},
defaultValue: 'auto',
description: tr('Which player to start with')
}, {
id: 'keyboardControl',
title: tr("Keyboard controls"),
type: 'select',
options: {
kodi: 'Kodi',
local: 'Browser',
both: 'Both'
},
defaultValue: 'kodi',
description: tr('In Chorus, will you keyboard control Kodi, the browser or both') + '.
' + tr('Learn more') + ' '
}
]
}, {
title: 'List options',
id: 'list',
children: [
{
id: 'ignoreArticle',
title: tr("Ignore article"),
type: 'checkbox',
defaultValue: true,
description: tr("Ignore articles (terms such as 'The' and 'A') when sorting lists")
}, {
id: 'albumArtistsOnly',
title: tr("Album artists only"),
type: 'checkbox',
defaultValue: true,
description: tr('When listing artists should we only see artists with albums or all artists found. Warning: turning this off can impact performance with large libraries')
}, {
id: 'playlistFocusPlaying',
title: tr("Focus playlist on playing"),
type: 'checkbox',
defaultValue: true,
description: tr('Automatically scroll the playlist to the current playing item. This happens whenever the playing item is changed')
}
]
}, {
title: 'Appearance',
id: 'appearance',
children: [
{
id: 'vibrantHeaders',
title: tr("Vibrant headers"),
type: 'checkbox',
defaultValue: true,
description: tr("Use colourful headers for media pages")
}, {
id: 'disableThumbs',
title: tr("Disable Thumbs Up"),
type: 'checkbox',
defaultValue: false,
description: t.sprintf(tr("Remove the thumbs up button from media. Note: you may also want to remove the menu item from the %1$s"), '
' + tr('Main Nav') + ' ')
}, {
id: 'showDeviceName',
title: tr("Show device name"),
type: 'checkbox',
defaultValue: false,
description: tr("Show the Kodi device name in the header of Chorus")
}
]
}, {
title: 'Advanced options',
id: 'advanced',
children: [
{
id: 'socketsPort',
title: tr("Websockets port"),
type: 'textfield',
defaultValue: '9090',
description: "9090 " + tr("is the default")
}, {
id: 'socketsHost',
title: tr("Websockets host"),
type: 'textfield',
defaultValue: 'auto',
description: tr("The hostname used for websockets connection. Set to 'auto' to use the current hostname.")
}, {
id: 'pollInterval',
title: tr("Poll interval"),
type: 'select',
defaultValue: '10000',
options: {
'5000': "5 " + tr('sec'),
'10000': "10 " + tr('sec'),
'30000': "30 " + tr('sec'),
'60000': "60 " + tr('sec')
},
description: tr("How often do I poll for updates from Kodi (Only applies when websockets inactive)")
}, {
id: 'kodiSettingsLevel',
title: tr("Kodi settings level"),
type: 'select',
defaultValue: 'standard',
options: {
'standard': 'Standard',
'advanced': 'Advanced',
'expert': 'Expert'
},
description: tr('Advanced setting level is recommended for those who know what they are doing.')
}, {
id: 'reverseProxy',
title: tr("Reverse proxy support"),
type: 'checkbox',
defaultValue: false,
description: tr('Enable support for reverse proxying.')
}, {
id: 'refreshIgnoreNFO',
title: tr("Refresh Ignore NFO"),
type: 'checkbox',
defaultValue: true,
description: tr('Ignore local NFO files when manually refreshing media.')
}
]
}
];
};
Controller.prototype.getState = function() {
return config.get('app', 'config:local', config["static"]);
};
Controller.prototype.saveCallback = function(data, formView) {
config.set('app', 'config:local', data);
config["static"] = _.extend(config["static"], config.get('app', 'config:local', config["static"]));
Kodi.vent.trigger("config:local:updated", config["static"]);
return Kodi.execute("notification:show", tr("Web Settings saved."));
};
return Controller;
})(App.Controllers.Base);
});
this.Kodi.module("SettingsApp.Show.navMain", function(NavMain, App, Backbone, Marionette, $, _) {
return NavMain.Controller = (function(_super) {
__extends(Controller, _super);
function Controller() {
this.onReady = __bind(this.onReady, this);
return Controller.__super__.constructor.apply(this, arguments);
}
Controller.prototype.getCollection = function(callback) {
var collection;
collection = App.request('navMain:entities');
return $.getJSON('lib/icons/mdi.json', function(iconList) {
return callback({
collection: collection,
icons: iconList
});
});
};
Controller.prototype.getStructure = function(data) {
var defaults, form, i, iconLink, item, row, _ref;
this.data = data;
defaults = '
' + t.gettext('Click here restore defaults') + ' ';
iconLink = '
icons ';
form = [
{
title: t.gettext('Main Menu Structure'),
id: 'intro',
children: [
{
id: 'intro-text',
type: 'markup',
markup: t.sprintf(tr('Here you can change the title, url and %1$s for menu items. You can also remove, re-order and add new items.'), iconLink) + defaults
}
]
}
];
_ref = data.collection.getRawCollection();
for (i in _ref) {
item = _ref[i];
item.weight = i;
row = this.getRow(item, data.icons);
form.push(row);
}
form.push({
id: 'add-another',
"class": 'add-another-wrapper',
children: [
{
type: 'button',
value: 'Add another',
id: 'add-another'
}
]
});
return form;
};
Controller.prototype.saveCallback = function(formState, formView) {
var i, item, items, _ref;
items = [];
_ref = formState.title;
for (i in _ref) {
item = _ref[i];
items.push({
title: formState.title[i],
path: formState.path[i],
icon: formState.icon[i],
weight: formState.weight[i],
id: formState.id[i],
parent: 0
});
}
App.request("navMain:update:entities", items);
App.vent.trigger("navMain:refresh");
return Kodi.execute("notification:show", t.gettext('Menu updated'));
};
Controller.prototype.onReady = function() {
var $ctx, self;
self = this;
$ctx = this.layout.regionContent.$el;
$('.settings-form').addClass('settings-form-draggable');
this.binds();
$('#form-edit-add-another', $ctx).click(function(e) {
var blank, formView, row;
e.preventDefault();
blank = {
weight: $(".nav-item-row").length + 1,
title: '',
path: '',
icon: 'mdi-action-extension'
};
row = self.getRow(blank);
formView = App.request("form:render:items", [row]);
$(this).closest('.add-another-wrapper').before(formView.render().$el);
return self.binds();
});
if ($(window).width() > config.getLocal('largeBreakpoint')) {
$('.form-groups', $ctx).sortable({
draggable: ".draggable-row",
onEnd: function(e) {
return $('input[id^="form-edit-weight-"]', e.target).each(function(i, d) {
return $(d).attr('value', i);
});
}
});
}
return $('.nav-restore-defaults', $ctx).on("click", (function(_this) {
return function(e) {
e.preventDefault();
App.request("navMain:update:defaults");
_this.initialize();
return App.vent.trigger("navMain:refresh");
};
})(this));
};
Controller.prototype.binds = function() {
var $ctx;
$ctx = $('.settings-form');
$('select[id^="form-edit-icon"]', $ctx).once('icon-changer').on("change", function(e) {
return $(this).closest('.group-parent', $ctx).find('i').first().attr('class', $(this).val());
});
$('.remove-item', $ctx).on("click", function(e) {
return $(this).closest('.group-parent', $ctx).remove();
});
return $.material.init();
};
Controller.prototype.getRow = function(item) {
var i, icon, icons;
icons = this.data.icons;
i = item.weight;
icon = '
';
return {
id: 'item-' + item.weight,
"class": 'nav-item-row draggable-row',
children: [
{
id: 'title-' + i,
name: 'title[]',
type: 'textfield',
title: 'Title',
defaultValue: item.title
}, {
id: 'path-' + i,
name: 'path[]',
type: 'textfield',
title: 'Url',
defaultValue: item.path
}, {
id: 'icon-' + i,
name: 'icon[]',
type: 'select',
title: 'Icon' + icon,
defaultValue: item.icon,
options: icons
}, {
id: 'weight-' + i,
name: 'weight[]',
type: 'hidden',
title: '',
defaultValue: i
}, {
id: 'id-' + i,
name: 'id[]',
type: 'hidden',
title: '',
defaultValue: 1000 + i
}, {
id: 'remove-' + i,
type: 'markup',
markup: '
× '
}
]
};
};
return Controller;
})(App.SettingsApp.Show.Base.Controller);
});
this.Kodi.module("SettingsApp.Show.Search", function(Search, App, Backbone, Marionette, $, _) {
return Search.Controller = (function(_super) {
__extends(Controller, _super);
function Controller() {
this.onReady = __bind(this.onReady, this);
return Controller.__super__.constructor.apply(this, arguments);
}
Controller.prototype.getCollection = function(callback) {
this.collection = App.request('searchAddons:entities');
return callback(this.collection);
};
Controller.prototype.getStructure = function(data) {
var form, i, item, items, row;
this.data = data;
form = [
{
title: t.gettext('Custom Add-on search'),
id: 'intro',
children: [
{
id: 'intro-text',
type: 'markup',
markup: t.sprintf(tr("Add custom add-on searches"), '
' + tr('Add-ons help page') + ' ')
}
]
}
];
items = this.collection.toJSON();
if (items.length === 0) {
items.push(this.getBlank(items.length));
}
for (i in items) {
item = items[i];
item.weight = i;
row = this.getRow(item);
form.push(row);
}
form.push({
id: 'add-another',
"class": 'add-another-wrapper',
children: [
{
type: 'button',
value: 'Add another',
id: 'add-another'
}
]
});
return form;
};
Controller.prototype.saveCallback = function(formState, formView) {
var i, item, items, _ref;
items = [];
_ref = formState.title;
for (i in _ref) {
item = _ref[i];
items.push({
title: formState.title[i],
url: formState.url[i],
media: formState.media[i],
weight: formState.weight[i],
id: formState.id[i]
});
}
App.request("searchAddons:update:entities", items);
return Kodi.execute("notification:show", t.gettext('Custom Addon search updated'));
};
Controller.prototype.onReady = function() {
var $ctx, self;
self = this;
$ctx = this.layout.regionContent.$el;
$('.settings-form').addClass('settings-form-draggable');
this.binds();
if ($(window).width() > config.getLocal('largeBreakpoint')) {
$('.form-groups', $ctx).sortable({
draggable: ".draggable-row",
onEnd: function(e) {
return $('input[id^="form-edit-weight-"]', e.target).each(function(i, d) {
return $(d).attr('value', i);
});
}
});
}
$('#form-edit-add-another', $ctx).click(function(e) {
var blank, formView, row;
e.preventDefault();
blank = self.getBlank($(".item-row").length);
row = self.getRow(blank);
formView = App.request("form:render:items", [row]);
$(this).closest('.add-another-wrapper').before(formView.render().$el);
return self.binds();
});
return $('.restore-defaults', $ctx).on("click", (function(_this) {
return function(e) {};
})(this));
};
Controller.prototype.getBlank = function(weight) {
return {
weight: weight,
title: '',
url: '',
media: 'music'
};
};
Controller.prototype.binds = function() {
var $ctx;
$ctx = $('.settings-form');
$('.remove-item', $ctx).on("click", function(e) {
return $(this).closest('.group-parent', $ctx).remove();
});
return $.material.init();
};
Controller.prototype.getRow = function(item) {
var i;
i = item.weight;
return {
id: 'item-' + item.weight,
"class": 'item-row draggable-row',
children: [
{
id: 'title-' + i,
name: 'title[]',
type: 'textfield',
title: 'Title',
defaultValue: item.title
}, {
id: 'url-' + i,
name: 'url[]',
type: 'textfield',
title: 'Url',
defaultValue: item.url
}, {
id: 'media-' + i,
name: 'media[]',
type: 'select',
title: 'Media',
defaultValue: item.media,
options: {
music: 'Music',
video: 'Video'
}
}, {
id: 'weight-' + i,
name: 'weight[]',
type: 'hidden',
title: '',
defaultValue: i
}, {
id: 'id-' + i,
name: 'id[]',
type: 'hidden',
title: '',
defaultValue: 'custom.addon.' + i
}, {
id: 'remove-' + i,
type: 'markup',
markup: '
× '
}
]
};
};
return Controller;
})(App.SettingsApp.Show.Base.Controller);
});
this.Kodi.module("SettingsApp.Show", function(Show, App, Backbone, Marionette, $, _) {
Show.Layout = (function(_super) {
__extends(Layout, _super);
function Layout() {
return Layout.__super__.constructor.apply(this, arguments);
}
Layout.prototype.className = "settings-page";
return Layout;
})(App.Views.LayoutWithSidebarFirstView);
return Show.Sidebar = (function(_super) {
__extends(Sidebar, _super);
function Sidebar() {
return Sidebar.__super__.constructor.apply(this, arguments);
}
Sidebar.prototype.className = "settings-sidebar";
Sidebar.prototype.template = "apps/settings/show/settings_sidebar";
Sidebar.prototype.tagName = "div";
Sidebar.prototype.regions = {
regionKodiNav: '.kodi-nav',
regionLocalNav: '.local-nav'
};
return Sidebar;
})(App.Views.LayoutView);
});
this.Kodi.module("Shell", function(Shell, App, Backbone, Marionette, $, _) {
var API;
Shell.Router = (function(_super) {
__extends(Router, _super);
function Router() {
return Router.__super__.constructor.apply(this, arguments);
}
Router.prototype.appRoutes = {
"": "homePage",
"home": "homePage"
};
return Router;
})(App.Router.Base);
API = {
homePage: function() {
var home;
home = new Shell.HomepageLayout();
App.regionContent.show(home);
this.setFanart();
App.vent.on("state:changed", (function(_this) {
return function(state) {
var stateObj;
stateObj = App.request("state:current");
if (stateObj.isPlayingItemChanged() && helpers.url.arg(0) === '') {
return _this.setFanart();
}
};
})(this));
return App.listenTo(home, "destroy", (function(_this) {
return function() {
return App.execute("images:fanart:set", 'none');
};
})(this));
},
setFanart: function() {
var playingItem, stateObj;
stateObj = App.request("state:current");
if (stateObj != null) {
playingItem = stateObj.getPlaying('item');
return App.execute("images:fanart:set", playingItem.fanart);
} else {
return App.execute("images:fanart:set");
}
},
renderLayout: function() {
var playlistState, shellLayout;
shellLayout = new Shell.Layout();
App.root.show(shellLayout);
App.addRegions(shellLayout.regions);
App.execute("loading:show:page");
this.setAppTitle();
playlistState = config.get('app', 'shell:playlist:state', 'open');
if (playlistState === 'closed') {
this.alterRegionClasses('add', "shell-playlist-closed");
}
this.configUpdated();
App.vent.on("config:local:updated", (function(_this) {
return function(data) {
return _this.configUpdated();
};
})(this));
App.vent.on("filter:filtering:start", (function(_this) {
return function() {
return _this.alterRegionClasses('add', "filters-loading");
};
})(this));
App.vent.on("filter:filtering:stop", (function(_this) {
return function() {
return _this.alterRegionClasses('remove', "filters-loading");
};
})(this));
App.listenTo(shellLayout, "shell:playlist:toggle", (function(_this) {
return function(child, args) {
var state;
playlistState = config.get('app', 'shell:playlist:state', 'open');
state = playlistState === 'open' ? 'closed' : 'open';
config.set('app', 'shell:playlist:state', state);
return _this.alterRegionClasses('toggle', "shell-playlist-closed");
};
})(this));
App.listenTo(shellLayout, "shell:reconnect", (function(_this) {
return function() {
return App.execute('shell:reconnect');
};
})(this));
this.bindListenersContextMenu(shellLayout);
return this.bindListenersSelectedMenu(shellLayout);
},
alterRegionClasses: function(op, classes, region) {
var $body, action;
if (region == null) {
region = 'root';
}
$body = App.getRegion(region).$el;
action = "" + op + "Class";
return $body[action](classes);
},
configUpdated: function() {
var disableThumbs, disableThumbsClassOp;
disableThumbs = config.getLocal('disableThumbs', false);
disableThumbsClassOp = disableThumbs === true ? 'add' : 'remove';
this.alterRegionClasses(disableThumbsClassOp, 'disable-thumbs');
return this.setAppTitle();
},
setAppTitle: function() {
var settingsController;
App.getRegion('regionTitle').$el.html('');
if (config.getLocal('showDeviceName', false) === true) {
settingsController = App.request("command:kodi:controller", 'auto', 'Settings');
return settingsController.getSettingValue('services.devicename', function(title) {
return App.getRegion('regionTitle').$el.html(title);
});
}
},
bindListenersContextMenu: function(shellLayout) {
App.listenTo(shellLayout, "shell:audio:scan", function() {
return App.request("command:kodi:controller", 'auto', 'AudioLibrary').scan();
});
App.listenTo(shellLayout, "shell:video:scan", function() {
return App.request("command:kodi:controller", 'auto', 'VideoLibrary').scan();
});
App.listenTo(shellLayout, "shell:goto:lab", function() {
return App.navigate("#lab", {
trigger: true
});
});
App.listenTo(shellLayout, "shell:about", function() {
return App.navigate("#help", {
trigger: true
});
});
return App.listenTo(shellLayout, "shell:send:input", function() {
return App.execute("input:textbox", '');
});
},
bindListenersSelectedMenu: function(shellLayout) {
App.listenTo(shellLayout, "shell:selected:play", function() {
return App.execute("selected:action:play");
});
App.listenTo(shellLayout, "shell:selected:add", function() {
return App.execute("selected:action:add");
});
return App.listenTo(shellLayout, "shell:selected:localadd", function() {
return App.execute("selected:action:localadd");
});
}
};
App.addInitializer(function() {
return App.commands.setHandler("shell:view:ready", function() {
API.renderLayout();
new Shell.Router({
controller: API
});
App.vent.trigger("shell:ready");
return App.commands.setHandler("body:state", function(op, state) {
return API.alterRegionClasses(op, state);
});
});
});
App.commands.setHandler('shell:reconnect', function() {
API.alterRegionClasses('add', 'reconnecting');
return helpers.connection.reconnect(function() {
API.alterRegionClasses('remove', 'lost-connection');
return API.alterRegionClasses('remove', 'reconnecting');
});
});
return App.commands.setHandler('shell:disconnect', function() {
API.alterRegionClasses('add', 'lost-connection');
API.alterRegionClasses('remove', 'reconnecting');
return helpers.connection.disconnect(function() {});
});
});
this.Kodi.module("Shell", function(Shell, App, Backbone, Marionette, $, _) {
Shell.Layout = (function(_super) {
__extends(Layout, _super);
function Layout() {
return Layout.__super__.constructor.apply(this, arguments);
}
Layout.prototype.template = "apps/shell/show/shell";
Layout.prototype.regions = {
regionNav: '#nav-bar',
regionContent: '#content',
regionSidebarFirst: '#sidebar-first',
regionPlaylist: '#playlist-bar',
regionTitle: '#page-title .title',
regionTitleContext: '#page-title .context',
regionFanart: '#fanart',
regionPlayerKodi: '#player-kodi',
regionPlayerLocal: '#player-local',
regionModal: '#modal-window',
regionModalTitle: '.modal-title',
regionModalBody: '.modal-body',
regionModalFooter: '.modal-footer',
regionRemote: '#remote',
regionSearch: '#search-region',
regionTitle: '#page-title .title',
regionOffscreen: '#offscreen'
};
Layout.prototype.triggers = {
"click .playlist-toggle-open": "shell:playlist:toggle",
"click .audio-scan": "shell:audio:scan",
"click .video-scan": "shell:video:scan",
"click .goto-lab": "shell:goto:lab",
"click .send-input": "shell:send:input",
"click .about": "shell:about",
"click .selected-play": "shell:selected:play",
"click .selected-add": "shell:selected:add",
"click .selected-localadd": "shell:selected:localadd",
"click .reconnect": "shell:reconnect"
};
Layout.prototype.events = {
"click .player-menu > li": "closePlayerMenu"
};
Layout.prototype.closePlayerMenu = function() {
return App.execute("ui:playermenu", 'close');
};
return Layout;
})(App.Views.LayoutView);
Shell.HomepageLayout = (function(_super) {
__extends(HomepageLayout, _super);
function HomepageLayout() {
return HomepageLayout.__super__.constructor.apply(this, arguments);
}
HomepageLayout.prototype.template = "apps/shell/show/homepage";
return HomepageLayout;
})(Backbone.Marionette.LayoutView);
return App.execute("shell:view:ready");
});
this.Kodi.module("SongApp.Edit", function(Edit, App, Backbone, Marionette, $, _) {
return Edit.Controller = (function(_super) {
__extends(Controller, _super);
function Controller() {
return Controller.__super__.constructor.apply(this, arguments);
}
Controller.prototype.initialize = function() {
var form, options;
this.model = this.getOption('model');
options = {
title: '
' + tr('Edit') + ' ' + this.model.get('title'),
form: this.getStructure(),
formState: this.model.attributes,
config: {
attributes: {
"class": 'edit-form'
},
editForm: true,
tabs: true,
callback: (function(_this) {
return function(data, formView) {
return _this.saveCallback(data, formView);
};
})(this)
}
};
return form = App.request("form:popup:wrapper", options);
};
Controller.prototype.getStructure = function() {
return [
{
title: 'General',
id: 'general',
children: [
{
id: 'title',
title: tr('Title'),
type: 'textfield'
}, {
id: 'artist',
title: tr('Artist'),
type: 'textfield',
format: 'array.string'
}, {
id: 'albumartist',
title: tr('Album artist'),
type: 'textfield',
format: 'array.string'
}, {
id: 'album',
title: tr('Album'),
type: 'textfield'
}, {
id: 'year',
title: tr('Year'),
type: 'number',
format: 'integer',
attributes: {
"class": 'half-width',
step: 1,
min: 1000,
max: 9999
}
}, {
id: 'rating',
title: tr('Rating'),
type: 'number',
format: 'float',
attributes: {
"class": 'half-width',
step: 0.1,
min: 0,
max: 10
},
suffix: '
'
}, {
id: 'track',
title: tr('Track'),
type: 'textfield',
format: 'integer',
attributes: {
"class": 'half-width'
}
}, {
id: 'disc',
title: tr('Disc'),
type: 'textfield',
format: 'integer',
attributes: {
"class": 'half-width'
},
suffix: '
'
}
]
}, {
title: 'Tags',
id: 'tags',
children: [
{
id: 'genre',
title: tr('Genres'),
type: 'textfield',
format: 'array.string'
}
]
}, {
title: 'Information',
id: 'info',
children: [
{
id: 'file',
title: tr('File path'),
type: 'textarea',
attributes: {
disabled: 'disabled',
cols: 5
},
format: 'prevent.submit'
}
]
}
];
};
Controller.prototype.saveCallback = function(data, formView) {
var controller;
controller = App.request("command:kodi:controller", 'audio', 'AudioLibrary');
return controller.setSongDetails(this.model.get('id'), data, (function(_this) {
return function() {
Kodi.vent.trigger('entity:kodi:update', _this.model.get('uid'));
return Kodi.execute("notification:show", t.sprintf(tr("Updated %1$s details"), 'song'));
};
})(this));
};
return Controller;
})(App.Controllers.Base);
});
this.Kodi.module("SongApp.List", function(List, App, Backbone, Marionette, $, _) {
var API;
API = {
getSongsView: function(songs, verbose) {
if (verbose == null) {
verbose = false;
}
this.songsView = new List.Songs({
collection: songs,
verbose: verbose
});
App.listenTo(this.songsView, 'childview:song:play', (function(_this) {
return function(list, item) {
return _this.playSong(item.model.get('songid'));
};
})(this));
App.listenTo(this.songsView, 'childview:song:add', (function(_this) {
return function(list, item) {
return _this.addSong(item.model.get('songid'));
};
})(this));
App.listenTo(this.songsView, 'childview:song:localadd', (function(_this) {
return function(list, item) {
return _this.localAddSong(item.model.get('songid'));
};
})(this));
App.listenTo(this.songsView, 'childview:song:localplay', (function(_this) {
return function(list, item) {
return _this.localPlaySong(item.model.get('songid'));
};
})(this));
App.listenTo(this.songsView, 'childview:song:download', (function(_this) {
return function(list, item) {
return _this.downloadSong(item.model);
};
})(this));
App.listenTo(this.songsView, 'childview:song:musicvideo', (function(_this) {
return function(list, item) {
return App.execute("youtube:search:popup", item.model.get('label') + ' ' + item.model.get('artist'));
};
})(this));
App.listenTo(this.songsView, 'childview:song:edit', function(parent, item) {
return App.execute('song:edit', item.model);
});
App.listenTo(this.songsView, "show", function() {
return App.vent.trigger("state:content:updated");
});
return this.songsView;
},
playSong: function(songId) {
return App.execute("command:audio:play", 'songid', songId);
},
addSong: function(songId) {
return App.execute("command:audio:add", 'songid', songId);
},
localAddSong: function(songId) {
return App.execute("localplaylist:addentity", 'songid', songId);
},
localPlaySong: function(songId) {
var localPlaylist;
localPlaylist = App.request("command:local:controller", 'audio', 'PlayList');
return localPlaylist.play('songid', songId);
},
downloadSong: function(model) {
var files;
files = App.request("command:kodi:controller", 'video', 'Files');
return files.downloadFile(model.get('file'));
}
};
return App.reqres.setHandler("song:list:view", function(songs, verbose) {
if (verbose == null) {
verbose = false;
}
return API.getSongsView(songs, verbose);
});
});
this.Kodi.module("SongApp.List", function(List, App, Backbone, Marionette, $, _) {
List.Song = (function(_super) {
__extends(Song, _super);
function Song() {
return Song.__super__.constructor.apply(this, arguments);
}
Song.prototype.template = 'apps/song/list/song';
Song.prototype.tagName = "tr";
Song.prototype.initialize = function() {
var duration, menu;
Song.__super__.initialize.apply(this, arguments);
if (this.model) {
duration = helpers.global.secToTime(this.model.get('duration'));
menu = {
'song-localadd': 'Add to playlist',
'song-download': 'Download song',
'song-localplay': 'Play in browser',
'song-musicvideo': 'Music video',
'divider': '',
'song-edit': 'Edit'
};
return this.model.set({
displayDuration: helpers.global.formatTime(duration),
menu: menu
});
}
};
Song.prototype.triggers = {
"click .play": "song:play",
"dblclick .song-title": "song:play",
"click .add": "song:add",
"click .song-localadd": "song:localadd",
"click .song-download": "song:download",
"click .song-localplay": "song:localplay",
"click .song-musicvideo": "song:musicvideo",
"click .song-remove": "song:remove",
"click .song-edit": "song:edit"
};
Song.prototype.events = {
"click .dropdown > i": "populateModelMenu",
"click .thumbs": "toggleThumbs",
"click": "toggleSelect"
};
Song.prototype.modelEvents = {
'change': 'render'
};
Song.prototype.toggleThumbs = function() {
App.request("thumbsup:toggle:entity", this.model);
this.$el.toggleClass('thumbs-up');
return $('.plitem-' + this.model.get('type') + '-' + this.model.get('id')).toggleClass('thumbs-up');
};
Song.prototype.attributes = function() {
var classes;
if (this.model) {
classes = ['song', 'table-row', 'can-play', 'item-' + this.model.get('uid')];
if (App.request("thumbsup:check", this.model)) {
classes.push('thumbs-up');
}
return {
'class': classes.join(' '),
'data-id': this.model.id
};
}
};
Song.prototype.onShow = function() {
return this.menuBlur();
};
Song.prototype.onRender = function() {
return this.$el.data('model', this.model);
};
return Song;
})(App.Views.ItemView);
return List.Songs = (function(_super) {
__extends(Songs, _super);
function Songs() {
return Songs.__super__.constructor.apply(this, arguments);
}
Songs.prototype.childView = List.Song;
Songs.prototype.placeHolderViewName = 'SongViewPlaceholder';
Songs.prototype.cardSelector = '.song';
Songs.prototype.preload = 40;
Songs.prototype.tagName = "table";
Songs.prototype.attributes = function() {
var verbose;
verbose = this.options.verbose ? 'verbose' : 'basic';
return {
"class": 'songs-table table table-hover ' + verbose
};
};
return Songs;
})(App.Views.VirtualListView);
});
this.Kodi.module("SongApp", function(SongApp, App, Backbone, Marionette, $, _) {
return App.commands.setHandler('song:edit', function(model) {
var loadedModel;
loadedModel = App.request("song:entity", model.get('songid'));
return App.execute("when:entity:fetched", loadedModel, (function(_this) {
return function() {
return new SongApp.Edit.Controller({
model: loadedModel
});
};
})(this));
});
});
this.Kodi.module("StateApp", function(StateApp, App, Backbone, Marionette, $, _) {
return StateApp.Base = (function(_super) {
__extends(Base, _super);
function Base() {
return Base.__super__.constructor.apply(this, arguments);
}
Base.prototype.instanceSettings = {};
Base.prototype.state = {
player: 'kodi',
media: 'audio',
volume: 50,
lastVolume: 50,
muted: false,
shuffled: false,
repeat: 'off',
version: {
major: 15,
minor: 0
}
};
Base.prototype.playing = {
playing: false,
paused: false,
playState: '',
item: {},
media: 'audio',
itemChanged: false,
latPlaying: '',
canrepeat: true,
canseek: true,
canshuffle: true,
partymode: false,
percentage: 0,
playlistid: 0,
position: 0,
speed: 0,
time: {
hours: 0,
milliseconds: 0,
minutes: 0,
seconds: 0
},
totaltime: {
hours: 0,
milliseconds: 0,
minutes: 0,
seconds: 0
}
};
Base.prototype.defaultPlayingItem = {
thumbnail: '',
fanart: '',
id: 0,
songid: 0,
episodeid: 0,
album: '',
albumid: '',
duration: 0,
type: 'song'
};
Base.prototype.getState = function(key) {
if (key == null) {
key = 'all';
}
if (key === 'all') {
return this.state;
} else {
return this.state[key];
}
};
Base.prototype.setState = function(key, value) {
return this.state[key] = value;
};
Base.prototype.getPlaying = function(key) {
var ret;
if (key == null) {
key = 'all';
}
ret = this.playing;
if (ret.item.length === 0) {
ret.item = this.defaultPlayingItem;
}
if (key === 'all') {
return this.playing;
} else {
return this.playing[key];
}
};
Base.prototype.setPlaying = function(key, value) {
return this.playing[key] = value;
};
Base.prototype.isPlaying = function(media) {
if (media == null) {
media = 'auto';
}
if (media === 'auto') {
return this.getPlaying('playing');
} else {
return media === this.getState('media') && this.getPlaying('playing');
}
};
Base.prototype.isPlayingItemChanged = function() {
return this.getPlaying('itemChanged');
};
Base.prototype.doCallback = function(callback, resp) {
if (typeof callback === 'function') {
return callback(resp);
}
};
Base.prototype.getCurrentState = function(callback) {};
Base.prototype.getCachedState = function() {
return {
state: this.state,
playing: this.playing
};
};
Base.prototype.setPlayer = function(player) {
var $body;
if (player == null) {
player = 'kodi';
}
$body = App.getRegion('root').$el;
$body.removeClassStartsWith('active-player-').addClass('active-player-' + player);
config.set('state', 'lastplayer', player);
return config.set('app', 'state:lastplayer', player);
};
Base.prototype.getPlayer = function() {
var $body, player;
player = 'kodi';
$body = App.getRegion('root').$el;
if ($body.hasClass('active-player-local')) {
player = 'local';
}
return player;
};
return Base;
})(Marionette.Object);
});
this.Kodi.module("StateApp.Kodi", function(StateApp, App, Backbone, Marionette, $, _) {
return StateApp.State = (function(_super) {
__extends(State, _super);
function State() {
return State.__super__.constructor.apply(this, arguments);
}
State.prototype.playerController = {};
State.prototype.applicationController = {};
State.prototype.playlistApi = {};
State.prototype.initialize = function() {
this.state = _.extend({}, this.state);
this.playing = _.extend({}, this.playing);
this.setState('player', 'kodi');
this.playerController = App.request("command:kodi:controller", 'auto', 'Player');
this.applicationController = App.request("command:kodi:controller", 'auto', 'Application');
this.playlistApi = App.request("playlist:kodi:entity:api");
App.reqres.setHandler("state:kodi:update", (function(_this) {
return function(callback) {
return _this.getCurrentState(callback);
};
})(this));
return App.reqres.setHandler("state:kodi:get", (function(_this) {
return function() {
return _this.getCachedState();
};
})(this));
};
State.prototype.getCurrentState = function(callback) {
return this.applicationController.getProperties((function(_this) {
return function(properties) {
_this.setState('volume', properties.volume);
_this.setState('muted', properties.muted);
_this.setState('version', properties.version);
App.reqres.setHandler('player:kodi:timer', 'stop');
return _this.playerController.getPlaying(function(playing) {
var autoMap, key, media, _i, _len;
if (playing) {
_this.setPlaying('playing', true);
_this.setPlaying('paused', playing.properties.speed === 0);
_this.setPlaying('playState', (playing.properties.speed === 0 ? 'paused' : 'playing'));
autoMap = ['canrepeat', 'canseek', 'canshuffle', 'partymode', 'percentage', 'playlistid', 'position', 'speed', 'time', 'totaltime'];
for (_i = 0, _len = autoMap.length; _i < _len; _i++) {
key = autoMap[_i];
if (playing.properties[key] != null) {
_this.setPlaying(key, playing.properties[key]);
}
}
_this.setState('shuffled', playing.properties.shuffled);
_this.setState('repeat', playing.properties.repeat);
media = _this.playerController.playerIdToName(playing.properties.playlistid);
if (media) {
_this.setState('media', media);
}
if (playing.item.file !== _this.getPlaying('lastPlaying')) {
_this.setPlaying('itemChanged', true);
App.vent.trigger("state:kodi:itemchanged", _this.getCachedState());
} else {
_this.setPlaying('itemChanged', false);
}
_this.setPlaying('lastPlaying', playing.item.file);
_this.setPlaying('item', _this.parseItem(playing.item, {
media: media,
playlistid: playing.properties.playlistid
}));
App.reqres.setHandler('player:kodi:timer', 'start');
} else {
_this.setPlaying('playing', false);
_this.setPlaying('paused', false);
_this.setPlaying('item', _this.defaultPlayingItem);
_this.setPlaying('lstPlaying', '');
}
App.vent.trigger("state:kodi:changed", _this.getCachedState());
App.vent.trigger("state:changed");
return _this.doCallback(callback, _this.getCachedState());
});
};
})(this));
};
State.prototype.parseItem = function(model, options) {
model = this.playlistApi.parseItem(model, options);
model = App.request("images:path:entity", model);
model.url = helpers.url.get(model.type, model.id);
model.url = helpers.url.playlistUrl(model);
return model;
};
return State;
})(App.StateApp.Base);
});
this.Kodi.module("StateApp.Kodi", function(StateApp, App, Backbone, Marionette, $, _) {
return StateApp.Notifications = (function(_super) {
__extends(Notifications, _super);
function Notifications() {
return Notifications.__super__.constructor.apply(this, arguments);
}
Notifications.prototype.wsActive = false;
Notifications.prototype.wsObj = {};
Notifications.prototype.getConnection = function() {
var host, protocol, socketHost, socketPath, socketPort;
host = config.getLocal('socketsHost');
socketPath = config.getLocal('jsonRpcEndpoint');
socketPort = config.getLocal('socketsPort');
socketHost = host === 'auto' ? location.hostname : host;
protocol = helpers.url.isSecureProtocol() ? "wss" : "ws";
return "" + protocol + "://" + socketHost + ":" + socketPort + "/" + socketPath + "?kodi";
};
Notifications.prototype.initialize = function() {
var msg, ws;
if (window.WebSocket) {
ws = new WebSocket(this.getConnection());
ws.onopen = (function(_this) {
return function(e) {
helpers.debug.msg("Websockets Active");
_this.wsActive = true;
return App.vent.trigger("sockets:available");
};
})(this);
ws.onerror = (function(_this) {
return function(resp) {
helpers.debug.msg(_this.socketConnectionErrorMsg(), "warning", resp);
_this.wsActive = false;
return App.vent.trigger("sockets:unavailable");
};
})(this);
ws.onmessage = (function(_this) {
return function(resp) {
return _this.messageReceived(resp);
};
})(this);
ws.onclose = (function(_this) {
return function(resp) {
helpers.debug.msg("Websockets Closed", "warning", resp);
_this.wsActive = false;
App.execute("notification:show", tr("Lost websocket connection"));
return setTimeout(function() {
App.execute("notification:show", tr("Attempting websockets reconnect"));
return App.execute('state:ws:init');
}, 60000);
};
})(this);
} else {
msg = "Your browser doesn't support websockets! Get with the times and update your browser.";
helpers.debug.msg(t.gettext(msg), "warning", resp);
App.vent.trigger("sockets:unavailable");
}
return App.reqres.setHandler("sockets:active", (function(_this) {
return function() {
return _this.wsActive;
};
})(this));
};
Notifications.prototype.parseResponse = function(resp) {
return jQuery.parseJSON(resp.data);
};
Notifications.prototype.messageReceived = function(resp) {
var data;
data = this.parseResponse(resp);
return this.onMessage(data);
};
Notifications.prototype.socketConnectionErrorMsg = function() {
var msg;
msg = "Failed to connect to websockets";
return t.gettext(msg);
};
Notifications.prototype.refreshStateNow = function(callback) {
App.vent.trigger("state:kodi:changed", this.getCachedState());
return setTimeout(((function(_this) {
return function() {
return App.request("state:kodi:update", function(state) {
if (callback) {
return callback(state);
}
});
};
})(this)), 1000);
};
Notifications.prototype.onLibraryUpdate = function(data) {
var model;
model = data.params.data.item ? data.params.data.item : data.params.data;
model.uid = helpers.entities.createUid(model, model.type);
App.vent.trigger('entity:kodi:update', model.uid);
if (model.type === 'episode') {
clearTimeout(App.episodeRecheckTimeout);
return App.episodeRecheckTimeout = setTimeout(function() {
return App.request('episode:entity', model.id, {
success: function(epModel) {
return App.vent.trigger('entity:kodi:update', 'tvshow-' + epModel.get('tvshowid'));
}
});
}, 2000);
}
};
Notifications.prototype.onMessage = function(data) {
var wait;
switch (data.method) {
case 'Player.OnPlay':
this.setPlaying('paused', false);
this.setPlaying('playState', 'playing');
App.execute("player:kodi:timer", 'start');
this.refreshStateNow();
break;
case 'Player.OnStop':
this.setPlaying('playing', false);
App.execute("player:kodi:timer", 'stop');
this.refreshStateNow();
break;
case 'Player.OnPropertyChanged':
this.refreshStateNow();
break;
case 'Player.OnPause':
this.setPlaying('paused', true);
this.setPlaying('playState', 'paused');
App.execute("player:kodi:timer", 'stop');
this.refreshStateNow();
break;
case 'Player.OnSeek':
App.execute("player:kodi:timer", 'stop');
this.refreshStateNow(function() {
return App.execute("player:kodi:timer", 'start');
});
break;
case 'Playlist.OnClear':
case 'Playlist.OnAdd':
case 'Playlist.OnRemove':
clearTimeout(App.playlistUpdateTimeout);
App.playlistUpdateTimeout = setTimeout((function(_this) {
return function(e) {
var playerController;
playerController = App.request("command:kodi:controller", 'auto', 'Player');
App.execute("playlist:refresh", 'kodi', playerController.playerIdToName(data.params.data.playlistid));
return _this.refreshStateNow();
};
})(this), 500);
break;
case 'Application.OnVolumeChanged':
App.request("state:kodi").getCurrentState();
break;
case 'VideoLibrary.OnScanStarted':
App.execute("notification:show", t.gettext("Video library scan started"));
break;
case 'VideoLibrary.OnScanFinished':
App.execute("notification:show", t.gettext("Video library scan complete"));
Backbone.fetchCache.clearItem('MovieCollection');
Backbone.fetchCache.clearItem('TVShowCollection');
break;
case 'AudioLibrary.OnScanStarted':
App.execute("notification:show", t.gettext("Audio library scan started"));
break;
case 'AudioLibrary.OnScanFinished':
App.execute("notification:show", t.gettext("Audio library scan complete"));
Backbone.fetchCache.clearItem('AlbumCollection');
Backbone.fetchCache.clearItem('ArtistCollection');
break;
case 'AudioLibrary.OnCleanStarted':
App.execute("notification:show", t.gettext("Audio library clean started"));
break;
case 'AudioLibrary.OnCleanFinished':
App.execute("notification:show", t.gettext("Audio library clean finished"));
break;
case 'VideoLibrary.OnCleanStarted':
App.execute("notification:show", t.gettext("Video library clean started"));
break;
case 'VideoLibrary.OnCleanFinished':
App.execute("notification:show", t.gettext("Video library clean finished"));
break;
case 'AudioLibrary.OnUpdate':
case 'VideoLibrary.OnUpdate':
this.onLibraryUpdate(data);
break;
case 'Input.OnInputRequested':
App.execute("input:textbox", '');
wait = 60;
App.inputTimeout = setTimeout((function() {
var msg, wotd;
wotd = '
word of the day ';
msg = t.sprintf(tr("%1$d seconds ago, an input dialog opened in Kodi and it is still open! To prevent " + "a mainframe implosion, you should probably give me some text. I don't really care what it " + "is at this point, why not be creative? Do you have a %2$s? I won't tell..."), wait, wotd);
App.execute("input:textbox", msg);
}), 1000 * wait);
break;
case 'Input.OnInputFinished':
clearTimeout(App.inputTimeout);
App.execute("input:textbox:close");
break;
case 'System.OnQuit':
App.execute("notification:show", t.gettext("Kodi has quit"));
App.execute("shell:disconnect");
break;
case 'System.OnWake':
case 'System.OnRestart':
App.execute("shell:reconnect");
break;
}
};
return Notifications;
})(App.StateApp.Base);
});
this.Kodi.module("StateApp.Kodi", function(StateApp, App, Backbone, Marionette, $, _) {
return StateApp.Polling = (function(_super) {
__extends(Polling, _super);
function Polling() {
return Polling.__super__.constructor.apply(this, arguments);
}
Polling.prototype.commander = {};
Polling.prototype.checkInterval = 10000;
Polling.prototype.currentInterval = '';
Polling.prototype.timeoutObj = {};
Polling.prototype.failures = 0;
Polling.prototype.maxFailures = 100;
Polling.prototype.initialize = function() {
var interval;
interval = config.getLocal('pollInterval');
this.checkInterval = parseInt(interval);
return this.currentInterval = this.checkInterval;
};
Polling.prototype.startPolling = function() {
return this.update();
};
Polling.prototype.updateState = function() {
var stateObj;
stateObj = App.request("state:kodi");
return stateObj.getCurrentState();
};
Polling.prototype.update = function() {
if (config.getLocal('connected', true) === false) {
return;
}
if (App.kodiPolling.failures < App.kodiPolling.maxFailures) {
App.kodiPolling.updateState();
return App.kodiPolling.timeout = setTimeout(App.kodiPolling.ping, App.kodiPolling.currentInterval);
} else {
App.execute("notification:show", t.gettext("Unable to communicate with Kodi in a long time. I think it's dead Jim!"));
return App.execute("shell:disconnect");
}
};
Polling.prototype.ping = function() {
var commander;
commander = App.request("command:kodi:controller", 'auto', 'Commander');
commander.setOptions({
timeout: 5000,
error: function() {
return App.kodiPolling.failure();
}
});
commander.onError = function() {};
return commander.sendCommand('Ping', [], function() {
return App.kodiPolling.alive();
});
};
Polling.prototype.alive = function() {
App.kodiPolling.failures = 0;
App.kodiPolling.currentInterval = App.kodiPolling.checkInterval;
return App.kodiPolling.update();
};
Polling.prototype.failure = function() {
App.kodiPolling.failures++;
if (App.kodiPolling.failures > 10) {
App.kodiPolling.currentInterval = App.kodiPolling.checkInterval * 5;
}
if (App.kodiPolling.failures > 20) {
App.kodiPolling.currentInterval = App.kodiPolling.checkInterval * 10;
}
if (App.kodiPolling.failures > 30) {
App.kodiPolling.currentInterval = App.kodiPolling.checkInterval * 30;
}
return App.kodiPolling.update();
};
return Polling;
})(App.StateApp.Base);
});
this.Kodi.module("StateApp.Local", function(StateApp, App, Backbone, Marionette, $, _) {
return StateApp.State = (function(_super) {
__extends(State, _super);
function State() {
return State.__super__.constructor.apply(this, arguments);
}
State.prototype.initialize = function() {
this.state = _.extend({}, this.state);
this.playing = _.extend({}, this.playing);
this.setState('player', 'local');
this.setState('currentPlaybackId', 'browser-none');
this.setState('localPlay', false);
App.reqres.setHandler("state:local:update", (function(_this) {
return function(callback) {
return _this.getCurrentState(callback);
};
})(this));
return App.reqres.setHandler("state:local:get", (function(_this) {
return function() {
return _this.getCachedState();
};
})(this));
};
State.prototype.getCurrentState = function(callback) {
return this.doCallback(callback, this.getCachedState());
};
return State;
})(App.StateApp.Base);
});
this.Kodi.module("StateApp", function(StateApp, App, Backbone, Marionette, $, _) {
var API;
API = {
setState: function(player) {
if (player == null) {
player = 'kodi';
}
this.setBodyClasses(player);
this.setPlayingContent(player);
this.setPlayerPlaying(player);
this.setAppProperties(player);
return this.setTitle(player);
},
playerClass: function(className, player) {
return player + '-' + className;
},
setBodyClasses: function(player) {
var $body, c, newClasses, stateObj, _i, _len, _results;
stateObj = App.request("state:" + player);
$body = App.getRegion('root').$el;
$body.removeClassStartsWith(player + '-');
newClasses = [];
newClasses.push('shuffled-' + (stateObj.getState('shuffled') ? 'on' : 'off'));
newClasses.push('partymode-' + (stateObj.getPlaying('partymode') ? 'on' : 'off'));
newClasses.push('mute-' + (stateObj.getState('muted') ? 'on' : 'off'));
newClasses.push('repeat-' + stateObj.getState('repeat'));
newClasses.push('media-' + stateObj.getState('media'));
if (stateObj.isPlaying()) {
newClasses.push(stateObj.getPlaying('playState'));
} else {
newClasses.push('not-playing');
}
_results = [];
for (_i = 0, _len = newClasses.length; _i < _len; _i++) {
c = newClasses[_i];
_results.push($body.addClass(this.playerClass(c, player)));
}
return _results;
},
setPlayingContent: function(player) {
var $plItem, $playlistCtx, className, item, playState, stateObj;
stateObj = App.request("state:" + player);
$playlistCtx = $('.media-' + stateObj.getState('media') + ' .' + player + '-playlist');
$('.can-play').removeClassStartsWith(player + '-row-');
$('.item', $playlistCtx).removeClassStartsWith('row-');
if (stateObj.isPlaying()) {
item = stateObj.getPlaying('item');
playState = stateObj.getPlaying('playState');
className = '.item-' + item.uid;
$(className).addClass(this.playerClass('row-' + playState, player));
$plItem = $('.pos-' + stateObj.getPlaying('position'), $playlistCtx).addClass('row-' + playState);
if ($plItem.data('type') === 'file') {
$('.thumb', $plItem).css("background-image", "url('" + item.thumbnail + "')");
$('.title', $plItem).html(helpers.entities.playingLink(item));
}
return App.vent.trigger("state:" + player + ":playing:updated", stateObj);
}
},
setPlayerPlaying: function(player) {
var $dur, $img, $playerCtx, $subtitle, $title, item, stateObj;
stateObj = App.request("state:" + player);
$playerCtx = $('#player-' + player);
$title = $('.playing-title', $playerCtx);
$subtitle = $('.playing-subtitle', $playerCtx);
$dur = $('.playing-time-duration', $playerCtx);
$img = $('.playing-thumb', $playerCtx);
if (stateObj.isPlaying()) {
item = stateObj.getPlaying('item');
$title.html(helpers.entities.playingLink(item));
$subtitle.html(helpers.entities.getSubtitle(item));
$dur.html(helpers.global.formatTime(stateObj.getPlaying('totaltime')));
return $img.css("background-image", "url('" + item.thumbnail + "')");
} else {
$title.html(t.gettext('Nothing playing'));
$subtitle.html('');
$dur.html('0');
return $img.attr('src', App.request("images:path:get"));
}
},
setAppProperties: function(player) {
var $playerCtx, stateObj;
stateObj = App.request("state:" + player);
$playerCtx = $('#player-' + player);
return $('.volume', $playerCtx).val(stateObj.getState('volume'));
},
setTitle: function(player) {
var stateObj;
if (player === 'kodi') {
stateObj = App.request("state:" + player);
if (stateObj.isPlaying() && stateObj.getPlaying('playState') === 'playing') {
return helpers.global.appTitle(stateObj.getPlaying('item'));
} else {
return helpers.global.appTitle();
}
}
},
getDefaultPlayer: function() {
var player;
player = config.getLocal('defaultPlayer', 'auto');
if (player === 'auto') {
player = config.get('app', 'state:lastplayer', 'kodi');
}
return player;
},
initKodiState: function() {
App.kodiState = new StateApp.Kodi.State();
App.localState = new StateApp.Local.State();
App.kodiState.setPlayer(this.getDefaultPlayer());
App.kodiState.getCurrentState(function(state) {
API.setState('kodi');
App.kodiSockets = new StateApp.Kodi.Notifications();
App.kodiPolling = new StateApp.Kodi.Polling();
App.vent.on("sockets:unavailable", function() {
return App.kodiPolling.startPolling();
});
App.vent.on("playlist:rendered", function() {
return App.request("playlist:refresh", App.kodiState.getState('player'), App.kodiState.getState('media'));
});
App.vent.on("state:content:updated", function() {
API.setPlayingContent('kodi');
return API.setPlayingContent('local');
});
App.vent.on("state:kodi:changed", function(state) {
return API.setState('kodi');
});
App.vent.on("state:local:changed", function(state) {
return API.setState('local');
});
App.vent.on("state:player:updated", function(player) {
return API.setPlayerPlaying(player);
});
return App.vent.trigger("state:initialized");
});
App.reqres.setHandler("state:kodi", function() {
return App.kodiState;
});
App.reqres.setHandler("state:local", function() {
return App.localState;
});
App.reqres.setHandler("state:current", function() {
var stateObj;
stateObj = App.kodiState.getPlayer() === 'kodi' ? App.kodiState : App.localState;
return stateObj;
});
App.commands.setHandler('state:ws:init', function() {
return App.kodiSockets = new StateApp.Kodi.Notifications();
});
return App.vent.trigger("state:changed");
}
};
return App.addInitializer(function() {
return API.initKodiState();
});
});
this.Kodi.module("ThumbsApp.List", function(List, App, Backbone, Marionette, $, _) {
return List.Controller = (function(_super) {
__extends(Controller, _super);
function Controller() {
return Controller.__super__.constructor.apply(this, arguments);
}
Controller.prototype.entityTitles = {
musicvideo: 'music video'
};
Controller.prototype.initialize = function() {
var entities;
this.layout = this.getLayout();
entities = ['song', 'artist', 'album', 'tvshow', 'movie', 'episode', 'musicvideo'];
this.listenTo(this.layout, "show", (function(_this) {
return function() {
var entity, _i, _len, _results;
_results = [];
for (_i = 0, _len = entities.length; _i < _len; _i++) {
entity = entities[_i];
_results.push(_this.getResult(entity));
}
return _results;
};
})(this));
return App.regionContent.show(this.layout);
};
Controller.prototype.getLayout = function() {
return new List.ListLayout();
};
Controller.prototype.getResult = function(entity) {
var limit, loaded, query, setView, view;
query = this.getOption('query');
limit = this.getOption('media') === 'all' ? 'limit' : 'all';
loaded = App.request("thumbsup:get:entities", entity);
if (loaded.length > 0) {
view = App.request("" + entity + ":list:view", loaded, true);
setView = new List.ListSet({
entity: this.getTitle(entity)
});
App.listenTo(setView, "show", (function(_this) {
return function() {
return setView.regionResult.show(view);
};
})(this));
return this.layout["" + entity + "Set"].show(setView);
}
};
Controller.prototype.getTitle = function(entity) {
var title;
title = this.entityTitles[entity] ? this.entityTitles[entity] : entity;
return title;
};
return Controller;
})(App.Controllers.Base);
});
this.Kodi.module("ThumbsApp.List", function(List, App, Backbone, Marionette, $, _) {
List.ListLayout = (function(_super) {
__extends(ListLayout, _super);
function ListLayout() {
return ListLayout.__super__.constructor.apply(this, arguments);
}
ListLayout.prototype.template = 'apps/thumbs/list/thumbs_layout';
ListLayout.prototype.className = "thumbs-page set-page";
ListLayout.prototype.regions = {
artistSet: '.entity-set-artist',
albumSet: '.entity-set-album',
songSet: '.entity-set-song',
movieSet: '.entity-set-movie',
tvshowSet: '.entity-set-tvshow',
episodeSet: '.entity-set-episode',
musicvideoSet: '.entity-set-musicvideo'
};
return ListLayout;
})(App.Views.LayoutView);
return List.ListSet = (function(_super) {
__extends(ListSet, _super);
function ListSet() {
return ListSet.__super__.constructor.apply(this, arguments);
}
ListSet.prototype.template = 'apps/thumbs/list/thumbs_set';
ListSet.prototype.className = "thumbs-set";
ListSet.prototype.onRender = function() {
if (this.options) {
if (this.options.entity) {
return $('h2.set-header', this.$el).html(t.gettext(this.options.entity + 's'));
}
}
};
ListSet.prototype.regions = {
regionResult: '.set-results'
};
return ListSet;
})(App.Views.LayoutView);
});
this.Kodi.module("ThumbsApp", function(ThumbsApp, App, Backbone, Marionette, $, _) {
var API;
ThumbsApp.Router = (function(_super) {
__extends(Router, _super);
function Router() {
return Router.__super__.constructor.apply(this, arguments);
}
Router.prototype.appRoutes = {
"thumbsup": "list"
};
return Router;
})(App.Router.Base);
API = {
list: function() {
return new ThumbsApp.List.Controller();
}
};
return App.on("before:start", function() {
return new ThumbsApp.Router({
controller: API
});
});
});
this.Kodi.module("TVShowApp.EditEpisode", function(Edit, App, Backbone, Marionette, $, _) {
return Edit.Controller = (function(_super) {
__extends(Controller, _super);
function Controller() {
return Controller.__super__.constructor.apply(this, arguments);
}
Controller.prototype.initialize = function() {
var form, options;
this.model = this.getOption('model');
options = {
title: '
' + tr('Edit') + ' ' + this.model.get('showtitle') + ' - ' + this.model.get('title') + ' (S' + this.model.get('season') + ' E' + this.model.get('episode') + ')',
form: this.getStructure(),
formState: this.model.attributes,
config: {
attributes: {
"class": 'edit-form'
},
editForm: true,
tabs: true,
callback: (function(_this) {
return function(data, formView) {
return _this.saveCallback(data, formView);
};
})(this)
}
};
return form = App.request("form:popup:wrapper", options);
};
Controller.prototype.getStructure = function() {
return [
{
title: 'General',
id: 'general',
children: [
{
id: 'title',
title: tr('Title'),
type: 'textfield'
}, {
id: 'plot',
title: tr('Plot'),
type: 'textarea'
}, {
id: 'rating',
title: tr('Rating'),
type: 'number',
format: 'float',
attributes: {
"class": 'half-width',
step: 0.1,
min: 0,
max: 10
}
}, {
id: 'firstaired',
title: tr('First aired'),
type: 'date',
attributes: {
"class": 'half-width'
},
suffix: '
'
}, {
id: 'originaltitle',
title: tr('Original title'),
type: 'textfield'
}
]
}, {
title: 'Tags',
id: 'tags',
children: [
{
id: 'director',
title: tr('Directors'),
type: 'textfield',
format: 'array.string'
}, {
id: 'writer',
title: tr('Writers'),
type: 'textfield',
format: 'array.string'
}
]
}, {
title: 'Information',
id: 'info',
children: [
{
id: 'file',
title: tr('File path'),
type: 'textarea',
attributes: {
disabled: 'disabled',
cols: 5
},
format: 'prevent.submit'
}
]
}
];
};
Controller.prototype.saveCallback = function(data, formView) {
var controller;
controller = App.request("command:kodi:controller", 'video', 'VideoLibrary');
return controller.setEpisodeDetails(this.model.get('id'), data, (function(_this) {
return function() {
Kodi.vent.trigger('entity:kodi:update', _this.model.get('uid'));
return Kodi.execute("notification:show", t.sprintf(tr("Updated %1$s details"), 'episode'));
};
})(this));
};
return Controller;
})(App.Controllers.Base);
});
this.Kodi.module("TVShowApp.EditShow", function(Edit, App, Backbone, Marionette, $, _) {
return Edit.Controller = (function(_super) {
__extends(Controller, _super);
function Controller() {
return Controller.__super__.constructor.apply(this, arguments);
}
Controller.prototype.initialize = function() {
var form, options;
this.model = this.getOption('model');
options = {
title: '
' + tr('Edit') + ' ' + this.model.get('title'),
form: this.getStructure(),
formState: this.model.attributes,
config: {
attributes: {
"class": 'edit-form'
},
editForm: true,
tabs: true,
callback: (function(_this) {
return function(data, formView) {
return _this.saveCallback(data, formView);
};
})(this)
}
};
return form = App.request("form:popup:wrapper", options);
};
Controller.prototype.getStructure = function() {
return [
{
title: 'General',
id: 'general',
children: [
{
id: 'title',
title: tr('Title'),
type: 'textfield'
}, {
id: 'plot',
title: tr('Plot'),
type: 'textarea'
}, {
id: 'studio',
title: tr('Studio'),
type: 'textfield',
format: 'array.string'
}, {
id: 'mpaa',
title: tr('Content rating'),
type: 'textfield',
attributes: {
"class": 'half-width'
}
}, {
id: 'premiered',
title: tr('Premiered'),
type: 'date',
attributes: {
"class": 'half-width'
},
suffix: '
'
}, {
id: 'rating',
title: tr('Rating'),
type: 'number',
format: 'float',
attributes: {
"class": 'half-width',
step: 0.1,
min: 0,
max: 10
}
}, {
id: 'imdbnumber',
title: tr('IMDb'),
type: 'textfield',
attributes: {
"class": 'half-width'
},
suffix: '
'
}, {
id: 'sorttitle',
title: tr('Sort title'),
type: 'textfield'
}, {
id: 'originaltitle',
title: tr('Original title'),
type: 'textfield'
}
]
}, {
title: 'Tags',
id: 'tags',
children: [
{
id: 'genre',
title: tr('Genres'),
type: 'textfield',
format: 'array.string'
}, {
id: 'tag',
title: tr('Tags'),
type: 'textarea',
format: 'array.string'
}
]
}, {
title: 'Poster',
id: 'poster',
children: [
{
id: 'thumbnail',
title: tr('URL'),
type: 'imageselect',
valueProperty: 'thumbnailOriginal',
description: tr('Add an image via an external URL'),
metadataImageHandler: 'themoviedb:tv:image:entities',
metadataLookupField: 'imdbnumber'
}
]
}, {
title: 'Background',
id: 'background',
children: [
{
id: 'fanart',
title: tr('URL'),
type: 'imageselect',
valueProperty: 'fanartOriginal',
description: tr('Add an image via an external URL'),
metadataImageHandler: 'themoviedb:tv:image:entities',
metadataLookupField: 'imdbnumber'
}
]
}
];
};
Controller.prototype.saveCallback = function(data, formView) {
var controller;
controller = App.request("command:kodi:controller", 'video', 'VideoLibrary');
return controller.setTVShowDetails(this.model.get('id'), data, (function(_this) {
return function() {
Kodi.vent.trigger('entity:kodi:update', _this.model.get('uid'));
return Kodi.execute("notification:show", t.sprintf(tr("Updated %1$s details"), 'tvshow'));
};
})(this));
};
return Controller;
})(App.Controllers.Base);
});
this.Kodi.module("TVShowApp.Episode", function(Episode, App, Backbone, Marionette, $, _) {
var API;
API = {
getEpisodeList: function(collection) {
var view;
view = new Episode.Episodes({
collection: collection
});
App.listenTo(view, 'childview:episode:play', function(parent, viewItem) {
return App.execute('episode:action', 'play', viewItem);
});
App.listenTo(view, 'childview:episode:add', function(parent, viewItem) {
return App.execute('episode:action', 'add', viewItem);
});
App.listenTo(view, 'childview:episode:localplay', function(parent, viewItem) {
return App.execute('episode:action', 'localplay', viewItem);
});
App.listenTo(view, 'childview:episode:download', function(parent, viewItem) {
return App.execute('episode:action', 'download', viewItem);
});
App.listenTo(view, 'childview:episode:watched', function(parent, viewItem) {
return App.execute('episode:action:watched', parent, viewItem);
});
App.listenTo(view, 'childview:episode:goto:season', function(parent, viewItem) {
return App.execute('episode:action', 'gotoSeason', viewItem);
});
App.listenTo(view, 'childview:episode:edit', function(parent, viewItem) {
return App.execute('episode:edit', viewItem.model);
});
return view;
},
bindTriggers: function(view) {
App.listenTo(view, 'episode:play', function(viewItem) {
return App.execute('episode:action', 'play', viewItem);
});
App.listenTo(view, 'episode:add', function(viewItem) {
return App.execute('episode:action', 'add', viewItem);
});
App.listenTo(view, 'episode:localplay', function(viewItem) {
return App.execute('episode:action', 'localplay', viewItem);
});
App.listenTo(view, 'episode:download', function(viewItem) {
return App.execute('episode:action', 'download', viewItem);
});
App.listenTo(view, 'toggle:watched', function(viewItem) {
return App.execute('episode:action:watched', viewItem.view, viewItem.view);
});
App.listenTo(view, 'episode:refresh', function(viewItem) {
return App.execute('episode:action', 'refresh', viewItem);
});
return App.listenTo(view, 'episode:edit', function(viewItem) {
return App.execute('episode:edit', viewItem.model);
});
}
};
Episode.Controller = (function(_super) {
__extends(Controller, _super);
function Controller() {
return Controller.__super__.constructor.apply(this, arguments);
}
Controller.prototype.initialize = function(options) {
var episode, episodeId, id, seasonId;
id = parseInt(options.id);
seasonId = parseInt(options.season);
episodeId = parseInt(options.episodeid);
episode = App.request("episode:entity", episodeId);
return App.execute("when:entity:fetched", episode, (function(_this) {
return function() {
_this.layout = _this.getLayoutView(episode);
_this.listenTo(_this.layout, "show", function() {
_this.getDetailsLayoutView(episode);
return _this.getContentView(episode);
});
return App.regionContent.show(_this.layout);
};
})(this));
};
Controller.prototype.getLayoutView = function(episode) {
return new Episode.PageLayout({
model: episode
});
};
Controller.prototype.getDetailsLayoutView = function(episode) {
var headerLayout;
headerLayout = new Episode.HeaderLayout({
model: episode
});
this.listenTo(headerLayout, "show", (function(_this) {
return function() {
var detail, teaser;
teaser = new Episode.EpisodeDetailTeaser({
model: episode
});
detail = new Episode.Details({
model: episode
});
API.bindTriggers(detail);
headerLayout.regionSide.show(teaser);
return headerLayout.regionMeta.show(detail);
};
})(this));
return this.layout.regionHeader.show(headerLayout);
};
Controller.prototype.getContentView = function(episode) {
this.contentLayout = new Episode.Content({
model: episode
});
App.listenTo(this.contentLayout, 'show', (function(_this) {
return function() {
if (episode.get('cast').length > 0) {
_this.contentLayout.regionCast.show(_this.getCast(episode));
}
return _this.getSeason(episode);
};
})(this));
return this.layout.regionContent.show(this.contentLayout);
};
Controller.prototype.getCast = function(episode) {
return App.request('cast:list:view', episode.get('cast'), 'tvshows');
};
Controller.prototype.getSeason = function(episode) {
var collection;
collection = App.request("episode:tvshow:entities", episode.get('tvshowid'), episode.get('season'));
return App.execute("when:entity:fetched", collection, (function(_this) {
return function() {
var view;
collection.sortCollection('episode', 'asc');
view = App.request("episode:list:view", collection);
return _this.contentLayout.regionSeason.show(view);
};
})(this));
};
return Controller;
})(App.Controllers.Base);
return App.reqres.setHandler("episode:list:view", function(collection) {
return API.getEpisodeList(collection);
});
});
this.Kodi.module("TVShowApp.Episode", function(Episode, App, Backbone, Marionette, $, _) {
Episode.EpisodeTeaser = (function(_super) {
__extends(EpisodeTeaser, _super);
function EpisodeTeaser() {
return EpisodeTeaser.__super__.constructor.apply(this, arguments);
}
EpisodeTeaser.prototype.triggers = {
"click .play": "episode:play",
"click .watched": "episode:watched",
"click .add": "episode:add",
"click .localplay": "episode:localplay",
"click .download": "episode:download",
"click .goto-season": "episode:goto:season",
"click .edit": "episode:edit"
};
EpisodeTeaser.prototype.initialize = function() {
EpisodeTeaser.__super__.initialize.apply(this, arguments);
if (this.model != null) {
this.setMeta();
return this.model.set(App.request('episode:action:items'));
}
};
EpisodeTeaser.prototype.attributes = function() {
return this.watchedAttributes('card');
};
EpisodeTeaser.prototype.setMeta = function() {
var epNum, epNumFull, showLink, subTitleTip;
epNum = this.themeTag('span', {
"class": 'ep-num'
}, this.model.get('season') + 'x' + this.model.get('episode') + ' ');
epNumFull = this.themeTag('span', {
"class": 'ep-num-full'
}, t.gettext('Episode') + ' ' + this.model.get('episode'));
showLink = this.themeLink(this.model.get('showtitle') + ' ', 'tvshow/' + this.model.get('tvshowid'), {
className: 'show-name'
});
subTitleTip = this.model.get('firstaired') ? {
title: tr('First aired') + ': ' + this.model.get('firstaired')
} : {};
return this.model.set({
label: epNum + this.model.get('title'),
subtitle: this.themeTag('div', subTitleTip, showLink + epNumFull)
});
};
return EpisodeTeaser;
})(App.Views.CardView);
Episode.Empty = (function(_super) {
__extends(Empty, _super);
function Empty() {
return Empty.__super__.constructor.apply(this, arguments);
}
Empty.prototype.tagName = "li";
Empty.prototype.className = "episode-empty-result";
return Empty;
})(App.Views.EmptyViewResults);
Episode.Episodes = (function(_super) {
__extends(Episodes, _super);
function Episodes() {
return Episodes.__super__.constructor.apply(this, arguments);
}
Episodes.prototype.childView = Episode.EpisodeTeaser;
Episodes.prototype.emptyView = Episode.Empty;
Episodes.prototype.tagName = "ul";
Episodes.prototype.className = "card-grid--episode";
return Episodes;
})(App.Views.CollectionView);
Episode.PageLayout = (function(_super) {
__extends(PageLayout, _super);
function PageLayout() {
return PageLayout.__super__.constructor.apply(this, arguments);
}
PageLayout.prototype.className = 'episode-show detail-container';
return PageLayout;
})(App.Views.LayoutWithHeaderView);
Episode.HeaderLayout = (function(_super) {
__extends(HeaderLayout, _super);
function HeaderLayout() {
return HeaderLayout.__super__.constructor.apply(this, arguments);
}
HeaderLayout.prototype.className = 'episode-details';
return HeaderLayout;
})(App.Views.LayoutDetailsHeaderView);
Episode.Details = (function(_super) {
__extends(Details, _super);
function Details() {
return Details.__super__.constructor.apply(this, arguments);
}
Details.prototype.template = 'apps/tvshow/episode/details_meta';
Details.prototype.triggers = {
'click .play': 'episode:play',
'click .add': 'episode:add',
'click .stream': 'episode:localplay',
'click .download': 'episode:download',
'click .edit': 'episode:edit',
'click .refresh': 'episode:refresh'
};
Details.prototype.attributes = function() {
return this.watchedAttributes();
};
return Details;
})(App.Views.DetailsItem);
Episode.EpisodeDetailTeaser = (function(_super) {
__extends(EpisodeDetailTeaser, _super);
function EpisodeDetailTeaser() {
return EpisodeDetailTeaser.__super__.constructor.apply(this, arguments);
}
EpisodeDetailTeaser.prototype.tagName = "div";
EpisodeDetailTeaser.prototype.triggers = {
"click .menu": "episode-menu:clicked"
};
EpisodeDetailTeaser.prototype.initialize = function() {
return this.model.set({
actions: {
thumbs: tr('Thumbs up')
}
});
};
EpisodeDetailTeaser.prototype.attributes = function() {
return this.watchedAttributes('card-detail');
};
return EpisodeDetailTeaser;
})(App.Views.CardView);
return Episode.Content = (function(_super) {
__extends(Content, _super);
function Content() {
return Content.__super__.constructor.apply(this, arguments);
}
Content.prototype.template = 'apps/tvshow/episode/content';
Content.prototype.className = "episode-content content-sections";
Content.prototype.regions = {
regionCast: '.region-cast',
regionSeason: '.region-season'
};
Content.prototype.modelEvents = {
'change': 'modelChange'
};
Content.prototype.modelChange = function() {
this.render();
return this.trigger('show');
};
return Content;
})(App.Views.LayoutView);
});
this.Kodi.module("TVShowApp.List", function(List, App, Backbone, Marionette, $, _) {
var API;
API = {
getTVShowsList: function(tvshows, set) {
var view, viewName;
if (set == null) {
set = false;
}
viewName = set ? 'TVShowsSet' : 'TVShows';
view = new List[viewName]({
collection: tvshows
});
API.bindTriggers(view);
return view;
},
bindTriggers: function(view) {
App.listenTo(view, 'childview:tvshow:play', function(parent, viewItem) {
return App.execute('tvshow:action', 'play', viewItem);
});
App.listenTo(view, 'childview:tvshow:add', function(parent, viewItem) {
return App.execute('tvshow:action', 'add', viewItem);
});
App.listenTo(view, 'childview:tvshow:watched', function(parent, viewItem) {
return App.execute('tvshow:action:watched', parent, viewItem);
});
return App.listenTo(view, 'childview:tvshow:edit', function(parent, viewItem) {
return App.execute('tvshow:edit', viewItem.model);
});
}
};
List.Controller = (function(_super) {
__extends(Controller, _super);
function Controller() {
return Controller.__super__.constructor.apply(this, arguments);
}
Controller.prototype.initialize = function() {
var collection;
collection = App.request("tvshow:entities");
collection.availableFilters = this.getAvailableFilters();
collection.sectionId = 'tvshows/recent';
App.request('filter:init', this.getAvailableFilters());
return App.execute("when:entity:fetched", collection, (function(_this) {
return function() {
_this.layout = _this.getLayoutView(collection);
_this.listenTo(_this.layout, "show", function() {
_this.getFiltersView(collection);
return _this.renderList(collection);
});
return App.regionContent.show(_this.layout);
};
})(this));
};
Controller.prototype.getLayoutView = function(tvshows) {
return new List.ListLayout({
collection: tvshows
});
};
Controller.prototype.getAvailableFilters = function() {
return {
sort: ['title', 'year', 'dateadded', 'rating', 'random'],
filter: ['year', 'genre', 'unwatched', 'inprogress', 'cast', 'mpaa', 'studio', 'thumbsUp']
};
};
Controller.prototype.getFiltersView = function(collection) {
var filters;
filters = App.request('filter:show', collection);
this.layout.regionSidebarFirst.show(filters);
return this.listenTo(filters, "filter:changed", (function(_this) {
return function() {
return _this.renderList(collection);
};
})(this));
};
Controller.prototype.renderList = function(collection) {
var filteredCollection, view;
App.execute("loading:show:view", this.layout.regionContent);
filteredCollection = App.request('filter:apply:entities', collection);
view = API.getTVShowsList(filteredCollection);
return this.layout.regionContent.show(view);
};
return Controller;
})(App.Controllers.Base);
return App.reqres.setHandler("tvshow:list:view", function(collection) {
return API.getTVShowsList(collection, true);
});
});
this.Kodi.module("TVShowApp.List", function(List, App, Backbone, Marionette, $, _) {
List.ListLayout = (function(_super) {
__extends(ListLayout, _super);
function ListLayout() {
return ListLayout.__super__.constructor.apply(this, arguments);
}
ListLayout.prototype.className = "tvshow-list with-filters";
return ListLayout;
})(App.Views.LayoutWithSidebarFirstView);
List.TVShowTeaser = (function(_super) {
__extends(TVShowTeaser, _super);
function TVShowTeaser() {
return TVShowTeaser.__super__.constructor.apply(this, arguments);
}
TVShowTeaser.prototype.triggers = {
"click .play": "tvshow:play",
"click .watched": "tvshow:watched",
"click .add": "tvshow:add",
"click .edit": "tvshow:edit"
};
TVShowTeaser.prototype.initialize = function() {
TVShowTeaser.__super__.initialize.apply(this, arguments);
this.setMeta();
return this.model.set(App.request('tvshow:action:items'));
};
TVShowTeaser.prototype.attributes = function() {
return this.watchedAttributes('card tv-show prevent-select');
};
TVShowTeaser.prototype.setMeta = function() {
if (this.model) {
return this.model.set({
subtitle: this.model.get('rating')
});
}
};
return TVShowTeaser;
})(App.Views.CardView);
List.Empty = (function(_super) {
__extends(Empty, _super);
function Empty() {
return Empty.__super__.constructor.apply(this, arguments);
}
Empty.prototype.tagName = "li";
Empty.prototype.className = "tvshow-empty-result";
return Empty;
})(App.Views.EmptyViewResults);
List.TVShows = (function(_super) {
__extends(TVShows, _super);
function TVShows() {
return TVShows.__super__.constructor.apply(this, arguments);
}
TVShows.prototype.childView = List.TVShowTeaser;
TVShows.prototype.emptyView = List.Empty;
TVShows.prototype.tagName = "ul";
TVShows.prototype.className = "card-grid--tall";
return TVShows;
})(App.Views.VirtualListView);
return List.TVShowsSet = (function(_super) {
__extends(TVShowsSet, _super);
function TVShowsSet() {
return TVShowsSet.__super__.constructor.apply(this, arguments);
}
TVShowsSet.prototype.childView = List.TVShowTeaser;
TVShowsSet.prototype.emptyView = List.Empty;
TVShowsSet.prototype.tagName = "ul";
TVShowsSet.prototype.className = "card-grid--tall";
return TVShowsSet;
})(App.Views.CollectionView);
});
this.Kodi.module("TVShowApp.Season", function(Season, App, Backbone, Marionette, $, _) {
var API;
API = {
getSeasonList: function(collection) {
var view;
view = new Season.Seasons({
collection: collection
});
return view;
},
bindTriggers: function(view) {
App.listenTo(view, 'season:play', function(view) {
return App.execute('tvshow:action', 'play', view);
});
App.listenTo(view, 'season:add', function(view) {
return App.execute('tvshow:action', 'add', view);
});
return App.listenTo(view, 'toggle:watched', function(view) {
return App.execute('tvshow:action:watched', view.view, view.view, true);
});
},
mergeSeasonDetails: function(tvshow, season, seasons) {
var attributes, mergeAttributes, prop, _i, _len;
mergeAttributes = ['season', 'thumbnail', 'episode', 'unwatched', 'playcount', 'progress', 'watchedepisodes'];
attributes = {
seasons: seasons,
type: 'season'
};
for (_i = 0, _len = mergeAttributes.length; _i < _len; _i++) {
prop = mergeAttributes[_i];
attributes[prop] = season.get(prop);
}
tvshow.set(attributes);
return tvshow;
}
};
Season.Controller = (function(_super) {
__extends(Controller, _super);
function Controller() {
return Controller.__super__.constructor.apply(this, arguments);
}
Controller.prototype.initialize = function(options) {
var id, seasonId, tvshow;
id = parseInt(options.id);
seasonId = parseInt(options.season);
tvshow = App.request("tvshow:entity", id);
return App.execute("when:entity:fetched", tvshow, (function(_this) {
return function() {
var seasons;
seasons = App.request("season:entities", tvshow.get('id'));
return App.execute("when:entity:fetched", seasons, function() {
var season;
season = seasons.findWhere({
season: seasonId
});
tvshow = API.mergeSeasonDetails(tvshow, season, seasons);
_this.layout = _this.getLayoutView(tvshow);
_this.listenTo(_this.layout, "show", function() {
_this.getDetailsLayoutView(tvshow);
return _this.getEpisodes(tvshow, seasonId);
});
return App.regionContent.show(_this.layout);
});
};
})(this));
};
Controller.prototype.getLayoutView = function(tvshow) {
return new Season.PageLayout({
model: tvshow
});
};
Controller.prototype.getDetailsLayoutView = function(tvshow) {
var headerLayout;
headerLayout = new Season.HeaderLayout({
model: tvshow
});
this.listenTo(headerLayout, "show", (function(_this) {
return function() {
var detail, teaser;
teaser = new Season.SeasonDetailTeaser({
model: tvshow
});
detail = new Season.Details({
model: tvshow
});
API.bindTriggers(detail);
headerLayout.regionSide.show(teaser);
return headerLayout.regionMeta.show(detail);
};
})(this));
return this.layout.regionHeader.show(headerLayout);
};
Controller.prototype.getEpisodes = function(tvshow, seasonId) {
var collection;
collection = App.request("episode:tvshow:entities", tvshow.get('tvshowid'), seasonId);
return App.execute("when:entity:fetched", collection, (function(_this) {
return function() {
var view;
collection.sortCollection('episode', 'asc');
view = App.request("episode:list:view", collection);
return _this.layout.regionContent.show(view);
};
})(this));
};
return Controller;
})(App.Controllers.Base);
return App.reqres.setHandler("season:list:view", function(collection) {
return API.getSeasonList(collection);
});
});
this.Kodi.module("TVShowApp.Season", function(Season, App, Backbone, Marionette, $, _) {
Season.SeasonTeaser = (function(_super) {
__extends(SeasonTeaser, _super);
function SeasonTeaser() {
return SeasonTeaser.__super__.constructor.apply(this, arguments);
}
SeasonTeaser.prototype.triggers = {
"click .play": "season:play",
"click .watched": "season:watched",
"click .add": "season:add"
};
SeasonTeaser.prototype.initialize = function() {
var subtitle;
SeasonTeaser.__super__.initialize.apply(this, arguments);
subtitle = this.model.get('episode') + ' ' + tr('episodes');
this.model.set({
subtitle: subtitle
});
this.model.set(App.request('tvshow:action:items'));
return this.model.set({
label: tr('Season') + ' ' + this.model.get('season')
});
};
SeasonTeaser.prototype.attributes = function() {
return this.watchedAttributes('card tv-season prevent-select');
};
return SeasonTeaser;
})(App.Views.CardView);
Season.Empty = (function(_super) {
__extends(Empty, _super);
function Empty() {
return Empty.__super__.constructor.apply(this, arguments);
}
Empty.prototype.tagName = "li";
Empty.prototype.className = "season-empty-result";
return Empty;
})(App.Views.EmptyViewResults);
Season.Seasons = (function(_super) {
__extends(Seasons, _super);
function Seasons() {
return Seasons.__super__.constructor.apply(this, arguments);
}
Seasons.prototype.childView = Season.SeasonTeaser;
Seasons.prototype.emptyView = Season.Empty;
Seasons.prototype.tagName = "ul";
Seasons.prototype.className = "card-grid--tall";
return Seasons;
})(App.Views.CollectionView);
Season.PageLayout = (function(_super) {
__extends(PageLayout, _super);
function PageLayout() {
return PageLayout.__super__.constructor.apply(this, arguments);
}
PageLayout.prototype.className = 'season-show tv-collection detail-container';
return PageLayout;
})(App.Views.LayoutWithHeaderView);
Season.HeaderLayout = (function(_super) {
__extends(HeaderLayout, _super);
function HeaderLayout() {
return HeaderLayout.__super__.constructor.apply(this, arguments);
}
HeaderLayout.prototype.className = 'season-details';
return HeaderLayout;
})(App.Views.LayoutDetailsHeaderView);
Season.Details = (function(_super) {
__extends(Details, _super);
function Details() {
return Details.__super__.constructor.apply(this, arguments);
}
Details.prototype.template = 'apps/tvshow/season/details_meta';
Details.prototype.triggers = {
"click .play": "season:play",
"click .add": "season:add"
};
Details.prototype.attributes = function() {
return this.watchedAttributes('details-meta');
};
return Details;
})(App.Views.DetailsItem);
return Season.SeasonDetailTeaser = (function(_super) {
__extends(SeasonDetailTeaser, _super);
function SeasonDetailTeaser() {
return SeasonDetailTeaser.__super__.constructor.apply(this, arguments);
}
SeasonDetailTeaser.prototype.tagName = "div";
SeasonDetailTeaser.prototype.className = "card-detail";
return SeasonDetailTeaser;
})(App.Views.CardView);
});
this.Kodi.module("TVShowApp.Show", function(Show, App, Backbone, Marionette, $, _) {
var API;
API = {
bindTriggersTVShow: function(view) {
App.listenTo(view, 'tvshow:play', function(view) {
return App.execute('tvshow:action', 'play', view);
});
App.listenTo(view, 'tvshow:add', function(view) {
return App.execute('tvshow:action', 'add', view);
});
App.listenTo(view, 'toggle:watched', function(view) {
return App.execute('tvshow:action:watched', view.view, view.view, true);
});
App.listenTo(view, 'tvshow:refresh', function(view) {
return App.execute('tvshow:action', 'refresh', view);
});
App.listenTo(view, 'tvshow:refresh:episodes', function(view) {
return App.execute('tvshow:action', 'refreshEpisodes', view);
});
return App.listenTo(view, 'tvshow:edit', function(view) {
return App.execute('tvshow:edit', view.model);
});
},
bindTriggersTVSeason: function(view) {
App.listenTo(view, 'childview:season:play', function(parent, viewItem) {
return App.execute('tvshow:action', 'play', viewItem);
});
App.listenTo(view, 'childview:season:add', function(parent, viewItem) {
return App.execute('tvshow:action', 'add', viewItem);
});
return App.listenTo(view, 'childview:season:watched', function(parent, viewItem) {
return App.execute('tvshow:action:watched', parent, viewItem, false);
});
}
};
return Show.Controller = (function(_super) {
__extends(Controller, _super);
function Controller() {
return Controller.__super__.constructor.apply(this, arguments);
}
Controller.prototype.initialize = function(options) {
var id, tvshow;
id = parseInt(options.id);
tvshow = App.request("tvshow:entity", id);
return App.execute("when:entity:fetched", tvshow, (function(_this) {
return function() {
_this.layout = _this.getLayoutView(tvshow);
_this.listenTo(_this.layout, "destroy", function() {
return App.execute("images:fanart:set", 'none');
});
_this.listenTo(_this.layout, "show", function() {
_this.getDetailsLayoutView(tvshow);
return _this.getSeasons(tvshow);
});
return App.regionContent.show(_this.layout);
};
})(this));
};
Controller.prototype.getLayoutView = function(tvshow) {
return new Show.PageLayout({
model: tvshow
});
};
Controller.prototype.getDetailsLayoutView = function(tvshow) {
var headerLayout;
headerLayout = new Show.HeaderLayout({
model: tvshow
});
this.listenTo(headerLayout, "show", (function(_this) {
return function() {
var detail, teaser;
teaser = new Show.TVShowTeaser({
model: tvshow
});
detail = new Show.Details({
model: tvshow
});
API.bindTriggersTVShow(detail);
API.bindTriggersTVShow(teaser);
headerLayout.regionSide.show(teaser);
return headerLayout.regionMeta.show(detail);
};
})(this));
return this.layout.regionHeader.show(headerLayout);
};
Controller.prototype.getSeasons = function(tvshow) {
var collection;
collection = App.request("season:entities", tvshow.get('tvshowid'));
return App.execute("when:entity:fetched", collection, (function(_this) {
return function() {
var view;
view = App.request("season:list:view", collection);
API.bindTriggersTVSeason(view);
if (_this.layout.regionContent) {
_this.layout.regionContent.show(view);
return App.vent.on('entity:kodi:update', function(uid) {
if (tvshow.get('uid') === uid) {
return _this.getSeasons(tvshow);
}
});
}
};
})(this));
};
return Controller;
})(App.Controllers.Base);
});
this.Kodi.module("TVShowApp.Show", function(Show, App, Backbone, Marionette, $, _) {
Show.PageLayout = (function(_super) {
__extends(PageLayout, _super);
function PageLayout() {
return PageLayout.__super__.constructor.apply(this, arguments);
}
PageLayout.prototype.className = 'tvshow-show tv-collection detail-container';
return PageLayout;
})(App.Views.LayoutWithHeaderView);
Show.HeaderLayout = (function(_super) {
__extends(HeaderLayout, _super);
function HeaderLayout() {
return HeaderLayout.__super__.constructor.apply(this, arguments);
}
HeaderLayout.prototype.className = 'tvshow-details';
return HeaderLayout;
})(App.Views.LayoutDetailsHeaderView);
Show.Details = (function(_super) {
__extends(Details, _super);
function Details() {
return Details.__super__.constructor.apply(this, arguments);
}
Details.prototype.template = 'apps/tvshow/show/details_meta';
Details.prototype.triggers = {
"click .play": "tvshow:play",
"click .add": "tvshow:add",
"click .edit": "tvshow:edit",
"click .refresh": "tvshow:refresh",
"click .refresh-episodes": "tvshow:refresh:episodes"
};
Details.prototype.attributes = function() {
return this.watchedAttributes('details-meta');
};
return Details;
})(App.Views.DetailsItem);
return Show.TVShowTeaser = (function(_super) {
__extends(TVShowTeaser, _super);
function TVShowTeaser() {
return TVShowTeaser.__super__.constructor.apply(this, arguments);
}
TVShowTeaser.prototype.tagName = "div";
TVShowTeaser.prototype.triggers = {
"click .play": "tvshow:play"
};
TVShowTeaser.prototype.initialize = function() {
return this.model.set({
actions: {
thumbs: tr('Thumbs up')
}
});
};
TVShowTeaser.prototype.attributes = function() {
return this.watchedAttributes('card-detail');
};
return TVShowTeaser;
})(App.Views.CardView);
});
this.Kodi.module("TVShowApp", function(TVShowApp, App, Backbone, Marionette, $, _) {
var API;
TVShowApp.Router = (function(_super) {
__extends(Router, _super);
function Router() {
return Router.__super__.constructor.apply(this, arguments);
}
Router.prototype.appRoutes = {
"tvshows": "list",
"tvshow/:tvshowid": "view",
"tvshow/:tvshowid/:season": "season",
"tvshow/:tvshowid/:season/:episodeid": "episode"
};
return Router;
})(App.Router.Base);
API = {
list: function() {
return new TVShowApp.List.Controller();
},
view: function(tvshowid) {
return new TVShowApp.Show.Controller({
id: tvshowid
});
},
season: function(tvshowid, season) {
return new TVShowApp.Season.Controller({
id: tvshowid,
season: season
});
},
episode: function(tvshowid, season, episodeid) {
return new TVShowApp.Episode.Controller({
id: tvshowid,
season: season,
episodeid: episodeid
});
},
toggleWatched: function(model, season, op) {
if (season == null) {
season = 'all';
}
return API.getAllEpisodesCollection(model.get('tvshowid'), season, function(collection) {
var videoLib;
videoLib = App.request("command:kodi:controller", 'video', 'VideoLibrary');
return videoLib.toggleWatchedCollection(collection, op);
});
},
toggleWatchedUiState: function($el, setChildren) {
var $layout, classOp, op, progress, unwatched;
if (setChildren == null) {
setChildren = true;
}
op = $el.hasClass('is-watched') ? 'unwatched' : 'watched';
classOp = op === 'watched' ? 'addClass' : 'removeClass';
progress = op === 'watched' ? 100 : 0;
$el[classOp]('is-watched');
helpers.entities.setProgress($el, progress);
$layout = $el.closest('.tv-collection');
if (setChildren) {
$layout.find('.region-content .card')[classOp]('is-watched');
helpers.entities.setProgress($layout, progress);
}
unwatched = parseInt($layout.find('.episode-total').text()) - $layout.find('.region-content .is-watched').length;
$layout.find('.episode-unwatched').html(unwatched);
return $layout;
},
getAllEpisodesCollection: function(tvshowid, season, callback) {
var collectionAll;
collectionAll = App.request("episode:tvshow:entities", tvshowid, season);
return App.execute("when:entity:fetched", collectionAll, (function(_this) {
return function() {
return callback(collectionAll);
};
})(this));
},
episodeAction: function(op, view) {
var files, model, playlist, videoLib;
model = view.model;
playlist = App.request("command:kodi:controller", 'video', 'PlayList');
files = App.request("command:kodi:controller", 'video', 'Files');
videoLib = App.request("command:kodi:controller", 'video', 'VideoLibrary');
switch (op) {
case 'play':
return App.execute("input:resume", model, 'episodeid');
case 'add':
return playlist.add('episodeid', model.get('episodeid'));
case 'localplay':
return files.videoStream(model.get('file'), model.get('fanart'));
case 'download':
return files.downloadFile(model.get('file'));
case 'toggleWatched':
return videoLib.toggleWatched(model, 'auto');
case 'gotoSeason':
return App.navigate("#tvshow/" + model.get('tvshowid') + '/' + model.get('season'), {
trigger: true
});
case 'refresh':
return helpers.entities.refreshEntity(model, videoLib, 'refreshEpisode');
}
},
tvShowAction: function(op, view) {
var model, playlist, season, videoLib;
model = view.model;
playlist = App.request("command:kodi:controller", 'video', 'PlayList');
season = model.get('type') === 'season' ? model.get('season') : 'all';
videoLib = App.request("command:kodi:controller", 'video', 'VideoLibrary');
switch (op) {
case 'play':
return API.getAllEpisodesCollection(model.get('tvshowid'), season, function(collection) {
return playlist.playCollection(collection);
});
case 'add':
return API.getAllEpisodesCollection(model.get('tvshowid'), season, function(collection) {
return playlist.addCollection(collection);
});
case 'watched':
return API.toggleWatched(model, season, op);
case 'unwatched':
return API.toggleWatched(model, season, op);
case 'edit':
return App.execute('tvshow:edit', model);
case 'refresh':
return helpers.entities.refreshEntity(model, videoLib, 'refreshTVShow');
case 'refreshEpisodes':
return helpers.entities.refreshEntity(model, videoLib, 'refreshTVShow', {
refreshepisodes: true
});
}
}
};
App.commands.setHandler('episode:action', function(op, view) {
return API.episodeAction(op, view);
});
App.commands.setHandler('tvshow:action', function(op, view) {
return API.tvShowAction(op, view);
});
App.reqres.setHandler('episode:action:items', function() {
return {
actions: {
watched: tr('Watched'),
thumbs: tr('Thumbs up')
},
menu: {
'add': tr('Queue in Kodi'),
'divider-1': '',
'download': tr('Download'),
'localplay': tr('Play in browser'),
'divider-2': '',
'goto-season': tr('Go to season'),
'divider-3': '',
'edit': tr('Edit')
}
};
});
App.reqres.setHandler('tvshow:action:items', function() {
return {
actions: {
watched: tr('Watched'),
thumbs: tr('Thumbs up')
},
menu: {
add: tr('Queue in Kodi'),
'divider-': '',
'edit': tr('Edit')
}
};
});
App.commands.setHandler('tvshow:action:watched', function(parent, viewItem, setChildren) {
var msg, op;
if (setChildren == null) {
setChildren = false;
}
op = parent.$el.hasClass('is-watched') ? 'unwatched' : 'watched';
if (viewItem.model.get('type') === 'season') {
msg = tr('Set all episodes for this season as') + ' ' + tr(op);
} else {
msg = tr('Set all episodes for this TV show as') + ' ' + tr(op);
}
return App.execute("ui:modal:confirm", tr('Are you sure?'), msg, function() {
API.toggleWatchedUiState(parent.$el, setChildren);
return API.tvShowAction(op, viewItem);
});
});
App.commands.setHandler('episode:action:watched', function(parent, viewItem) {
API.toggleWatchedUiState(parent.$el, false);
return API.episodeAction('toggleWatched', viewItem);
});
App.commands.setHandler('tvshow:edit', function(model) {
var loadedModel;
loadedModel = App.request("tvshow:entity", model.get('id'));
return App.execute("when:entity:fetched", loadedModel, (function(_this) {
return function() {
return new TVShowApp.EditShow.Controller({
model: loadedModel
});
};
})(this));
});
App.commands.setHandler('episode:edit', function(model) {
var loadedModel;
loadedModel = App.request("episode:entity", model.get('id'));
return App.execute("when:entity:fetched", loadedModel, (function(_this) {
return function() {
return new TVShowApp.EditEpisode.Controller({
model: loadedModel
});
};
})(this));
});
return App.on("before:start", function() {
return new TVShowApp.Router({
controller: API
});
});
});
this.Kodi.module("UiApp", function(UiApp, App, Backbone, Marionette, $, _) {
var API;
API = {
openModal: function(title, msg, open, style) {
var $body, $modal, $title;
if (open == null) {
open = true;
}
if (style == null) {
style = '';
}
$title = App.getRegion('regionModalTitle').$el;
$body = App.getRegion('regionModalBody').$el;
$modal = App.getRegion('regionModal').$el;
$modal.removeClassStartsWith('style-');
$modal.addClass('style-' + style);
$title.html(title);
$body.html(msg);
if (open) {
$modal.modal();
}
$modal.on('hidden.bs.modal', function(e) {
return $body.html('');
});
return $modal;
},
closeModal: function() {
App.getRegion('regionModal').$el.modal('hide');
return $('.modal-body').html('');
},
closeModalButton: function(text) {
if (text == null) {
text = 'close';
}
return API.getButton(t.gettext(text), 'default').on('click', function() {
return API.closeModal();
});
},
getModalButtonContainer: function() {
return App.getRegion('regionModalFooter').$el.empty();
},
getButton: function(text, type) {
if (type == null) {
type = 'primary';
}
return $('
').addClass('btn btn-' + type).html(text);
},
defaultButtons: function(callback) {
var $ok;
$ok = API.getButton(t.gettext('ok'), 'primary').on('click', function() {
if (callback) {
callback();
}
return API.closeModal();
});
return API.getModalButtonContainer().append(API.closeModalButton()).append($ok);
},
confirmButtons: function(callback) {
var $ok;
$ok = API.getButton(t.gettext('yes'), 'primary').on('click', function() {
if (callback) {
callback();
}
return API.closeModal();
});
return API.getModalButtonContainer().append(API.closeModalButton('no')).append($ok);
},
playerMenu: function(op) {
var $el, openClass;
if (op == null) {
op = 'toggle';
}
$el = $('.player-menu-wrapper');
openClass = 'opened';
switch (op) {
case 'open':
return $el.addClass(openClass);
case 'close':
return $el.removeClass(openClass);
default:
return $el.toggleClass(openClass);
}
},
buildOptions: function(options) {
var $newOption, $option, $wrap, option, _i, _len;
if (options.length === 0) {
return;
}
$wrap = $('').addClass('modal-options options-list');
$option = $('');
for (_i = 0, _len = options.length; _i < _len; _i++) {
option = options[_i];
$newOption = $option.clone();
$newOption.html(option);
$newOption.click(function(e) {
API.closeModal();
return $(this).closest('ul').find('li, span').unbind('click');
});
$wrap.append($newOption);
}
return $wrap;
}
};
App.commands.setHandler("ui:textinput:show", function(title, options, callback) {
var $input, $msg, el, msg, open, val;
if (options == null) {
options = {};
}
msg = options.msg ? options.msg : '';
open = options.open ? true : false;
val = options.defaultVal ? options.defaultVal : '';
$input = $(' ', {
id: 'text-input',
"class": 'form-control',
type: 'text',
value: val
}).on('keyup', function(e) {
if (e.keyCode === 13 && callback) {
callback($('#text-input').val());
return API.closeModal();
}
});
$msg = $('').html(msg);
API.defaultButtons(function() {
return callback($('#text-input').val());
});
API.openModal(title, $msg, callback, open);
el = App.getRegion('regionModalBody').$el.append($input.wrap('
'));
setTimeout(function() {
return el.find('input').first().focus();
}, 200);
return $.material.init();
});
App.commands.setHandler("ui:modal:close", function() {
return API.closeModal();
});
App.commands.setHandler("ui:modal:confirm", function(title, msg, callback) {
if (msg == null) {
msg = '';
}
API.confirmButtons(function() {
return callback(true);
});
return API.openModal(title, msg, true, 'confirm');
});
App.commands.setHandler("ui:modal:show", function(title, msg, footer, closeButton, style) {
if (msg == null) {
msg = '';
}
if (footer == null) {
footer = '';
}
if (closeButton == null) {
closeButton = false;
}
if (style == null) {
style = '';
}
API.getModalButtonContainer().html(footer);
if (closeButton) {
API.getModalButtonContainer().prepend(API.closeModalButton());
}
return API.openModal(title, msg, true, style);
});
App.commands.setHandler("ui:modal:form:show", function(title, msg, style) {
if (msg == null) {
msg = '';
}
if (style == null) {
style = 'form';
}
return API.openModal(title, msg, true, style);
});
App.commands.setHandler("ui:modal:close", function() {
return API.closeModal();
});
App.commands.setHandler("ui:modal:youtube", function(title, videoid) {
var msg;
API.getModalButtonContainer().html('');
msg = 'VIDEO ';
return API.openModal(title, msg, true, 'video');
});
App.commands.setHandler("ui:modal:options", function(title, items) {
var $options;
$options = API.buildOptions(items);
return API.openModal(title, $options, true, 'options');
});
App.commands.setHandler("ui:playermenu", function(op) {
return API.playerMenu(op);
});
App.commands.setHandler("ui:dropdown:bind:close", function($el) {
return $el.on("click", '.dropdown-menu li, .dropdown-menu a', function(e) {
return $(e.target).closest('.dropdown-menu').parent().removeClass('open').trigger('hide.bs.dropdown');
});
});
return App.vent.on("shell:ready", (function(_this) {
return function(options) {
return $('html').on('click', function() {
return API.playerMenu('close');
});
};
})(this));
});