Fillers can be set up to import playlists or collections from Plex automatically. Filler Service refactor.
This commit is contained in:
parent
caf3b3b72c
commit
2541e42513
10
index.js
10
index.js
@ -17,6 +17,7 @@ const HDHR = require('./src/hdhr')
|
||||
const FileCacheService = require('./src/services/file-cache-service');
|
||||
const CacheImageService = require('./src/services/cache-image-service');
|
||||
const ChannelService = require("./src/services/channel-service");
|
||||
const FillerService = require("./src/services/filler-service");
|
||||
|
||||
const xmltv = require('./src/xmltv')
|
||||
const Plex = require('./src/plex');
|
||||
@ -104,7 +105,7 @@ initDB(db, channelDB)
|
||||
|
||||
channelService = new ChannelService(channelDB);
|
||||
|
||||
fillerDB = new FillerDB( path.join(process.env.DATABASE, 'filler') , channelService );
|
||||
let fillerDB = new FillerDB( path.join(process.env.DATABASE, 'filler') );
|
||||
customShowDB = new CustomShowDB( path.join(process.env.DATABASE, 'custom-shows') );
|
||||
let programPlayTimeDB = new ProgramPlayTimeDB( path.join(process.env.DATABASE, 'play-cache') );
|
||||
let ffmpegSettingsService = new FfmpegSettingsService(db);
|
||||
@ -134,6 +135,9 @@ activeChannelService = new ActiveChannelService(onDemandService, channelService)
|
||||
|
||||
eventService = new EventService();
|
||||
|
||||
let fillerService = new FillerService(fillerDB, plexProxyService,
|
||||
channelService);
|
||||
|
||||
i18next
|
||||
.use(i18nextBackend)
|
||||
.use(i18nextMiddleware.LanguageDetector)
|
||||
@ -323,12 +327,12 @@ app.use('/favicon.svg', express.static(
|
||||
app.use('/custom.css', express.static(path.join(process.env.DATABASE, 'custom.css')))
|
||||
|
||||
// API Routers
|
||||
app.use(api.router(db, channelService, fillerDB, customShowDB, xmltvInterval, guideService, m3uService, eventService, ffmpegSettingsService, plexServerDB, plexProxyService, ffmpegInfo))
|
||||
app.use(api.router(db, channelService, fillerDB, customShowDB, xmltvInterval, guideService, m3uService, eventService, ffmpegSettingsService, plexServerDB, plexProxyService, ffmpegInfo, fillerService))
|
||||
app.use('/api/cache/images', cacheImageService.apiRouters())
|
||||
app.use('/' + fontAwesome, express.static(path.join(process.env.DATABASE, fontAwesome)))
|
||||
app.use('/' + bootstrap, express.static(path.join(process.env.DATABASE, bootstrap)))
|
||||
|
||||
app.use(video.router( channelService, fillerDB, db, programmingService, activeChannelService, programPlayTimeDB, ffmpegInfo ))
|
||||
app.use(video.router( channelService, fillerService, db, programmingService, activeChannelService, programPlayTimeDB, ffmpegInfo ))
|
||||
app.use(hdhr.router)
|
||||
app.listen(process.env.PORT, () => {
|
||||
console.log(`HTTP server running on port: http://*:${process.env.PORT}`)
|
||||
|
||||
10
src/api.js
10
src/api.js
@ -22,7 +22,7 @@ function safeString(object) {
|
||||
}
|
||||
|
||||
module.exports = { router: api }
|
||||
function api(db, channelService, fillerDB, customShowDB, xmltvInterval, guideService, _m3uService, eventService, ffmpegSettingsService, plexServerDB, plexProxyService, ffmpegInfo ) {
|
||||
function api(db, channelService, fillerDB, customShowDB, xmltvInterval, guideService, _m3uService, eventService, ffmpegSettingsService, plexServerDB, plexProxyService, ffmpegInfo, fillerService ) {
|
||||
let m3uService = _m3uService;
|
||||
const router = express.Router()
|
||||
|
||||
@ -419,7 +419,7 @@ function api(db, channelService, fillerDB, customShowDB, xmltvInterval, guideSe
|
||||
if (typeof(id) === 'undefined') {
|
||||
return res.status(400).send("Missing id");
|
||||
}
|
||||
await fillerDB.saveFiller(id, req.body );
|
||||
await fillerService.saveFiller(id, req.body );
|
||||
return res.status(204).send({});
|
||||
} catch(err) {
|
||||
console.error(err);
|
||||
@ -428,7 +428,7 @@ function api(db, channelService, fillerDB, customShowDB, xmltvInterval, guideSe
|
||||
})
|
||||
router.put('/api/filler', async (req, res) => {
|
||||
try {
|
||||
let uuid = await fillerDB.createFiller(req.body );
|
||||
let uuid = await fillerService.createFiller(req.body );
|
||||
return res.status(201).send({id: uuid});
|
||||
} catch(err) {
|
||||
console.error(err);
|
||||
@ -441,7 +441,7 @@ function api(db, channelService, fillerDB, customShowDB, xmltvInterval, guideSe
|
||||
if (typeof(id) === 'undefined') {
|
||||
return res.status(400).send("Missing id");
|
||||
}
|
||||
await fillerDB.deleteFiller(id);
|
||||
await fillerService.deleteFiller(id);
|
||||
return res.status(204).send({});
|
||||
} catch(err) {
|
||||
console.error(err);
|
||||
@ -455,7 +455,7 @@ function api(db, channelService, fillerDB, customShowDB, xmltvInterval, guideSe
|
||||
if (typeof(id) === 'undefined') {
|
||||
return res.status(400).send("Missing id");
|
||||
}
|
||||
let channels = await fillerDB.getFillerChannels(id);
|
||||
let channels = await fillerService.getFillerChannels(id);
|
||||
if (channels == null) {
|
||||
return res.status(404).send("Filler not found");
|
||||
}
|
||||
|
||||
@ -4,12 +4,9 @@ let fs = require('fs');
|
||||
|
||||
class FillerDB {
|
||||
|
||||
constructor(folder, channelService) {
|
||||
constructor(folder) {
|
||||
this.folder = folder;
|
||||
this.cache = {};
|
||||
this.channelService = channelService;
|
||||
|
||||
|
||||
}
|
||||
|
||||
async $loadFiller(id) {
|
||||
@ -77,40 +74,8 @@ class FillerDB {
|
||||
return id;
|
||||
}
|
||||
|
||||
async getFillerChannels(id) {
|
||||
let numbers = await this.channelService.getAllChannelNumbers();
|
||||
let channels = [];
|
||||
await Promise.all( numbers.map( async(number) => {
|
||||
let ch = await this.channelService.getChannel(number);
|
||||
let name = ch.name;
|
||||
let fillerCollections = ch.fillerCollections;
|
||||
for (let i = 0 ; i < fillerCollections.length; i++) {
|
||||
if (fillerCollections[i].id === id) {
|
||||
channels.push( {
|
||||
number: number,
|
||||
name : name,
|
||||
} );
|
||||
break;
|
||||
}
|
||||
}
|
||||
ch = null;
|
||||
|
||||
} ) );
|
||||
return channels;
|
||||
}
|
||||
|
||||
async deleteFiller(id) {
|
||||
try {
|
||||
let channels = await this.getFillerChannels(id);
|
||||
await Promise.all( channels.map( async(channel) => {
|
||||
console.log(`Updating channel ${channel.number} , remove filler: ${id}`);
|
||||
let json = await channelService.getChannel(channel.number);
|
||||
json.fillerCollections = json.fillerCollections.filter( (col) => {
|
||||
return col.id != id;
|
||||
} );
|
||||
await this.channelService.saveChannel( channel.number, json );
|
||||
} ) );
|
||||
|
||||
let f = path.join(this.folder, `${id}.json` );
|
||||
await new Promise( (resolve, reject) => {
|
||||
fs.unlink(f, function (err) {
|
||||
@ -162,27 +127,6 @@ class FillerDB {
|
||||
} );
|
||||
}
|
||||
|
||||
async getFillersFromChannel(channel) {
|
||||
|
||||
let loadChannelFiller = async(fillerEntry) => {
|
||||
let content = [];
|
||||
try {
|
||||
let filler = await this.getFiller(fillerEntry.id);
|
||||
content = filler.content;
|
||||
} catch(e) {
|
||||
console.error(`Channel #${channel.number} - ${channel.name} references an unattainable filler id: ${fillerEntry.id}`);
|
||||
}
|
||||
return {
|
||||
id: fillerEntry.id,
|
||||
content: content,
|
||||
weight: fillerEntry.weight,
|
||||
cooldown: fillerEntry.cooldown,
|
||||
}
|
||||
};
|
||||
return await Promise.all(
|
||||
channel.fillerCollections.map(loadChannelFiller)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -20,7 +20,7 @@
|
||||
const path = require('path');
|
||||
var fs = require('fs');
|
||||
|
||||
const TARGET_VERSION = 900;
|
||||
const TARGET_VERSION = 1000;
|
||||
|
||||
const STEPS = [
|
||||
// [v, v2, x] : if the current version is v, call x(db), and version becomes v2
|
||||
@ -46,6 +46,7 @@ const STEPS = [
|
||||
[ 803, 900, (db) => fixFFMpegPathSetting(db) ],
|
||||
[ 804, 900, (db) => fixFFMpegPathSetting(db) ],
|
||||
[ 805, 900, (db) => fixFFMpegPathSetting(db) ],
|
||||
[ 900, 1000, () => fixFillerModes() ],
|
||||
]
|
||||
|
||||
const { v4: uuidv4 } = require('uuid');
|
||||
@ -679,6 +680,25 @@ function extractFillersFromChannels() {
|
||||
|
||||
}
|
||||
|
||||
function fixFillerModes() {
|
||||
console.log("Fixing filler modes...");
|
||||
let fillers = path.join(process.env.DATABASE, 'filler');
|
||||
let fillerFiles = fs.readdirSync(fillers);
|
||||
|
||||
for (let i = 0; i < fillerFiles.length; i++) {
|
||||
if (path.extname( fillerFiles[i] ) === '.json') {
|
||||
console.log("Migrating filler : " + fillerFiles[i] +"..." );
|
||||
let fillerPath = path.join(fillers, fillerFiles[i]);
|
||||
let filler = JSON.parse(fs.readFileSync(fillerPath, 'utf-8'));
|
||||
if ( typeof(filler.mode) !== "string" ) {
|
||||
filler.mode = "custom";
|
||||
}
|
||||
fs.writeFileSync( fillerPath, JSON.stringify(filler), 'utf-8');
|
||||
}
|
||||
}
|
||||
console.log("Done fixing filler modes.");
|
||||
}
|
||||
|
||||
function addFPS(db) {
|
||||
let ffmpegSettings = db['ffmpeg-settings'].find()[0];
|
||||
let f = path.join(process.env.DATABASE, 'ffmpeg-settings.json');
|
||||
|
||||
150
src/services/filler-service.js
Normal file
150
src/services/filler-service.js
Normal file
@ -0,0 +1,150 @@
|
||||
const events = require('events')
|
||||
|
||||
const FILLER_UPDATE = 30 * 60 * 1000; //30 minutes might be too aggressive
|
||||
//this will be configurable one day.
|
||||
|
||||
class FillerService extends events.EventEmitter {
|
||||
|
||||
constructor(fillerDB, plexProxyService, channelService) {
|
||||
super();
|
||||
this.fillerDB = fillerDB;
|
||||
this.plexProxyService = plexProxyService;
|
||||
this.channelService = channelService;
|
||||
}
|
||||
|
||||
async saveFiller(id, body) {
|
||||
body = await this.prework(body);
|
||||
return this.fillerDB.saveFiller(id, body);
|
||||
}
|
||||
|
||||
async createFiller(body) {
|
||||
body = await this.prework(body);
|
||||
return this.fillerDB.createFiller(body);
|
||||
}
|
||||
|
||||
async getFillerChannels(id) {
|
||||
let numbers = await this.channelService.getAllChannelNumbers();
|
||||
let channels = [];
|
||||
await Promise.all( numbers.map( async(number) => {
|
||||
let ch = await this.channelService.getChannel(number);
|
||||
let name = ch.name;
|
||||
let fillerCollections = ch.fillerCollections;
|
||||
for (let i = 0 ; i < fillerCollections.length; i++) {
|
||||
if (fillerCollections[i].id === id) {
|
||||
channels.push( {
|
||||
number: number,
|
||||
name : name,
|
||||
} );
|
||||
break;
|
||||
}
|
||||
}
|
||||
ch = null;
|
||||
|
||||
} ) );
|
||||
return channels;
|
||||
}
|
||||
|
||||
async deleteFiller(id) {
|
||||
try {
|
||||
let channels = await this.getFillerChannels(id);
|
||||
await Promise.all( channels.map( async(channel) => {
|
||||
console.log(`Updating channel ${channel.number} , remove filler: ${id}`);
|
||||
let json = await channelService.getChannel(channel.number);
|
||||
json.fillerCollections = json.fillerCollections.filter( (col) => {
|
||||
return col.id != id;
|
||||
} );
|
||||
await this.channelService.saveChannel( channel.number, json );
|
||||
} ) );
|
||||
} finally {
|
||||
await this.fillerDB.deleteFiller(id);
|
||||
}
|
||||
}
|
||||
|
||||
async prework(body) {
|
||||
if (body.mode === "import") {
|
||||
body.content = await this.getContents(body);
|
||||
body.import.lastRefreshTime = new Date().getTime();
|
||||
} else {
|
||||
delete body.import;
|
||||
}
|
||||
return body;
|
||||
}
|
||||
|
||||
async getContents(body) {
|
||||
let serverKey = body.import.serverName;
|
||||
let key = body.import.key;
|
||||
let content = await this.plexProxyService.getKeyMediaContents(serverKey, key);
|
||||
console.log(JSON.stringify(content));
|
||||
return content;
|
||||
}
|
||||
|
||||
async getFillersFromChannel(channel) {
|
||||
|
||||
let loadChannelFiller = async(fillerEntry) => {
|
||||
let content = [];
|
||||
try {
|
||||
let filler = await this.fillerDB.getFiller(fillerEntry.id);
|
||||
await this.fillerUsageWatcher(fillerEntry.id, filler);
|
||||
content = filler.content;
|
||||
} catch(e) {
|
||||
console.error(`Channel #${channel.number} - ${channel.name} references an unattainable filler id: ${fillerEntry.id}`, e);
|
||||
}
|
||||
return {
|
||||
id: fillerEntry.id,
|
||||
content: content,
|
||||
weight: fillerEntry.weight,
|
||||
cooldown: fillerEntry.cooldown,
|
||||
}
|
||||
};
|
||||
return await Promise.all(
|
||||
channel.fillerCollections.map(loadChannelFiller)
|
||||
);
|
||||
}
|
||||
|
||||
async fillerUsageWatcher(id, filler) {
|
||||
if (filler.mode === "import") {
|
||||
//I need to upgrade nodejs version ASAP
|
||||
let lastTime = 0;
|
||||
if (
|
||||
(typeof(filler.import) !== "undefined")
|
||||
&&
|
||||
!isNaN(filler.import.lastRefreshTime)
|
||||
) {
|
||||
lastTime = filler.import.lastRefreshTime;
|
||||
}
|
||||
let t = new Date().getTime();
|
||||
if ( t - lastTime >= FILLER_UPDATE) {
|
||||
//time to do an update.
|
||||
if ( (typeof(filler.content) === "undefined")
|
||||
|| (filler.content.length == 0)
|
||||
) {
|
||||
//It should probably be an sync update...
|
||||
await this.refreshFiller(id);
|
||||
} else {
|
||||
this.refreshFiller(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async refreshFiller(id) {
|
||||
let t0 = new Date().getTime();
|
||||
console.log(`Refreshing filler with id=${id}`);
|
||||
try {
|
||||
let filler = await this.fillerDB.getFiller(id);
|
||||
await this.saveFiller(id, filler);
|
||||
} catch (err) {
|
||||
console.log(`Unable to update filler: ${id}`, err);
|
||||
} finally {
|
||||
let t1 = new Date().getTime();
|
||||
console.log(`Refreshed filler with id=${id} in ${t1-t0}ms`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
module.exports = FillerService
|
||||
@ -9,22 +9,86 @@ class PlexProxyService extends events.EventEmitter {
|
||||
}
|
||||
|
||||
async get(serverName64, path) {
|
||||
let plexServer = await getPlexServer(this.plexServerDB, serverName64);
|
||||
let plexServer = await getPlexServer64(this.plexServerDB, serverName64);
|
||||
// A potential area of improvement is to reuse the client when possible
|
||||
let client = new Plex(plexServer);
|
||||
return { MediaContainer: await client.Get("/" + path) };
|
||||
}
|
||||
|
||||
async getKeyMediaContents(serverName, key) {
|
||||
let plexServer = await getPlexServer(this.plexServerDB, serverName);
|
||||
let client = new Plex(plexServer);
|
||||
let obj = { MediaContainer: await client.Get(key) };
|
||||
let metadata = obj.MediaContainer.Metadata;
|
||||
if ( typeof(metadata) !== "object") {
|
||||
return [];
|
||||
}
|
||||
metadata = metadata.map( (item) => fillerMapper(serverName, item) );
|
||||
|
||||
return metadata;
|
||||
}
|
||||
}
|
||||
|
||||
function fillerMapper(serverName, plexMetadata) {
|
||||
let image = {};
|
||||
if ( (typeof(plexMetadata.Image) === "object")
|
||||
&& (typeof(plexMetadata.Image[0]) === "object")
|
||||
) {
|
||||
image = plexMetadata.Image[0];
|
||||
}
|
||||
|
||||
let media = {};
|
||||
if ( (typeof(plexMetadata.Media) === "object")
|
||||
&& (typeof(plexMetadata.Media[0]) === "object")
|
||||
) {
|
||||
media = plexMetadata.Media[0];
|
||||
}
|
||||
|
||||
|
||||
async function getPlexServer(plexServerDB, serverName64) {
|
||||
let serverKey = Buffer.from(serverName64, 'base64').toString('utf-8');
|
||||
let part = {};
|
||||
if ( (typeof(media.Part) === "object")
|
||||
&& (typeof(media.Part[0]) === "object")
|
||||
) {
|
||||
part = media.Part[0];
|
||||
}
|
||||
|
||||
|
||||
return {
|
||||
title : plexMetadata.title,
|
||||
key : plexMetadata.key,
|
||||
ratingKey: plexMetadata.ratingKey,
|
||||
icon : image.url,
|
||||
type : plexMetadata.type,
|
||||
duration : part.duration,
|
||||
durationStr : undefined,
|
||||
summary : "",
|
||||
date : "",
|
||||
year : plexMetadata.year,
|
||||
plexFile : part.key,
|
||||
file : part.file,
|
||||
showTitle: plexMetadata.title,
|
||||
episode : 1,
|
||||
season : 1,
|
||||
serverKey: serverName,
|
||||
commercials: [],
|
||||
}
|
||||
}
|
||||
|
||||
async function getPlexServer(plexServerDB, serverKey) {
|
||||
let server = await plexServerDB.getPlexServerByName(serverKey);
|
||||
if (server == null) {
|
||||
throw Error("server not found");
|
||||
}
|
||||
return server;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
async function getPlexServer64(plexServerDB, serverName64) {
|
||||
let serverKey = Buffer.from(serverName64, 'base64').toString('utf-8');
|
||||
return await getPlexServer(plexServerDB, serverKey);
|
||||
}
|
||||
|
||||
|
||||
|
||||
module.exports = PlexProxyService
|
||||
@ -18,7 +18,7 @@ async function shutdown() {
|
||||
stopPlayback = true;
|
||||
}
|
||||
|
||||
function video( channelService, fillerDB, db, programmingService, activeChannelService, programPlayTimeDB, ffmpegInfo ) {
|
||||
function video( channelService, fillerService, db, programmingService, activeChannelService, programPlayTimeDB, ffmpegInfo ) {
|
||||
var router = express.Router()
|
||||
|
||||
router.get('/setup', async (req, res) => {
|
||||
@ -304,7 +304,7 @@ function video( channelService, fillerDB, db, programmingService, activeChannelS
|
||||
if ( (prog == null) || (typeof(prog) === 'undefined') || (prog.program == null) || (typeof(prog.program) == "undefined") ) {
|
||||
throw "No video to play, this means there's a serious unexpected bug or the channel db is corrupted."
|
||||
}
|
||||
let fillers = await fillerDB.getFillersFromChannel(brandChannel);
|
||||
let fillers = await fillerService.getFillersFromChannel(brandChannel);
|
||||
try {
|
||||
let lineup = helperFuncs.createLineup(programPlayTimeDB, prog, brandChannel, fillers, isFirst)
|
||||
lineupItem = lineup.shift();
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
module.exports = function ($timeout, commonProgramTools, getShowData) {
|
||||
module.exports = function ($timeout, dizquetv, commonProgramTools, getShowData) {
|
||||
return {
|
||||
restrict: 'E',
|
||||
templateUrl: 'templates/filler-config.html',
|
||||
@ -13,6 +13,16 @@ module.exports = function ($timeout, commonProgramTools, getShowData) {
|
||||
scope.content = [];
|
||||
scope.visible = false;
|
||||
scope.error = undefined;
|
||||
scope.modes = [ {
|
||||
name: "import",
|
||||
description: "Collection/Playlist from Plex",
|
||||
}, {
|
||||
name: "custom",
|
||||
description: "Custom List of Clips",
|
||||
} ];
|
||||
scope.servers = [];
|
||||
scope.libraries = [];
|
||||
scope.sources = [];
|
||||
|
||||
function refreshContentIndexes() {
|
||||
for (let i = 0; i < scope.content.length; i++) {
|
||||
@ -47,20 +57,173 @@ module.exports = function ($timeout, commonProgramTools, getShowData) {
|
||||
console.log("movedFunction(" + index + ")");
|
||||
}
|
||||
|
||||
scope.serverChanged = async () => {
|
||||
if (scope.server === "") {
|
||||
scope.libraryKey = "";
|
||||
return;
|
||||
}
|
||||
scope.loadingLibraries = true;
|
||||
try {
|
||||
let libraries = (await dizquetv.getFromPlexProxy(scope.server, "/library/sections")).Directory;
|
||||
if ( typeof(libraries) === "undefined") {
|
||||
libraries = []
|
||||
}
|
||||
let officialLibraries = libraries.map( (library) => {
|
||||
return {
|
||||
"key" : library.key,
|
||||
"description" : library.title,
|
||||
}
|
||||
} );
|
||||
|
||||
let defaultLibrary = {
|
||||
"key": "",
|
||||
"description" : "Select a Library...",
|
||||
}
|
||||
let playlists = [
|
||||
{
|
||||
"key": "$PLAYLISTS",
|
||||
"description" : "Playlists",
|
||||
}
|
||||
];
|
||||
let combined = officialLibraries.concat(playlists);
|
||||
if (! combined.some( (library) => library.key === scope.libraryKey) ) {
|
||||
scope.libraryKey = "";
|
||||
scope.libraries = [defaultLibrary].concat(combined);
|
||||
} else {
|
||||
scope.libraries = combined;
|
||||
}
|
||||
} catch (err) {
|
||||
scope.libraries = [ { name: "", description: "Unable to load libraries"} ];
|
||||
scope.libraryKey = ""
|
||||
throw err;
|
||||
} finally {
|
||||
scope.loadingLibraries = false;
|
||||
$timeout( () => {}, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
scope.linker( (filler) => {
|
||||
scope.libraryChanged = async () => {
|
||||
if (scope.libraryKey == null) {
|
||||
throw Error(`null libraryKey? ${scope.libraryKey} ${new Date().getTime()} `);
|
||||
}
|
||||
if (scope.libraryKey === "") {
|
||||
scope.sourceKey = "";
|
||||
return;
|
||||
}
|
||||
scope.loadingCollections = true;
|
||||
try {
|
||||
let collections;
|
||||
if (scope.libraryKey === "$PLAYLISTS") {
|
||||
collections = (await dizquetv.getFromPlexProxy(scope.server, `/playlists`)).Metadata;
|
||||
} else {
|
||||
collections = (await dizquetv.getFromPlexProxy(scope.server, `/library/sections/${scope.libraryKey}/collections`));
|
||||
collections = collections.Metadata
|
||||
}
|
||||
if (typeof(collections) === "undefined") {
|
||||
//when the library has no collections it returns size=0
|
||||
//and no array
|
||||
collections = [];
|
||||
}
|
||||
let officialCollections = collections.map( (col) => {
|
||||
return {
|
||||
"key" : col.key,
|
||||
"description" : col.title,
|
||||
}
|
||||
} );
|
||||
let defaultSource = {
|
||||
"key": "",
|
||||
"description" : "Select a Source...",
|
||||
};
|
||||
if (officialCollections.length == 0) {
|
||||
defaultSource = {
|
||||
"key": "",
|
||||
"description" : "(No collections/lists found)",
|
||||
}
|
||||
}
|
||||
if (! officialCollections.some( (col) => col.key === scope.sourceKey ) ) {
|
||||
scope.sourceKey = "";
|
||||
scope.sources = [defaultSource].concat(officialCollections);
|
||||
} else {
|
||||
scope.sources = officialCollections;
|
||||
}
|
||||
} catch (err) {
|
||||
scope.sources = [ { name: "", description: "Unable to load collections"} ];
|
||||
scope.sourceKey = "";
|
||||
throw err;
|
||||
} finally {
|
||||
scope.loadingCollections = false;
|
||||
$timeout( () => {}, 0);
|
||||
}
|
||||
}
|
||||
|
||||
let reloadServers = async() => {
|
||||
scope.loadingServers = true;
|
||||
try {
|
||||
let servers = await dizquetv.getPlexServers();
|
||||
scope.servers = servers.map( (s) => {
|
||||
return {
|
||||
"name" : s.name,
|
||||
"description" : `Plex - ${s.name}`,
|
||||
}
|
||||
} );
|
||||
let defaultServer = {
|
||||
name: "",
|
||||
description: "Select a Plex server..."
|
||||
};
|
||||
if (! scope.servers.some( (server) => server.name === scope.server) ) {
|
||||
scope.server = "";
|
||||
scope.servers = [defaultServer].concat(scope.servers);
|
||||
}
|
||||
} catch (err) {
|
||||
scope.server = "";
|
||||
scope.servers = [ {name:"", description:"Could not load servers"} ];
|
||||
throw err;
|
||||
} finally {
|
||||
scope.loadingServers = false;
|
||||
$timeout( () => {}, 0);
|
||||
}
|
||||
|
||||
await scope.serverChanged();
|
||||
await scope.libraryChanged();
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
scope.linker( async (filler) => {
|
||||
|
||||
if ( typeof(filler) === 'undefined') {
|
||||
scope.name = "";
|
||||
scope.content = [];
|
||||
scope.id = undefined;
|
||||
scope.title = "Create Filler List";
|
||||
scope.mode = "import";
|
||||
scope.server = "";
|
||||
scope.libraryKey = "";
|
||||
scope.sourceKey = "";
|
||||
} else {
|
||||
scope.name = filler.name;
|
||||
scope.content = filler.content;
|
||||
scope.id = filler.id;
|
||||
scope.title = "Edit Filler List";
|
||||
scope.mode = filler.mode;
|
||||
scope.server = filler?.import?.serverName;
|
||||
if ( typeof(scope.server) !== "string" ) {
|
||||
scope.server = "";
|
||||
}
|
||||
scope.libraryKey = filler?.import?.meta?.libraryKey;
|
||||
if ( typeof(scope.libraryKey) !== "string" ) {
|
||||
scope.libraryKey = "";
|
||||
}
|
||||
scope.sourceKey = filler?.import?.key;
|
||||
if ( typeof(scope.sourceKey) !== "string" ) {
|
||||
scope.sourceKey = "";
|
||||
}
|
||||
}
|
||||
await reloadServers();
|
||||
scope.source = "";
|
||||
refreshContentIndexes();
|
||||
scope.visible = true;
|
||||
} );
|
||||
@ -73,8 +236,17 @@ module.exports = function ($timeout, commonProgramTools, getShowData) {
|
||||
if ( (typeof(scope.name) === 'undefined') || (scope.name.length == 0) ) {
|
||||
scope.error = "Please enter a name";
|
||||
}
|
||||
if ( scope.content.length == 0) {
|
||||
scope.error = "Please add at least one clip.";
|
||||
if ( scope?.mode === "import" ) {
|
||||
if ( (typeof(scope?.server) !== "string" ) || (scope?.server === "") ) {
|
||||
scope.error = "Please select a server"
|
||||
}
|
||||
if ( (typeof(scope?.source) !== "string" ) && (scope?.source === "") ) {
|
||||
scope.error = "Please select a source."
|
||||
}
|
||||
} else {
|
||||
if ( scope.content.length == 0) {
|
||||
scope.error = "Please add at least one clip.";
|
||||
}
|
||||
}
|
||||
if (typeof(scope.error) !== 'undefined') {
|
||||
$timeout( () => {
|
||||
@ -83,14 +255,30 @@ module.exports = function ($timeout, commonProgramTools, getShowData) {
|
||||
return;
|
||||
}
|
||||
scope.visible = false;
|
||||
scope.onDone( {
|
||||
let object = {
|
||||
name: scope.name,
|
||||
content: scope.content.map( (c) => {
|
||||
delete c.$index
|
||||
return c;
|
||||
} ),
|
||||
id: scope.id,
|
||||
} );
|
||||
mode: scope.mode,
|
||||
|
||||
};
|
||||
if (object.mode === "import") {
|
||||
object.content = [];
|
||||
//In reality dizqueTV only needs to know the server name
|
||||
//and the source key, the meta object is for extra data
|
||||
//that is useful for external things like this UI.
|
||||
object.import = {
|
||||
serverName : scope.server,
|
||||
key: scope.sourceKey,
|
||||
meta: {
|
||||
libraryKey : scope.libraryKey,
|
||||
}
|
||||
}
|
||||
}
|
||||
scope.onDone( object );
|
||||
}
|
||||
scope.getText = (clip) => {
|
||||
let show = getShowData(clip);
|
||||
|
||||
@ -11,8 +11,52 @@
|
||||
<div class="form-group">
|
||||
<label for="name">Filler Name:</label>
|
||||
<input type="text" class="form-control" id="name" placeholder="Filler Name" ng-model="name" ></input>
|
||||
|
||||
<div>Mode:</div>
|
||||
<select class="custom-select"
|
||||
ng-model="mode"
|
||||
ng-options="theMode.name as theMode.description for theMode in modes" ></select>
|
||||
</div>
|
||||
|
||||
|
||||
<div ng-show="mode==='import'">
|
||||
<div class="form-group">
|
||||
<label for="server">Server:</label>
|
||||
|
||||
<div class="loader" ng-show="loadingServers === true" ></div>
|
||||
<select
|
||||
ng-show="loadingServers !== true"
|
||||
id="server"
|
||||
class="custom-select"
|
||||
ng-change="serverChanged()"
|
||||
ng-model="server"
|
||||
ng-options="x.name as x.description for x in servers" ></select>
|
||||
</div>
|
||||
<div ng-show="server !==''">
|
||||
<label for="library">Library:</label>
|
||||
|
||||
<div class="loader" ng-show="loadingLibraries === true" ></div>
|
||||
<select
|
||||
ng-show="loadingLibraries !== true"
|
||||
id="library"
|
||||
class="custom-select"
|
||||
ng-change="libraryChanged()"
|
||||
ng-model="libraryKey"
|
||||
ng-options="x.key as x.description for x in libraries" ></select>
|
||||
</div>
|
||||
<div ng-show="libraryKey !==''">
|
||||
<label for="source">Source:</label>
|
||||
|
||||
<div class="loader" ng-show="loadingCollections === true" ></div>
|
||||
<select
|
||||
ng-show="loadingCollections !== true"
|
||||
id="source"
|
||||
class="custom-select"
|
||||
ng-model="sourceKey"
|
||||
ng-options="x.key as x.description for x in sources" ></select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div ng-show="mode==='custom'">
|
||||
<h6 style="margin-top: 10px;">Clips</h6>
|
||||
|
||||
<div class="flex-container">
|
||||
@ -65,10 +109,11 @@
|
||||
<div ng-show="content.length === 0">
|
||||
<p class="text-center text-info">Click the <span class="fa fa-plus"></span> to import filler content from your Plex server(s).</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div vs-repeat class="modal-body container list-group list-group-root filler-list"
|
||||
<div ng-show="mode==='custom'" vs-repeat class="modal-body container list-group list-group-root filler-list"
|
||||
dnd-list="content" ng-if="showList()"
|
||||
vs-repeat-reinitialized="vsReinitialized(event, startIndex, endIndex)"
|
||||
ng-init="setUpWatcher()"
|
||||
@ -76,8 +121,7 @@
|
||||
dnd-list=""
|
||||
|
||||
>
|
||||
<div class="list-group-item flex-container filler-row" style="cursor: default; height:1.1em; overflow:hidden" ng-repeat="x in content" track-by="x.$index" dnd-draggable="x"
|
||||
"
|
||||
<div class="list-group-item flex-container filler-row" style="cursor: default; height:1.1em; overflow:hidden" ng-repeat="x in content" track-by="x.$index" dnd-draggable="x"
|
||||
dnd-effect-allowed="move"
|
||||
dnd-moved="movedFunction(x.$index)"
|
||||
>
|
||||
|
||||
@ -3,8 +3,8 @@ module.exports = function ($http, $q) {
|
||||
getVersion: () => {
|
||||
return $http.get('/api/version').then((d) => { return d.data })
|
||||
},
|
||||
getPlexServers: () => {
|
||||
return $http.get('/api/plex-servers').then((d) => { return d.data })
|
||||
getPlexServers: async () => {
|
||||
return (await $http.get('/api/plex-servers')).data;
|
||||
},
|
||||
addPlexServer: (plexServer) => {
|
||||
return $http({
|
||||
@ -96,6 +96,9 @@ module.exports = function ($http, $q) {
|
||||
headers: { 'Content-Type': 'application/json; charset=utf-8' }
|
||||
}).then((d) => { return d.data })
|
||||
},
|
||||
getFFMpegPath: () => {
|
||||
return $http.get('/api/ffmpeg-info').then((d) => { return d.data })
|
||||
},
|
||||
getXmltvSettings: () => {
|
||||
return $http.get('/api/xmltv-settings').then((d) => { return d.data })
|
||||
},
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user