mirror of
https://github.com/WebTools-NG/WebTools-NG
synced 2024-11-26 04:50:18 +00:00
commit
54f6a1868a
19 changed files with 917 additions and 147 deletions
16
CHANGELOG.md
16
CHANGELOG.md
|
@ -1,6 +1,6 @@
|
|||
# ![Logo](https://github.com/WebTools-NG/WebTools-NG/blob/master/src/assets/WebTools-48x48.png) WebTools-ng Change log
|
||||
|
||||
## V0.3.15 (Not released yet)
|
||||
## V0.3.16 ( Not Released Yet)
|
||||
|
||||
**Note**: This version is an Beta version
|
||||
|
||||
|
@ -11,6 +11,20 @@
|
|||
|
||||
**Changes**:
|
||||
|
||||
* [#440 Dvr Backup and Restore](https://github.com/WebTools-NG/WebTools-NG/issues/440)
|
||||
|
||||
|
||||
## V0.3.15 (20220413)
|
||||
|
||||
**Note**: This version is an Beta version
|
||||
|
||||
**Note 2**: In this version, the following is disabled:
|
||||
|
||||
* Export to xlsx format ([See #331](https://github.com/WebTools-NG/WebTools-NG/issues/331))
|
||||
* Photo Library export
|
||||
|
||||
**Changes**:
|
||||
|
||||
* [#453 Kickstart Butler Scheduled tasks](https://github.com/WebTools-NG/WebTools-NG/issues/453)
|
||||
* [#456 ET Custom levels doesn't use include params](https://github.com/WebTools-NG/WebTools-NG/issues/456)
|
||||
* Internal: More easy way to hide stuff in progress
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "webtools-ng",
|
||||
"productName": "WebTools-NG",
|
||||
"version": "0.3.15",
|
||||
"version": "0.3.16",
|
||||
"description": "WebTools Next Generation 4 Plex",
|
||||
"author": "dane22 & CPSO",
|
||||
"license": "MPL-2.0",
|
||||
|
|
|
@ -117,6 +117,7 @@
|
|||
}
|
||||
},
|
||||
"Ok": "OK",
|
||||
"Cancel": "Cancel",
|
||||
"Reload": "Reload",
|
||||
"Update": {
|
||||
"Title": "Update detected",
|
||||
|
@ -397,8 +398,39 @@
|
|||
"ttselDVR": "Here you select the DVR you want to make a backup of",
|
||||
"lblBtnBackup": "Backup",
|
||||
"lblBtnRestore": "Restore",
|
||||
"BackupDone": "DVR has been saved"
|
||||
}
|
||||
"BackupDone": "DVR has been saved",
|
||||
"selRestoreFile": "Select DVR file to restore",
|
||||
"confirmRestore": "Confirm restore",
|
||||
"restoreMsg": "Are you sure you want to restore the DVR named: '{0}'",
|
||||
"selAlredyPresentMsg": "The selected DVR: '{0}' already exist on your PMS. So we will abort",
|
||||
"selAlredyPresentTitle": "Aborting",
|
||||
"selMissingDevice": "The selected backup file is missing devices",
|
||||
"selDeviceAlreadyUsed": "The device is in use with an existing DVR"
|
||||
},
|
||||
"ViewState": {
|
||||
"Name": "View State Copy",
|
||||
"Description": "@:Modules.PMS.ViewState.Name module allows you to copy a users list of seen medias to another user on the same server. Note: It's important, that both users has access to the medias",
|
||||
"selSourceUsr": "Select User to copy from",
|
||||
"ttSelSourceUsr": "Here you select the user you wants to copy view states from",
|
||||
"selTargetUsr": "Select User to copy to",
|
||||
"ttSelTargetUsr": "Here you select the user you wants to copy view states to",
|
||||
"Owner": "Server owner",
|
||||
"Managed": "Managed User",
|
||||
"lblBtnCopy": "Copy",
|
||||
"Status": {
|
||||
"Msg": {
|
||||
"CollectUserInfo": "Collecting user info...Please wait",
|
||||
"Processing": "Processing",
|
||||
"Idle": "Idle",
|
||||
"GatheringLibs": "Gathering libraries to process"
|
||||
},
|
||||
"Names": {
|
||||
"Status": "Status",
|
||||
"LibsToProcess": "Libraries to process",
|
||||
"StartTime": "Start time"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"PlexTV": {
|
||||
"Name": "Plex.TV",
|
||||
|
@ -416,6 +448,6 @@
|
|||
"ExportUsr": "Export user to CSV",
|
||||
"ExportAllUsr": "Export all users to CSV",
|
||||
"Settings": "To configure column separator and 'Not Avail', use @:Modules.ET.Name settings"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -97,15 +97,15 @@ export default {
|
|||
},
|
||||
methods: {
|
||||
fetchServers(){
|
||||
log.info("fetching servers")
|
||||
log.info("[Headers.vue] (fetchServers) fetching servers")
|
||||
this.$store.dispatch('fetchPlexServers', store.getters.getAuthToken);
|
||||
},
|
||||
active2(e) {
|
||||
log.info("active2 called")
|
||||
log.info("[Headers.vue] (active2) active2 called")
|
||||
this.active = e;
|
||||
},
|
||||
selected: function () {
|
||||
log.info('Selected server: ' + this.selectedOption.name)
|
||||
log.info(`[Headers.vue] (selected) Selected server: ${this.selectedOption.name}`)
|
||||
ptv.checkServerConnect(this.selectedOption)
|
||||
this.$store.commit("UPDATE_SELECTED_SERVER", this.selectedOption);
|
||||
},
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<sidebar-menu
|
||||
<sidebar-menu
|
||||
:menu="menu"
|
||||
:collapsed="collapsed"
|
||||
@toggle-collapse="onToggleCollapse"
|
||||
|
@ -10,8 +10,8 @@
|
|||
const log = require('electron-log');
|
||||
console.log = log.log;
|
||||
import '@fortawesome/fontawesome-free/css/all.css';
|
||||
import etIcon from '@/assets/ET-256.png';
|
||||
import pmsIcon from '@/assets/plex-pms-icon.png';
|
||||
import etIcon from '@/assets/ET-256.png';
|
||||
import pmsIcon from '@/assets/plex-pms-icon.png';
|
||||
import plextvIcon from '@/assets/plex-app-icon.png';
|
||||
import {wtconfig, wtutils} from '../../components/modules/General/wtutils';
|
||||
|
||||
|
@ -20,15 +20,15 @@
|
|||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
collapsed: false
|
||||
return {
|
||||
collapsed: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
menu(){
|
||||
return [
|
||||
{
|
||||
href: { path: '/home' },
|
||||
href: { path: '/home' },
|
||||
title: this.$t("Common.Menu.Sidebar.Home.NavTitle"),
|
||||
icon: 'fa fa-home'
|
||||
},
|
||||
|
@ -36,7 +36,7 @@
|
|||
header: true,
|
||||
title: this.$t("Common.Menu.Sidebar.NavSections.Tools"),
|
||||
hiddenOnCollapse: true
|
||||
},
|
||||
},
|
||||
{
|
||||
href: { path: '/plextv' },
|
||||
title: this.$t("Modules.PlexTV.Name"),
|
||||
|
@ -46,7 +46,7 @@
|
|||
//adjust element
|
||||
element: 'img',
|
||||
attributes: { src: plextvIcon },
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
href: { path: '/pms' },
|
||||
|
@ -59,15 +59,15 @@
|
|||
attributes: { src: pmsIcon },
|
||||
},
|
||||
child: [
|
||||
{
|
||||
{
|
||||
href: '/pms/settings',
|
||||
hidden: wtutils.hideMenu('pmsSettings'),
|
||||
title: this.$t("Common.Menu.Sidebar.PMS.Settings"),
|
||||
title: this.$t("Common.Menu.Sidebar.PMS.Settings"),
|
||||
icon: 'fa fa-cog'
|
||||
},
|
||||
{
|
||||
{
|
||||
href: '/pms/butler',
|
||||
title: this.$t("Common.Menu.Sidebar.PMS.Butler"),
|
||||
title: this.$t("Common.Menu.Sidebar.PMS.Butler"),
|
||||
hidden: wtutils.hideMenu('pmsButler'),
|
||||
icon: 'fa fa-tasks'
|
||||
},
|
||||
|
@ -75,7 +75,14 @@
|
|||
href: { path: '/pms/dvr' },
|
||||
title: this.$t("Modules.PMS.DVR.Name"),
|
||||
hidden: wtutils.hideMenu('pmsDVR'),
|
||||
icon: 'fas fa-tv',
|
||||
icon: 'fas fa-tv',
|
||||
}
|
||||
,
|
||||
{
|
||||
href: { path: '/pms/viewstate' },
|
||||
title: this.$t("Modules.PMS.ViewState.Name"),
|
||||
hidden: wtutils.hideMenu('pmsViewState'),
|
||||
icon: 'fas fa-tv',
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -87,23 +94,23 @@
|
|||
icon: {
|
||||
//adjust element
|
||||
element: 'img',
|
||||
attributes: { src: etIcon },
|
||||
attributes: { src: etIcon },
|
||||
},
|
||||
child: [
|
||||
{
|
||||
{
|
||||
href: '/export/settings',
|
||||
title: this.$t("Common.Menu.Sidebar.ET.Settings"),
|
||||
hidden: wtutils.hideMenu('etSettings'),
|
||||
hidden: wtutils.hideMenu('etSettings'),
|
||||
icon: 'fa fa-cog'
|
||||
},
|
||||
{
|
||||
{
|
||||
href: '/export/custom',
|
||||
title: this.$t("Common.Menu.Sidebar.ET.Custom"),
|
||||
hidden: wtutils.hideMenu('etCustom'),
|
||||
hidden: wtutils.hideMenu('etCustom'),
|
||||
icon: 'fa fa-cog'
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
},
|
||||
{
|
||||
header: true,
|
||||
|
@ -119,8 +126,8 @@
|
|||
},
|
||||
{
|
||||
href: '/settings',
|
||||
title: this.$t("Common.Menu.Sidebar.Settings.NavTitle"),
|
||||
hidden: wtutils.hideMenu('Settings'),
|
||||
title: this.$t("Common.Menu.Sidebar.Settings.NavTitle"),
|
||||
hidden: wtutils.hideMenu('Settings'),
|
||||
icon: 'fa fa-cog'
|
||||
},
|
||||
{
|
||||
|
@ -142,7 +149,7 @@
|
|||
onToggleCollapse(collapsed) {
|
||||
this.$emit("e-iscollapsed", collapsed);
|
||||
log.info(collapsed)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -69,16 +69,16 @@ function setQualifier( {str:str})
|
|||
function cleanupSuggestedFile( tmpFileName )
|
||||
{
|
||||
const unWantedChars = '.-*_[](){}';
|
||||
log.verbose(`etHelper (cleanupSuggestedFile) - starting Param: ${tmpFileName}`);
|
||||
log.verbose(`etHelper (cleanupSuggestedFile) - starting Param: ${tmpFileName}`);
|
||||
// Now replace square brackets if present with a dot
|
||||
tmpFileName = tmpFileName.replaceAll("[", ".");
|
||||
tmpFileName = tmpFileName.replaceAll("]", ".");
|
||||
tmpFileName = tmpFileName.replaceAll("]", ".");
|
||||
// Start by trimming the string
|
||||
tmpFileName = tmpFileName.trim();
|
||||
tmpFileName = tmpFileName.trim();
|
||||
while ( unWantedChars.indexOf(tmpFileName.charAt(0)) > -1)
|
||||
{
|
||||
tmpFileName = tmpFileName.slice(1).trim();
|
||||
if ( tmpFileName.length === 0 ) break;
|
||||
tmpFileName = tmpFileName.slice(1).trim();
|
||||
if ( tmpFileName.length === 0 ) break;
|
||||
}
|
||||
// Remove from end of the string
|
||||
while ( unWantedChars.indexOf(tmpFileName.charAt(tmpFileName.length-1)) > -1)
|
||||
|
@ -91,8 +91,8 @@ function cleanupSuggestedFile( tmpFileName )
|
|||
// Now delete empty brackets
|
||||
tmpFileName = tmpFileName.replaceAll("()", "");
|
||||
tmpFileName = tmpFileName.replaceAll("{}", "");
|
||||
log.verbose(`etHelper (cleanupSuggestedFile) - Returning: ${tmpFileName}`);
|
||||
return tmpFileName;
|
||||
log.verbose(`etHelper (cleanupSuggestedFile) - Returning: ${tmpFileName}`);
|
||||
return tmpFileName;
|
||||
}
|
||||
|
||||
// Returns a suggested title for a media
|
||||
|
@ -124,8 +124,8 @@ function getSuggestedYear( data )
|
|||
// Returns a suggested id for a media
|
||||
function getSuggestedId( data )
|
||||
{
|
||||
log.verbose(`etHelper (getSuggestedId) - Started. To see Param, switch to Silly logging`);
|
||||
log.silly(`etHelper (getSuggestedId) - Starting with param: ${JSON.stringify(data)}`);
|
||||
log.verbose(`etHelper (getSuggestedId) - Started. To see Param, switch to Silly logging`);
|
||||
log.silly(`etHelper (getSuggestedId) - Starting with param: ${JSON.stringify(data)}`);
|
||||
let imdb = String(JSONPath({path: "$.data.Guid[?(@.id.startsWith('imdb'))].id", json: data}));
|
||||
let tmdb = String(JSONPath({path: "$.data.Guid[?(@.id.startsWith('tmdb'))].id", json: data}));
|
||||
let tvdb = String(JSONPath({path: "$.data.Guid[?(@.id.startsWith('tvdb'))].id", json: data}));
|
||||
|
@ -142,7 +142,7 @@ function getSuggestedId( data )
|
|||
{
|
||||
tvdb = imdb;
|
||||
}
|
||||
let selId;
|
||||
let selId;
|
||||
if ( etHelper.Settings.libType === 1)
|
||||
{
|
||||
selId = wtconfig.get("ET.SelectedMoviesID", "imdb");
|
||||
|
@ -151,9 +151,9 @@ function getSuggestedId( data )
|
|||
{
|
||||
selId = wtconfig.get("ET.SelectedShowsID", "tmdb");
|
||||
}
|
||||
log.silly(`etHelper (getSuggestedId) - imdb ID: ${imdb}`);
|
||||
log.silly(`etHelper (getSuggestedId) - tmdb ID: ${tmdb}`);
|
||||
log.silly(`etHelper (getSuggestedId) - tvdb ID: ${tvdb}`);
|
||||
log.silly(`etHelper (getSuggestedId) - imdb ID: ${imdb}`);
|
||||
log.silly(`etHelper (getSuggestedId) - tmdb ID: ${tmdb}`);
|
||||
log.silly(`etHelper (getSuggestedId) - tvdb ID: ${tvdb}`);
|
||||
|
||||
let Id;
|
||||
switch(selId) {
|
||||
|
@ -179,43 +179,43 @@ function getSuggestedId( data )
|
|||
{
|
||||
Id = `{tvdb-${tvdb.slice(7)}}`;
|
||||
}
|
||||
break;
|
||||
break;
|
||||
}
|
||||
log.debug(`etHelper (getSuggestedId) - Returning: "imdb": ${imdb}, "tmdb": ${tmdb}, "tvdb": ${tvdb}, "selId": ${Id}`);
|
||||
log.debug(`etHelper (getSuggestedId) - Returning: "imdb": ${imdb}, "tmdb": ${tmdb}, "tvdb": ${tvdb}, "selId": ${Id}`);
|
||||
return {"imdb": imdb, "tmdb": tmdb, "tvdb": tvdb, "selId": Id};
|
||||
}
|
||||
|
||||
// Returns a string stripped for Year
|
||||
function stripYearFromFileName( tmpFileName, year ){
|
||||
const re = new RegExp(`\\b${year}\\b`, 'gi');
|
||||
return tmpFileName.replace(re, "").trim();
|
||||
return tmpFileName.replace(re, "").trim();
|
||||
}
|
||||
|
||||
// Returns a string stripped for ID's
|
||||
function stripIdFromFileName( param ){
|
||||
function stripIdFromFileName( param ){
|
||||
log.debug(`etHelper (stripIdFromFileName) - starting function with param as: ${JSON.stringify(param)}`);
|
||||
let tmpFileName = param.tmpFileName;
|
||||
let re;
|
||||
const imdb = param.imdb.slice(7);
|
||||
const tmdb = param.tmdb.slice(7);
|
||||
const tvdb = param.tvdb.slice(7);
|
||||
// Remove IMDB id
|
||||
// Remove IMDB id
|
||||
log.debug(`etHelper (stripIdFromFileName) - Imdb string is : ${imdb}`);
|
||||
re = new RegExp(`\\b${imdb}\\b`, 'gi');
|
||||
tmpFileName = tmpFileName.replace(re, "");
|
||||
log.debug(`etHelper (stripIdFromFileName) - After imdb id is removed: ${tmpFileName}`);
|
||||
tmpFileName = tmpFileName.replace(/imdb-/i, '');
|
||||
log.debug(`etHelper (stripIdFromFileName) - After imdb string is removed: ${tmpFileName}`);
|
||||
// Remove TMDB id
|
||||
// Remove TMDB id
|
||||
re = new RegExp(`\\b${tmdb}\\b`, 'gi');
|
||||
tmpFileName = tmpFileName.replace(re, "");
|
||||
// Remove TVDB id
|
||||
// Remove TVDB id
|
||||
re = new RegExp(`\\b${tvdb}\\b`, 'gi');
|
||||
tmpFileName = tmpFileName.replace(re, "");
|
||||
const idProviders = ['imdb', 'tmdb', 'tvdb'];
|
||||
const idProviders = ['imdb', 'tmdb', 'tvdb'];
|
||||
idProviders.forEach(element => {
|
||||
re = new RegExp(`\\b${element}\\b`, 'gi');
|
||||
tmpFileName = tmpFileName.replace(re, "");
|
||||
tmpFileName = tmpFileName.replace(re, "");
|
||||
});
|
||||
return tmpFileName.replace(`{-}`, "").trim();
|
||||
}
|
||||
|
@ -223,33 +223,33 @@ function stripIdFromFileName( param ){
|
|||
// Returns a filename without the title
|
||||
function stripTitleFromFileName( tmpFileName, title )
|
||||
{
|
||||
let re;
|
||||
let re;
|
||||
// Title in filename separated with dots
|
||||
let titleArray = tmpFileName.split(".");
|
||||
for (let titleElement of titleArray) {
|
||||
for (let titleElement of titleArray) {
|
||||
if (title.toUpperCase().indexOf(titleElement.toUpperCase()) > -1) {
|
||||
re = new RegExp(`\\b${titleElement}\\b`, 'gi');
|
||||
tmpFileName = tmpFileName.replace(re, "");
|
||||
}
|
||||
}
|
||||
if (titleElement.toUpperCase() === 'AND')
|
||||
{
|
||||
titleElement = '&'
|
||||
titleElement = '&'
|
||||
if (title.toUpperCase().indexOf(titleElement.toUpperCase()) > -1) {
|
||||
re = new RegExp(`\\band\\b`, 'gi');
|
||||
tmpFileName = tmpFileName.replace(re, "");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Title in filename separated with spaces
|
||||
titleArray = tmpFileName.split(" ");
|
||||
for (let titleElement of titleArray) {
|
||||
for (let titleElement of titleArray) {
|
||||
if (title.toUpperCase().indexOf(titleElement.toUpperCase()) > -1) {
|
||||
re = new RegExp(`\\b${titleElement}\\b`, 'gi');
|
||||
tmpFileName = tmpFileName.replace(re, "");
|
||||
}
|
||||
if (titleElement == '&')
|
||||
{
|
||||
titleElement = 'AND'
|
||||
titleElement = 'AND'
|
||||
if (title.toUpperCase().indexOf(titleElement.toUpperCase()) > -1) {
|
||||
re = new RegExp(`\\b${titleElement}\\b`, 'gi');
|
||||
tmpFileName = tmpFileName.replace(re, "");
|
||||
|
@ -266,7 +266,7 @@ function stripPartsFromFileName( tmpFileName, title ) {
|
|||
let partName = '';
|
||||
// Find stacked item if present
|
||||
etHelper.StackedFilesName.forEach(element => {
|
||||
// Got a hit?
|
||||
// Got a hit?
|
||||
if (tmpFileName.toLowerCase().indexOf(element) > -1) {
|
||||
// Get index again
|
||||
const idx = tmpFileName.toLowerCase().indexOf(element);
|
||||
|
@ -287,14 +287,14 @@ function stripPartsFromFileName( tmpFileName, title ) {
|
|||
log.warn(`etHelper (stripPartsFromFileName) - for the media with the title: "${title}" looking at the string: "${tmpFileName}" for stacked element: "${element}" but found entry not in range [1-8] so ignorring`)
|
||||
log.warn(`etHelper (stripPartsFromFileName) - See: https://support.plex.tv/articles/naming-and-organizing-your-movie-media-files/`)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Remove partName from tmpFile
|
||||
|
||||
// Remove partName from tmpFile
|
||||
// Get index of partName
|
||||
const idx = tmpFileName.toUpperCase().indexOf(partName.toUpperCase());
|
||||
tmpFileName = tmpFileName.slice(0, idx) + tmpFileName.slice(idx + partName.length);
|
||||
tmpFileName = tmpFileName.slice(0, idx) + tmpFileName.slice(idx + partName.length);
|
||||
// Remove white spaces
|
||||
tmpFileName = tmpFileName.trim();
|
||||
if (tmpFileName.length === 1)
|
||||
|
@ -307,7 +307,7 @@ function stripPartsFromFileName( tmpFileName, title ) {
|
|||
}
|
||||
}
|
||||
log.verbose(`etHelper (stripPartsFromFileName) - Returning tmpFileName as: ${tmpFileName} *** Returning partName as: ${partName}`);
|
||||
return {
|
||||
return {
|
||||
fileName: tmpFileName,
|
||||
partName: partName
|
||||
};
|
||||
|
@ -466,24 +466,24 @@ const etHelper = new class ETHELPER {
|
|||
log.verbose(`etHelper (getSuggestedFolderName) - Starting function. To see param, use Silly log level`);
|
||||
log.silly(`etHelper (getSuggestedFolderName) - Data pased over as: ${JSON.stringify(data)}`);
|
||||
const title = getSuggestedTitle( data );
|
||||
const year = getSuggestedYear( data );
|
||||
const Id = getSuggestedId( data ).selId;
|
||||
// Get current folder name
|
||||
const curFolderName = path.basename(path.dirname(String(JSONPath({path: "$.data.Media[0].Part[0].file", json: data}))))
|
||||
const year = getSuggestedYear( data );
|
||||
const Id = getSuggestedId( data ).selId;
|
||||
// Get current folder name
|
||||
const curFolderName = path.basename(path.dirname(String(JSONPath({path: "$.data.Media[0].Part[0].file", json: data}))))
|
||||
// Compute suggested foldername
|
||||
let foldername = `${title} (${year}) ${Id}`;
|
||||
log.debug(`etHelper (getSuggestedFolderName) - Suggested folderName is: ${foldername}`);
|
||||
if (curFolderName === foldername) {
|
||||
return i18n.t("Modules.ET.FolderNameOK")
|
||||
return i18n.t("Modules.ET.FolderNameOK")
|
||||
}
|
||||
else {
|
||||
else {
|
||||
return foldername
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// This will return a suggested filename, following Plex naming std
|
||||
async getSuggestedFileName( data )
|
||||
{
|
||||
{
|
||||
const title = getSuggestedTitle( data );
|
||||
const year = getSuggestedYear( data );
|
||||
const Ids = getSuggestedId( data );
|
||||
|
@ -492,7 +492,7 @@ const etHelper = new class ETHELPER {
|
|||
const tmdb = Ids.tmdb;
|
||||
const tvdb = Ids.tvdb;
|
||||
|
||||
// Get current filename
|
||||
// Get current filename
|
||||
const curFileName = path.parse(String(JSONPath({path: '$.data.Media[0].Part[0].file', json: data}))).name;
|
||||
|
||||
// Compute suggested filename, and start by stripping known info from existing name
|
||||
|
@ -503,7 +503,7 @@ const etHelper = new class ETHELPER {
|
|||
tmpFileName = stripYearFromFileName( tmpFileName, year );
|
||||
// Strip ID from fileName
|
||||
tmpFileName = stripIdFromFileName( {tmpFileName: tmpFileName, imdb: imdb, tmdb: tmdb, tvdb: tvdb} );
|
||||
tmpFileName = cleanupSuggestedFile(tmpFileName);
|
||||
tmpFileName = cleanupSuggestedFile(tmpFileName);
|
||||
// Get parts, if a stacked media
|
||||
const parts = stripPartsFromFileName( tmpFileName, title );
|
||||
tmpFileName = parts.fileName;
|
||||
|
@ -519,7 +519,7 @@ const etHelper = new class ETHELPER {
|
|||
tmpFileName = tmpFileName.replaceAll("{}", "");
|
||||
// Now replace square brackets if present with a dot
|
||||
tmpFileName = tmpFileName.replaceAll("[", ".");
|
||||
tmpFileName = tmpFileName.replaceAll("]", ".");
|
||||
tmpFileName = tmpFileName.replaceAll("]", ".");
|
||||
// Remove double dots if present
|
||||
tmpFileName = tmpFileName.replaceAll("..", ".");
|
||||
tmpFileName = tmpFileName.trim();
|
||||
|
@ -527,12 +527,12 @@ const etHelper = new class ETHELPER {
|
|||
while(tmpFileName.charAt(0) === '.')
|
||||
{
|
||||
tmpFileName = tmpFileName.substring(1);
|
||||
}
|
||||
// Remove trailing dots if present
|
||||
}
|
||||
// Remove trailing dots if present
|
||||
while(tmpFileName.slice(-1) === '.')
|
||||
{
|
||||
tmpFileName = tmpFileName.substring(0, tmpFileName.length - 1);
|
||||
}
|
||||
}
|
||||
// Remove double square brackets if present
|
||||
tmpFileName = tmpFileName.replaceAll("[]", "");
|
||||
// Remove double square brackets with a space if present
|
||||
|
@ -541,12 +541,12 @@ const etHelper = new class ETHELPER {
|
|||
tmpFileName = tmpFileName.replaceAll(" ", " ");
|
||||
// Remove space dot if present, and replace with dot
|
||||
tmpFileName = tmpFileName.replaceAll(" .", ".");
|
||||
|
||||
|
||||
|
||||
|
||||
tmpFileName = tmpFileName.trim();
|
||||
|
||||
|
||||
|
||||
tmpFileName = tmpFileName.trim();
|
||||
|
||||
*/
|
||||
// Get filename part of remaining filename
|
||||
if (tmpFileName.length >= 1)
|
||||
|
@ -559,20 +559,20 @@ const etHelper = new class ETHELPER {
|
|||
suggestedFileName = `${title} (${year}) ${Id} ${partName}`.trim();
|
||||
}
|
||||
else
|
||||
{
|
||||
{
|
||||
suggestedFileName = `${title} (${year}) ${Id} ${tmpFileName} ${partName}`.trim();
|
||||
}
|
||||
// Remove double space if present
|
||||
suggestedFileName = suggestedFileName.replaceAll(" ", " ");
|
||||
const fileNameExt = path.parse(String(JSONPath({path: '$.data.Media[0].Part[0].file', json: data}))).ext;
|
||||
suggestedFileName = suggestedFileName.replaceAll(" ", " ");
|
||||
const fileNameExt = path.parse(String(JSONPath({path: '$.data.Media[0].Part[0].file', json: data}))).ext;
|
||||
suggestedFileName = `${suggestedFileName}${fileNameExt}`;
|
||||
log.debug(`etHelper (getSuggestedFileName) - returning ${suggestedFileName}`);
|
||||
if (curFileName === path.parse(suggestedFileName).name) {
|
||||
return i18n.t("Modules.ET.FileNameOK")
|
||||
return i18n.t("Modules.ET.FileNameOK")
|
||||
}
|
||||
else {
|
||||
else {
|
||||
return suggestedFileName
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async postProcess( {name, val, title="", data} ){
|
||||
|
@ -596,19 +596,13 @@ const etHelper = new class ETHELPER {
|
|||
break;
|
||||
}
|
||||
case "Suggested File Name":
|
||||
retVal = await this.getSuggestedFileName( {data: data} );
|
||||
retVal = await this.getSuggestedFileName( {data: data} );
|
||||
break;
|
||||
case "Suggested Folder Name":
|
||||
retVal = await this.getSuggestedFolderName( {data: data} );
|
||||
break;
|
||||
retVal = await this.getSuggestedFolderName( {data: data} );
|
||||
break;
|
||||
case "Part File":
|
||||
console.log('Ged 76-0 Part File in: ' + valArray)
|
||||
console.log('Ged 76-1 Part File in: ' + JSON.stringify(valArray))
|
||||
console.log('Ged 76-2 Part File Basename: ' + path.basename(valArray[0]))
|
||||
|
||||
for (x=0; x<valArray.length; x++) {
|
||||
console.log('Ged 77-1 Part File in: ' + valArray[x])
|
||||
console.log('Ged 77-2 Part File basename : ' + path.basename(valArray[x]))
|
||||
retArray.push(path.basename(valArray[x]).slice(0, -1));
|
||||
}
|
||||
retVal = retArray.join(wtconfig.get('ET.ArraySep', ' * '))
|
||||
|
@ -1563,7 +1557,7 @@ const etHelper = new class ETHELPER {
|
|||
|
||||
getIncludeInfo(){
|
||||
let includeInfo;
|
||||
log.debug(`etHelper (getIncludeInfo) - Started. libTypeSec is: ${this.Settings.libTypeSec} and levelName is: ${this.Settings.levelName}`);
|
||||
log.debug(`etHelper (getIncludeInfo) - Started. libTypeSec is: ${this.Settings.libTypeSec} and levelName is: ${this.Settings.levelName}`);
|
||||
try {
|
||||
includeInfo = defLevels[this.Settings.libTypeSec]['Include'][this.Settings.levelName];
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ const wtutils = new class WTUtils {
|
|||
|
||||
constructor() {
|
||||
this.logFileName = this.AppName + '.log';
|
||||
this.plexTVApi = 'https://plex.tv/api/';
|
||||
}
|
||||
|
||||
get ConfigFileName(){
|
||||
|
@ -548,11 +549,27 @@ const dialog = new class Dialog {
|
|||
buttonLabel : OKLabel,
|
||||
title: Title
|
||||
}
|
||||
|
||||
let dirName = dialog.showOpenDialogSync(WIN, options)
|
||||
log.debug('Returned directoryname is: ' + dirName)
|
||||
return dirName
|
||||
}
|
||||
|
||||
SelectFile(Title, OKLabel, filter, defaultPath)
|
||||
{
|
||||
log.debug('Start SelectFile Dialog');
|
||||
const {remote} = require('electron'),
|
||||
dialog = remote.dialog,
|
||||
WIN = remote.getCurrentWindow();
|
||||
let options = {
|
||||
properties:["openFile"],
|
||||
buttonLabel : OKLabel,
|
||||
title: Title,
|
||||
filters: filter,
|
||||
defaultPath: defaultPath
|
||||
}
|
||||
let fileName = dialog.showOpenDialogSync(WIN, options);
|
||||
log.debug('Returned filename is: ' + fileName)
|
||||
return fileName
|
||||
}
|
||||
|
||||
SaveFile(title, defaultPath, OKLabel) {
|
||||
|
@ -577,6 +594,20 @@ const dialog = new class Dialog {
|
|||
log.debug('Returned filename is: ' + filename)
|
||||
return filename
|
||||
}
|
||||
|
||||
ShowMsgBox(message, type, title, buttons){
|
||||
const {remote} = require('electron'),
|
||||
dialog = remote.dialog,
|
||||
|
||||
WIN = remote.getCurrentWindow();
|
||||
let options = {
|
||||
message: message,
|
||||
type: type,
|
||||
title: title,
|
||||
buttons: buttons
|
||||
}
|
||||
return dialog.showMessageBoxSync(WIN, options);
|
||||
}
|
||||
}
|
||||
|
||||
const github = new class GitHub {
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
@click="dvrRestore"
|
||||
icon-left="fas fa-file-download"
|
||||
icon-pack="fas"
|
||||
:disabled=!this.serverIsSelected
|
||||
variant="success"
|
||||
>
|
||||
{{ $t("Modules.PMS.DVR.lblBtnRestore") }}
|
||||
|
@ -66,7 +67,8 @@
|
|||
data() {
|
||||
return {
|
||||
optSelDVR: [],
|
||||
selDVR: ""
|
||||
selDVR: "",
|
||||
serverIsSelected: false
|
||||
};
|
||||
},
|
||||
created() {
|
||||
|
@ -79,6 +81,7 @@
|
|||
selectedServerAddress: async function(){
|
||||
log.info("DVR Selected server changed");
|
||||
this.optSelDVR = this.getDVRList();
|
||||
this.serverIsSelected = ( this.$store.getters.getSelectedServer != "none" );
|
||||
},
|
||||
doneDVRBackup: async function(){
|
||||
if (this.$store.getters.doneDVRBackup!='')
|
||||
|
@ -121,6 +124,7 @@
|
|||
tell user, and disable backup */
|
||||
async serverSelected() {
|
||||
let serverCheck = this.$store.getters.getSelectedServer;
|
||||
this.serverIsSelected = ( this.$store.getters.getSelectedServer != "none" );
|
||||
if (serverCheck == "none") {
|
||||
log.debug("serverCheck is none");
|
||||
this.selDVR = "";
|
||||
|
|
|
@ -4,15 +4,20 @@ const {JSONPath} = require('jsonpath-plus');
|
|||
console.log = log.log;
|
||||
|
||||
|
||||
import {wtconfig, wtutils} from '../../../General/wtutils';
|
||||
import {wtconfig, wtutils, dialog} from '../../../General/wtutils';
|
||||
import i18n from '../../../../../i18n';
|
||||
import store from '../../../../../store';
|
||||
import axios from 'axios';
|
||||
import { electron } from 'process';
|
||||
|
||||
i18n, wtconfig
|
||||
|
||||
const dvr = new class DVR {
|
||||
|
||||
constructor() {
|
||||
this.fileDVRRestore = '';
|
||||
this.dvrList = [];
|
||||
this.dvrKey = 0;
|
||||
this.deviceKey = 0;
|
||||
}
|
||||
|
||||
async getDVRList(){
|
||||
log.info(`Getting list of DVRs`);
|
||||
// Placeholder for return value
|
||||
|
@ -27,8 +32,8 @@ const dvr = new class DVR {
|
|||
url: url,
|
||||
headers: header
|
||||
})
|
||||
.then((response) => {
|
||||
log.debug('Response from getDVRList recieved');
|
||||
.then((response) => {
|
||||
log.debug('Response from getDVRList recieved');
|
||||
DVRs = JSONPath({path: '$..Dvr[*]', json: response.data});
|
||||
// Save to store
|
||||
store.commit('UPDATE_DVR_SETTINGS', DVRs);
|
||||
|
@ -44,27 +49,212 @@ const dvr = new class DVR {
|
|||
log.error('getDVRList: ' + error.message);
|
||||
}
|
||||
});
|
||||
DVRs.forEach(dvr => {
|
||||
arrDVR.push({
|
||||
"value": JSONPath({path: '$.uuid', json: dvr}),
|
||||
"text": JSONPath({path: '$.lineupTitle', json: dvr})
|
||||
})
|
||||
DVRs.forEach(dvr => {
|
||||
arrDVR.push({
|
||||
"value": JSONPath({path: '$.uuid', json: dvr}),
|
||||
"text": JSONPath({path: '$.lineupTitle', json: dvr})
|
||||
})
|
||||
});
|
||||
return arrDVR;
|
||||
this.dvrList = arrDVR;
|
||||
return arrDVR;
|
||||
}
|
||||
|
||||
async setDvrPrefs(){
|
||||
log.debug('Start DVR Settings');
|
||||
let url = '';
|
||||
let arrSettings = []
|
||||
const Settings = JSONPath({path: '$.Setting', json: this.fileDVRRestore});
|
||||
Settings[0].forEach(Setting => {
|
||||
arrSettings.push(Setting['id'] + '=' + Setting['value'])
|
||||
});
|
||||
url = `${store.getters.getSelectedServerAddress}/livetv/dvrs/${this.dvrKey}/prefs?` + arrSettings.join("&");
|
||||
let header = wtutils.PMSHeader;
|
||||
header['X-Plex-Token'] = store.getters.getSelectedServerToken;
|
||||
await axios({
|
||||
method: 'put',
|
||||
url: url,
|
||||
headers: header
|
||||
})
|
||||
.then((response) => {
|
||||
log.debug('Response from setDvrPrefs recieved');
|
||||
log.silly(`DVR Set as: ${JSON.stringify(response.data)}`);
|
||||
})
|
||||
.catch(function (error) {
|
||||
if (error.response) {
|
||||
log.error('setDvrPrefs: ' + error.response.data);
|
||||
alert(error.response.data.errors[0].code + " " + error.response.data.errors[0].message);
|
||||
} else if (error.request) {
|
||||
log.error('setDvrPrefs: ' + error.request);
|
||||
} else {
|
||||
log.error('setDvrPrefs: ' + error.message);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async setDevicePrefs(){
|
||||
log.debug('[dvr.js] Start Device Settings');
|
||||
let url = '';
|
||||
let arrSettings = []
|
||||
const Settings = JSONPath({path: '$..Device[0].Setting', json: this.fileDVRRestore});
|
||||
Settings[0].forEach(Setting => {
|
||||
arrSettings.push(Setting['id'] + '=' + Setting['value'])
|
||||
});
|
||||
url = `${store.getters.getSelectedServerAddress}/media/grabbers/devices/${this.deviceKey}/prefs?` + arrSettings.join("&");
|
||||
let header = wtutils.PMSHeader;
|
||||
header['X-Plex-Token'] = store.getters.getSelectedServerToken;
|
||||
await axios({
|
||||
method: 'put',
|
||||
url: url,
|
||||
headers: header
|
||||
})
|
||||
.then((response) => {
|
||||
log.debug('Response from setDevicePrefs recieved');
|
||||
log.silly(`setDevicePrefs Set as: ${JSON.stringify(response.data)}`);
|
||||
})
|
||||
.catch(function (error) {
|
||||
if (error.response) {
|
||||
log.error('setDevicePrefs: ' + error.response.data);
|
||||
alert(error.response.data.errors[0].code + " " + error.response.data.errors[0].message);
|
||||
} else if (error.request) {
|
||||
log.error('setDevicePrefs: ' + error.request);
|
||||
} else {
|
||||
log.error('setDvrPrefs: ' + error.message);
|
||||
}
|
||||
});
|
||||
const DvrTitle = encodeURIComponent(JSONPath({path: '$..Device[0].title', json: this.fileDVRRestore}));
|
||||
url = `${store.getters.getSelectedServerAddress}/media/grabbers/devices/${this.deviceKey}?title=${DvrTitle}&enabled=1`;
|
||||
await axios({
|
||||
method: 'put',
|
||||
url: url,
|
||||
headers: header
|
||||
})
|
||||
.then((response) => {
|
||||
log.debug('Response from setDeviceTitle recieved');
|
||||
log.silly(`setDeviceTitle Set as: ${JSON.stringify(response.data)}`);
|
||||
})
|
||||
.catch(function (error) {
|
||||
if (error.response) {
|
||||
log.error('setDeviceTitle: ' + error.response.data);
|
||||
alert(error.response.data.errors[0].code + " " + error.response.data.errors[0].message);
|
||||
} else if (error.request) {
|
||||
log.error('setDeviceTitle: ' + error.request);
|
||||
} else {
|
||||
log.error('setDeviceTitle: ' + error.message);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async setDeviceMapping(){
|
||||
console.log('Ged 0 ************ SET Device Mapping *********')
|
||||
new Promise((resolve) => {
|
||||
resolve
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/// This will create a DVR
|
||||
async createDVR(){
|
||||
console.log('Ged 1 CreateDVR started')
|
||||
let devices = [];
|
||||
// Store array of devices
|
||||
devices = JSONPath({path: '$..Device[*].uuid', json: this.fileDVRRestore});
|
||||
// To create the DVR, we should only use the first DVR
|
||||
const paramDevice = encodeURIComponent(devices[0]);
|
||||
// Now we need the DVR lineup
|
||||
const paramLineUp = encodeURIComponent(JSONPath({path: '$.lineup', json: this.fileDVRRestore}));
|
||||
// Get DVR Language
|
||||
const paramLang = JSONPath({path: '$.language', json: this.fileDVRRestore});
|
||||
// Get DVR Country
|
||||
const paramCountry = JSONPath({path: '$.country', json: this.fileDVRRestore});
|
||||
const url = `${store.getters.getSelectedServerAddress}/livetv/dvrs?device=${paramDevice}&lineup=${paramLineUp}&language=${paramLang}&country=${paramCountry}`
|
||||
let header = wtutils.PMSHeader;
|
||||
header['X-Plex-Token'] = store.getters.getSelectedServerToken;
|
||||
await axios({
|
||||
method: 'post',
|
||||
url: url,
|
||||
headers: header
|
||||
})
|
||||
.then((response) => {
|
||||
log.debug('Response from createDVR recieved');
|
||||
log.silly(`DVR Created as: ${JSON.stringify(response.data)}`);
|
||||
if (JSONPath({path: '$.MediaContainer.size', json: response.data}) == 0)
|
||||
{
|
||||
dialog.ShowMsgBox(i18n.t("Modules.PMS.DVR.selDeviceAlreadyUsed"), 'error', i18n.t("Modules.PMS.DVR.selAlredyPresentTitle"), [i18n.t("Common.Ok")]);
|
||||
}
|
||||
else
|
||||
{
|
||||
log.info(`DVR Created with UUID: ${JSONPath({path: '$.MediaContainer.Dvr[0].uuid', json: response.data})}`);
|
||||
this.dvrKey = JSONPath({path: '$.MediaContainer.Dvr[0].key', json: response.data});
|
||||
this.deviceKey = JSONPath({path: '$..Device[0].key', json: response.data});
|
||||
log.info(`DVR Created with Key: ${this.dvrKey}`);
|
||||
this.setDvrPrefs();
|
||||
this.setDevicePrefs();
|
||||
this.setDeviceMapping();
|
||||
}
|
||||
|
||||
|
||||
})
|
||||
.catch(function (error) {
|
||||
if (error.response) {
|
||||
log.error('createDVR: ' + error.response.data);
|
||||
alert(error.response.data.errors[0].code + " " + error.response.data.errors[0].message);
|
||||
} else if (error.request) {
|
||||
log.error('createDVR: ' + error.request);
|
||||
} else {
|
||||
log.error('createDVR: ' + error.message);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
console.log('Ged 57: ' + JSON.stringify(url))
|
||||
|
||||
|
||||
}
|
||||
|
||||
async restoreDVR (){
|
||||
console.log('Ged 70 restore start')
|
||||
|
||||
const dialogConfig = {
|
||||
title: 'Select a file',
|
||||
buttonLabel: 'This one will do',
|
||||
properties: ['openFile']
|
||||
};
|
||||
//const electron = require('electron');
|
||||
|
||||
electron.openDialog('showOpenDialog', dialogConfig)
|
||||
.then(result => console.log(result));
|
||||
log.info(`DVR Restore started`);
|
||||
await this.getDVRList();
|
||||
const filters = [{name: 'DVR Backups', extensions: ['json']}];
|
||||
const path = require('path');
|
||||
const defaultPath = path.join(wtconfig.get('General.ExportPath'), 'Plex Media Server', 'DVR', '\\');
|
||||
const selectFile = dialog.SelectFile( i18n.t("Modules.PMS.DVR.selRestoreFile"), i18n.t("Common.Ok"), filters, defaultPath);
|
||||
if (selectFile)
|
||||
{
|
||||
log.info(`Selected restore file is: ${selectFile}`);
|
||||
var fs = require('fs');
|
||||
this.fileDVRRestore = JSON.parse(fs.readFileSync(selectFile[0], 'utf8'));
|
||||
log.silly(`DVR Backup file contents`);
|
||||
log.silly(JSON.stringify(this.fileDVRRestore));
|
||||
const dvrTitle = String(JSONPath({path: '$.lineupTitle', json: this.fileDVRRestore}));
|
||||
//const msgBody = i18n.t("Modules.PMS.DVR.restoreMsg", [dvrTitle]);
|
||||
if ( dialog.ShowMsgBox(i18n.t("Modules.PMS.DVR.restoreMsg", [dvrTitle]), 'question', i18n.t("Modules.PMS.DVR.confirmRestore"), [i18n.t("Common.Ok"), i18n.t("Common.Cancel")]) == 0 )
|
||||
{
|
||||
// Check if DVR to restore is already present
|
||||
if ( JSON.stringify(this.dvrList).indexOf(dvrTitle) > -1 )
|
||||
{
|
||||
log.error(`Selected dvr was "${dvrTitle}" but is was already present on the PMS`)
|
||||
dialog.ShowMsgBox(i18n.t("Modules.PMS.DVR.selAlredyPresentMsg", [dvrTitle]), 'error', i18n.t("Modules.PMS.DVR.selAlredyPresentTitle"), [i18n.t("Common.Ok")]);
|
||||
}
|
||||
else
|
||||
{
|
||||
log.info('Starting DVR Restore');
|
||||
// Let's get the amount of devices
|
||||
const deviceCount = JSONPath({path: '$..Device.length', json: this.fileDVRRestore});
|
||||
if ( deviceCount < 1){
|
||||
dialog.ShowMsgBox(i18n.t("Modules.PMS.DVR.selMissingDevice", [dvrTitle]), 'error', i18n.t("Modules.PMS.DVR.selAlredyPresentTitle"), [i18n.t("Common.Ok")]);
|
||||
log.error('No devices found in backup file')
|
||||
}
|
||||
else
|
||||
{
|
||||
this.createDVR();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
log.info(`No files selected`);
|
||||
}
|
||||
}
|
||||
|
||||
async backupDVR( { dvrName } ){
|
||||
|
@ -94,7 +284,7 @@ const dvr = new class DVR {
|
|||
if (dvr['uuid']==uuid){
|
||||
retVal = dvr['lineupTitle'];
|
||||
}
|
||||
})
|
||||
})
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
|
196
src/components/modules/PMS/ViewState/ViewState.vue
Normal file
196
src/components/modules/PMS/ViewState/ViewState.vue
Normal file
|
@ -0,0 +1,196 @@
|
|||
<template>
|
||||
<b-container fluid>
|
||||
<div class="col-lg-10 col-md-12 col-xs-12">
|
||||
<h1>{{ $t("Modules.PMS.ViewState.Name") }}</h1>
|
||||
<p>{{ $t("Modules.PMS.ViewState.Description") }}</p>
|
||||
</div>
|
||||
|
||||
<div class="d-flex align-items-center">
|
||||
<b-form-group id="ViewStateSelSourceUsrGroup" v-bind:label="$t('Modules.PMS.ViewState.selSourceUsr')" label-size="lg" label-class="font-weight-bold pt-0" name="ViewStateSelSourceUsrGroup">
|
||||
<b-tooltip target="ViewStateSelSourceUsrGroup" triggers="hover">
|
||||
{{ $t('Modules.PMS.ViewState.ttSelSourceUsr') }}
|
||||
</b-tooltip>
|
||||
<b-form-select
|
||||
v-model="selSrcUsr"
|
||||
id="selSrcUsr"
|
||||
:options="optselSrcUsr"
|
||||
@change="selSrcUsrChanged"
|
||||
name="selSrcUsr">
|
||||
</b-form-select>
|
||||
</b-form-group>
|
||||
</div>
|
||||
<div ref="libSpinner" id="libSpinner" :hidden="WaitForUsers">
|
||||
<b-spinner id="libLoad" class="ml-auto text-danger"></b-spinner>
|
||||
</div>
|
||||
<div class="d-flex align-items-center">
|
||||
<b-form-group id="ViewStateSelTargetUsrGroup" v-bind:label="$t('Modules.PMS.ViewState.selTargetUsr')" label-size="lg" label-class="font-weight-bold pt-0" name="ViewStateSelTargetUsrGroup">
|
||||
<b-tooltip target="ViewStateSelTargetUsrGroup" triggers="hover">
|
||||
{{ $t('Modules.PMS.ViewState.ttSelTargetUsr') }}
|
||||
</b-tooltip>
|
||||
<b-form-select
|
||||
v-model="selTargetUsr"
|
||||
@change="selTargetUsrChanged"
|
||||
id="selTargetUsr"
|
||||
:options="optSelTargetUsr"
|
||||
name="selTargetUsr">
|
||||
</b-form-select>
|
||||
</b-form-group>
|
||||
</div>
|
||||
<br>
|
||||
<br>
|
||||
<div class="buttons">
|
||||
<!-- Buttons -->
|
||||
<div id="buttons" class="text-center">
|
||||
<b-button-group >
|
||||
<b-button
|
||||
class="mr-2"
|
||||
type="is-primary"
|
||||
@click="copyViewState"
|
||||
icon-left="fas fa-file-download"
|
||||
icon-pack="fas"
|
||||
:disabled="this.DisableCopy"
|
||||
variant="success"
|
||||
>
|
||||
{{ $t("Modules.PMS.ViewState.lblBtnCopy") }}
|
||||
</b-button>
|
||||
</b-button-group>
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
<b-container fluid> <!-- Status -->
|
||||
<b-row>
|
||||
<b-col sm="2">
|
||||
<label for="status">{{ $t('Modules.PMS.ViewState.Status.Names.Status') }}:</label>
|
||||
</b-col>
|
||||
<b-col sm="10">
|
||||
<b-form-textarea
|
||||
id="status"
|
||||
v-bind:placeholder="$t('Modules.PMS.ViewState.Status.Names.Status')"
|
||||
v-model="statusMsg"
|
||||
:disabled=true
|
||||
rows="1"
|
||||
max-rows="8">
|
||||
</b-form-textarea>
|
||||
</b-col>
|
||||
</b-row>
|
||||
</b-container>
|
||||
|
||||
|
||||
</b-container>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import i18n from '../../../../i18n';
|
||||
import store from '../../../../store';
|
||||
//import { wtconfig } from '../General/wtutils';
|
||||
import { viewstate } from "./scripts/viewstate";
|
||||
|
||||
const log = require("electron-log");
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
optselSrcUsr: [],
|
||||
optSelTargetUsr: [],
|
||||
selTargetUsr: "",
|
||||
selSrcUsr: "",
|
||||
serverIsSelected: false,
|
||||
WaitForUsers: false,
|
||||
statusMsg: 'Idle'
|
||||
};
|
||||
},
|
||||
async created() {
|
||||
log.info("[ViewState.vue] viewState Created");
|
||||
this.serverSelected();
|
||||
if (store.getters.getSelectedServer != 'none'){
|
||||
this.WaitForUsers = false;
|
||||
await viewstate.getUsers();
|
||||
this.optselSrcUsr = viewstate.viewStateUsers;
|
||||
this.optSelTargetUsr = viewstate.viewStateUsers;
|
||||
this.WaitForUsers = true;
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
// Watch for when selected server address is updated
|
||||
selectedServerAddress: async function(){
|
||||
log.info("ViewState selected server changed");
|
||||
console.log('Ged 1-1: ' + JSON.stringify(this.$store.getters.getViewStateStatus))
|
||||
viewstate.clearStatus();
|
||||
console.log('Ged 1-2: ' + JSON.stringify(this.$store.getters.getViewStateStatus))
|
||||
viewstate.updateStatusMsg(1, i18n.t("Modules.PMS.ViewState.Status.Msg.CollectUserInfo"));
|
||||
viewstate.SrcUsrKey = -1;
|
||||
viewstate.TargetUsrKey = -1;
|
||||
console.log('Ged 1-3: ' + JSON.stringify(this.$store.getters.getViewStateStatus))
|
||||
this.serverIsSelected = ( this.$store.getters.getSelectedServer != "none" );
|
||||
this.WaitForUsers = false;
|
||||
await viewstate.getServerToken();
|
||||
console.log('Ged 1-4: ' + JSON.stringify(this.$store.getters.getViewStateStatus))
|
||||
await viewstate.getUsers();
|
||||
console.log('Ged 1-5: ' + JSON.stringify(this.$store.getters.getViewStateStatus))
|
||||
this.optselSrcUsr = viewstate.viewStateUsers;
|
||||
this.optSelTargetUsr = viewstate.viewStateUsers;
|
||||
this.selSrcUsr = '';
|
||||
this.selTargetUsr = '',
|
||||
this.WaitForUsers = true;
|
||||
viewstate.updateStatusMsg(1, i18n.t("Modules.PMS.ViewState.Status.Msg.Idle"));
|
||||
console.log('Ged 1-6: ' + JSON.stringify(this.$store.getters.getViewStateStatus))
|
||||
},
|
||||
// Watch for status update
|
||||
viewStateStatus: function() {
|
||||
this.statusMsg = this.$store.getters.getViewStateStatus;
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
// We need this computed, for watching for changes to selected server
|
||||
selectedServerAddress: function(){
|
||||
return this.$store.getters.getSelectedServerAddress
|
||||
},
|
||||
DisableCopy : function(){
|
||||
// Only enable copy btn. if we have a server, users are selected and not identical
|
||||
return !(this.WaitForUsers&&(this.selTargetUsr)&&(this.selSrcUsr)&&(this.selTargetUsr!=this.selSrcUsr))
|
||||
},
|
||||
viewStateStatus: function(){
|
||||
return this.$store.getters.getViewStateStatus;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// SrcUsr changed
|
||||
async selSrcUsrChanged() {
|
||||
await viewstate.setKey( 'selSrcUsr', this.selSrcUsr);
|
||||
await viewstate.getLibs( this.selSrcUsr, this.selTargetUsr );
|
||||
},
|
||||
// SrcUsr changed
|
||||
async selTargetUsrChanged() {
|
||||
await viewstate.setKey( 'selTargetUsr', this.selTargetUsr );
|
||||
await viewstate.getLibs( this.selSrcUsr, this.selTargetUsr );
|
||||
},
|
||||
/* Check if a server is selected, and if not
|
||||
tell user, and disable copy */
|
||||
async serverSelected() {
|
||||
let serverCheck = this.$store.getters.getSelectedServer;
|
||||
this.serverIsSelected = ( this.$store.getters.getSelectedServer != "none" );
|
||||
if (serverCheck == "none") {
|
||||
log.debug("serverCheck is none");
|
||||
this.selDVR = "";
|
||||
this.$bvToast.toast(this.$t("Modules.PMS.ErrorNoServerSelectedMsg"), {
|
||||
title: this.$t("Modules.PMS.ErrorNoServerSelectedTitle"),
|
||||
autoHideDelay: 4000,
|
||||
solid: true,
|
||||
variant: 'primary',
|
||||
toaster: 'b-toaster-bottom-right'
|
||||
});
|
||||
}
|
||||
},
|
||||
async copyViewState(){
|
||||
viewstate.copyViewState( this.selSrcUsr, this.selTargetUsr );
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
||||
<style scoped>
|
||||
#sync-button {
|
||||
margin-left: 1em;
|
||||
}
|
||||
</style>
|
256
src/components/modules/PMS/ViewState/scripts/viewstate.js
Normal file
256
src/components/modules/PMS/ViewState/scripts/viewstate.js
Normal file
|
@ -0,0 +1,256 @@
|
|||
// Helper file for dvr.tv module
|
||||
const log = require('electron-log');
|
||||
const {JSONPath} = require('jsonpath-plus');
|
||||
console.log = log.log;
|
||||
|
||||
|
||||
import {wtutils} from '../../../General/wtutils';
|
||||
import i18n from '../../../../../i18n';
|
||||
import store from '../../../../../store';
|
||||
import axios from 'axios';
|
||||
|
||||
const viewstate = new class ViewState {
|
||||
// Private Fields
|
||||
#_FieldHeader = [];
|
||||
#_StartTime = null;
|
||||
#_EndTime = null;
|
||||
#_statusmsg = {};
|
||||
#_msgType = {
|
||||
1: i18n.t("Modules.PMS.ViewState.Status.Names.Status"),
|
||||
2: i18n.t("Modules.PMS.ViewState.Status.Names.LibsToProcess"),
|
||||
3: i18n.t("Modules.PMS.ViewState.Status.Names.StartTime")
|
||||
|
||||
}
|
||||
|
||||
constructor() {
|
||||
this.selServerServerToken = '',
|
||||
this.viewStateUsers = [],
|
||||
this.libs = {},
|
||||
this.SrcUsrKey = -1,
|
||||
this.TargetUsrKey = -1
|
||||
}
|
||||
|
||||
async setKey( Usr, data ){
|
||||
if ( Usr == 'selSrcUsr' ){
|
||||
this.SrcUsrKey = JSONPath({path: `$..libs[0].key`, json: data})
|
||||
if ( isNaN(this.SrcUsrKey) ){
|
||||
this.SrcUsrKey = -1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.TargetUsrKey = JSONPath({path: `$..libs[0].key`, json: data})
|
||||
if ( isNaN(this.TargetUsrKey) ){
|
||||
this.TargetUsrKey = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async getNowTime(StartEnd){
|
||||
let now = new Date();
|
||||
if (StartEnd == 'start')
|
||||
{
|
||||
this.#_StartTime = now;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.#_EndTime = now;
|
||||
}
|
||||
let hours = now.getHours();
|
||||
let minutes = now.getMinutes();
|
||||
let seconds = now.getSeconds();
|
||||
if ( hours.toString().length < 2) { hours = '0' + hours}
|
||||
if ( minutes.toString().length < 2) { minutes = '0' + minutes}
|
||||
if ( seconds.toString().length < 2) { seconds = '0' + seconds}
|
||||
return hours + ':' + minutes + ':' + seconds;
|
||||
}
|
||||
|
||||
async copyViewState( SrcUsr, TargetUsr ){
|
||||
log.info('[viewstate.js] Starting copyViewState');
|
||||
const startTime = await this.getNowTime('start');
|
||||
console.log('Ged 4 start time: ' + startTime)
|
||||
this.updateStatusMsg(3, startTime);
|
||||
|
||||
|
||||
console.log('Ged 1 SrcUsr: ' + JSON.stringify(SrcUsr))
|
||||
console.log('Ged 2 TargetUsr: ' + JSON.stringify(TargetUsr))
|
||||
|
||||
this.updateStatusMsg(1, i18n.t("Modules.PMS.ViewState.Status.Msg.Processing"));
|
||||
await this.getLibs( SrcUsr, TargetUsr );
|
||||
this.updateStatusMsg(1, "Ged")
|
||||
}
|
||||
|
||||
// Update status msg
|
||||
async updateStatusMsg(msgType, msg)
|
||||
{
|
||||
// Update relevant key
|
||||
this.#_statusmsg[msgType] = msg;
|
||||
// Tmp store of new msg
|
||||
let newMsg = '';
|
||||
// Walk each current msg keys
|
||||
Object.entries(this.#_statusmsg).forEach(([key, value]) => {
|
||||
if ( value != '')
|
||||
{
|
||||
newMsg += this.#_msgType[key] + ': ' + value + '\n';
|
||||
}
|
||||
})
|
||||
store.commit("UPDATE_viewStateStatus", newMsg);
|
||||
console.log('Ged 7 Msg: ' + JSON.stringify(newMsg))
|
||||
}
|
||||
|
||||
// Clear Status Window
|
||||
async clearStatus()
|
||||
{
|
||||
this.#_statusmsg = {};
|
||||
store.commit("UPDATE_viewStateStatus", '');
|
||||
return;
|
||||
}
|
||||
|
||||
async getLibs( SrcUsr, TargetUsr ){
|
||||
log.info('[viewstate.js] Starting getLibs');
|
||||
// Are both users selected ?
|
||||
if ( this.TargetUsrKey < 0 || this.SrcUsrKey < 0 ){
|
||||
return;
|
||||
}
|
||||
if ( JSON.stringify(SrcUsr) === JSON.stringify(TargetUsr) ){
|
||||
this.clearStatus();
|
||||
this.updateStatusMsg(1, i18n.t("Modules.PMS.ViewState.Status.Msg.Idle"));
|
||||
log.info('[viewstate.js] Same user selected, so aborting');
|
||||
return;
|
||||
}
|
||||
this.clearStatus();
|
||||
this.updateStatusMsg(1, i18n.t("Modules.PMS.ViewState.Status.Msg.GatheringLibs"));
|
||||
log.silly(`[viewstate.js] Source usr: ${JSON.stringify(SrcUsr)}`);
|
||||
log.silly(`[viewstate.js] Target usr: ${JSON.stringify(TargetUsr)}`);
|
||||
this.libs = {};
|
||||
if ( JSONPath({path: `$..libs[0].key`, json: SrcUsr}) == 0 )
|
||||
{
|
||||
// We need to add all libs from target usr
|
||||
log.debug(`[viewstate.js] SrcUsr is owner`);
|
||||
for(let i of TargetUsr["libs"]) {
|
||||
this.libs[i.key] = i.title;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( JSONPath({path: `$..libs[0].key`, json: TargetUsr}) == 0 ){
|
||||
// We need to add all libs from Source usr
|
||||
log.debug(`[viewstate.js] TargetUsr is owner`);
|
||||
for(let i of SrcUsr["libs"]) {
|
||||
this.libs[i.key] = i.title;
|
||||
}
|
||||
}
|
||||
else {
|
||||
for(let i of SrcUsr["libs"]) {
|
||||
if ( JSON.stringify(TargetUsr["libs"]).indexOf(JSON.stringify(i)) > -1)
|
||||
{
|
||||
this.libs[i.key] = i.title;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
let libstatus = []
|
||||
for (let lib in this.libs){
|
||||
libstatus.push(this.libs[lib])
|
||||
}
|
||||
this.updateStatusMsg(1, i18n.t("Modules.PMS.ViewState.Status.Msg.Idle"));
|
||||
this.updateStatusMsg(2, libstatus.join(', '))
|
||||
}
|
||||
|
||||
// Here we get the server token for the selected server
|
||||
async getServerToken(){
|
||||
// Start by finding selected servers clientIdentifier
|
||||
const clientIdentifier = store.getters.getSelectedServer.clientIdentifier;
|
||||
// Ask for a list of devices
|
||||
let header = wtutils.PMSHeader;
|
||||
header['X-Plex-Token'] = store.getters.getAuthToken;
|
||||
const url = `${wtutils.plexTVApi}v2/devices`;
|
||||
await axios({
|
||||
method: 'get',
|
||||
url: url,
|
||||
headers: header
|
||||
})
|
||||
.then((response) => {
|
||||
log.debug('[viewState.js] Response from getServerToken recieved');
|
||||
//log.silly(`getServerToken returned as: ${JSON.stringify(response.data)}`);
|
||||
this.selServerServerToken = JSONPath({path: `$[?(@.clientIdentifier== '${clientIdentifier}')].token`, json: response.data});
|
||||
log.silly(`[viewState.js] selServerServerToken returned as: ${this.selServerServerToken}`);
|
||||
})
|
||||
.catch(function (error) {
|
||||
if (error.response) {
|
||||
log.error('[viewState.js] getServerToken: ' + error.response.data);
|
||||
alert(error.response.data.errors[0].code + " " + error.response.data.errors[0].message);
|
||||
} else if (error.request) {
|
||||
log.error('[viewState.js] getServerToken: ' + error.request);
|
||||
} else {
|
||||
log.error('[viewState.js] getServerToken: ' + error.message);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Get selected server sharelist
|
||||
async getShareList(){
|
||||
log.info('[viewState.js] Start getShareList');
|
||||
// We can't use the normal header
|
||||
let header = {
|
||||
'Accept': 'application/json',
|
||||
'X-Plex-Token': this.selServerServerToken[0]
|
||||
};
|
||||
const url = `${wtutils.plexTVApi}v2/server/sharing`;
|
||||
let retVal
|
||||
await axios({
|
||||
method: 'get',
|
||||
url: url,
|
||||
headers: header
|
||||
})
|
||||
.then((response) => {
|
||||
log.debug('[viewState.js] Response from getShareList recieved');
|
||||
log.silly(`[viewState.js] getShareList returned as: ${JSON.stringify(response.data)}`);
|
||||
retVal = JSON.stringify(response.data)
|
||||
})
|
||||
.catch(function (error) {
|
||||
if (error.response) {
|
||||
log.error('[viewState.js] getShareList1: ' + JSON.stringify(error.response.data));
|
||||
alert(error.response.data.errors[0].code + " " + error.response.data.errors[0].message);
|
||||
} else if (error.request) {
|
||||
log.error('[viewState.js] getShareList2: ' + error.request);
|
||||
} else {
|
||||
log.error('[viewState.js] getShareList3: ' + error.message);
|
||||
}
|
||||
});
|
||||
return retVal
|
||||
}
|
||||
|
||||
// Get a list of users
|
||||
async getUsers(){
|
||||
log.info('[viewState.js] Start getUsers');
|
||||
let Users = store.getters.getUsers;
|
||||
// Already got the users ?
|
||||
if (Object.keys(Users).length == 0){
|
||||
await store.dispatch('fetchUsers');
|
||||
Users = store.getters.getUsers;
|
||||
}
|
||||
await this.getServerToken();
|
||||
this.viewStateUsers = [];
|
||||
// Get a list of users only on this server
|
||||
let shareList = await this.getShareList();
|
||||
// Now we need to walk them one by one
|
||||
for(const sharedUsr of JSON.parse(shareList)) {
|
||||
let name = Users[sharedUsr['id']]["friendlyName"];
|
||||
if (!name){
|
||||
name = Users[sharedUsr['id']]["title"];
|
||||
}
|
||||
if (!Users[sharedUsr['id']]["email"])
|
||||
{
|
||||
name = `${name} ***( ${i18n.t("Modules.PMS.ViewState.Managed")} )***`
|
||||
}
|
||||
let usr = { value: { "id": sharedUsr['id'], "libs": sharedUsr['librarySections']}, text: name };
|
||||
this.viewStateUsers.push(usr);
|
||||
}
|
||||
// Now we need to add Server Owner
|
||||
let usr = { value: { "id": `${store.getters.getMeId}`, "libs": [{"id":null,"key":0,"title":"*","type":"*"}]}, text: `${store.getters.getPlexName} ***( ${i18n.t("Modules.PMS.ViewState.Owner")} )***` };
|
||||
this.viewStateUsers.push(usr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export { viewstate };
|
|
@ -33,7 +33,7 @@
|
|||
<b-form-input id="usrEmail" name="usrEmail" type="text" class="form-control" v-model="usrEmail" :disabled=true></b-form-input>
|
||||
</b-input-group>
|
||||
<b-input-group id="UserRestrictedGrp" :prepend="$t('Modules.PlexTV.UsrRestricted')" class="mt-3">
|
||||
<b-form-input id="usrRestricted" name="usrRestricted" class="form-control" v-model="usrRestricted" :disabled=true></b-form-input>
|
||||
<b-form-input id="usrRestricted" name="usrRestricted" class="form-control" v-model="usrRestricted" :disabled=true></b-form-input>
|
||||
</b-input-group>
|
||||
<b-input-group id="UserThumbGrp" :prepend="$t('Modules.PlexTV.UsrThumb')" class="mt-3">
|
||||
<b-form-input id="usrThumb" name="usrThumb" type="text" class="form-control" v-model="usrThumb" :disabled=true></b-form-input>
|
||||
|
|
|
@ -15,14 +15,14 @@ function loadLocaleMessages () {
|
|||
// Force read en lang, since it's the fallback
|
||||
const langCode = 'en'
|
||||
var langFile = wtutils.Home + '/locales/' + langCode + '.json'
|
||||
log.debug(`Loading language: ${langCode}`)
|
||||
log.debug(`[i18n.js] (loadLocaleMessages) Loading language: ${langCode}`)
|
||||
messages[langCode] = JSON.parse(fs.readFileSync(langFile, 'utf8'));
|
||||
log.debug(`Defined language: ${wtconfig.get('General.language')}`)
|
||||
log.debug(`[i18n.js] (loadLocaleMessages) Defined language: ${wtconfig.get('General.language')}`)
|
||||
if (wtconfig.get('General.language', 'en') != 'en'){
|
||||
// We need to preload an additional language
|
||||
const langCode = wtconfig.get('General.language')
|
||||
langFile = wtutils.Home + '/locales/' + langCode + '.json'
|
||||
log.debug(`Loading language: ${langCode}`)
|
||||
log.debug(`[i18n.js] (loadLocaleMessages) Loading language: ${langCode}`)
|
||||
messages[langCode] = JSON.parse(fs.readFileSync(langFile, 'utf8'));
|
||||
}
|
||||
return messages
|
||||
|
|
16
src/main.js
16
src/main.js
|
@ -32,9 +32,9 @@ log.transports.console.level = wtconfig.get('Log.consoleLevel', 'silly');
|
|||
// Set logfile to 10Mb
|
||||
log.transports.file.maxSize = wtconfig.get('Log.maxSize', 1048576);
|
||||
log.info('*********************************')
|
||||
log.info(`Starting ${wtutils.AppName} Version: ${wtutils.AppVersion}`);
|
||||
log.info(`Running on ${wtutils.RunningOS}`);
|
||||
log.info(`Log level set to ${log.transports.file.level}`);
|
||||
log.info(`[main.js] Starting ${wtutils.AppName} Version: ${wtutils.AppVersion}`);
|
||||
log.info(`[main.js] Running on ${wtutils.RunningOS}`);
|
||||
log.info(`[main.js] Log level set to ${log.transports.file.level}`);
|
||||
// Logging ended
|
||||
|
||||
// Log Commandline Params
|
||||
|
@ -53,7 +53,7 @@ params.forEach(param => {
|
|||
// Handles dev stuff from Json
|
||||
const token = wtconfig.get('Developer.X-Plex-Token', '');
|
||||
if ( token != ''){
|
||||
log.verbose(`Logging in with Dev Token`);
|
||||
log.verbose(`[main.js] Logging in with Dev Token`);
|
||||
store.commit("UPDATE_AUTHTOKEN", token);
|
||||
}
|
||||
|
||||
|
@ -67,19 +67,19 @@ if (wtconfig.get("general.version", "") != wtutils.AppVersion){
|
|||
var fs = require('fs');
|
||||
var prefs = JSON.parse(fs.readFileSync(wtutils.ConfigFileName, 'utf8'));
|
||||
delete prefs ['Developer'];
|
||||
log.verbose('***** Prefs *****');
|
||||
log.verbose('[main.js] ***** Prefs *****');
|
||||
log.verbose(prefs);
|
||||
log.verbose('***** Prefs Ended *****');
|
||||
log.verbose('[main.js] ***** Prefs Ended *****');
|
||||
|
||||
// Get saved language to use, and default to en
|
||||
i18n.locale = wtconfig.get('General.language', 'en');
|
||||
|
||||
// App Menu Bar
|
||||
log.verbose('Starting to build App Menu');
|
||||
log.verbose('[main.js] Starting to build App Menu');
|
||||
const menuTemplate = require('./components/layout/script/menubar');
|
||||
const menu = require('electron').remote.Menu.buildFromTemplate(menuTemplate.default);
|
||||
require('electron').remote.Menu.setApplicationMenu(menu);
|
||||
log.verbose('App Menu builded');
|
||||
log.verbose('[main.js] App Menu builded');
|
||||
|
||||
Vue.config.productionTip = false;
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ import Butler from '../components/modules/PMS/Butler/butler';
|
|||
import Language from '../components/modules/Main/Language.vue';
|
||||
import GlobalSettings from '../components/modules/Main/GlobalSettings';
|
||||
import DVR from '../components/modules/PMS/DVR/DVR';
|
||||
import ViewState from '../components/modules/PMS/ViewState/ViewState';
|
||||
import About from '../components/modules/Main/About';
|
||||
import Store from '../store/index.js';
|
||||
|
||||
|
@ -76,6 +77,12 @@ Vue.use(VueRouter)
|
|||
component: Butler,
|
||||
meta: {requiresAuth: true}
|
||||
},
|
||||
{
|
||||
path: '/pms/viewstate',
|
||||
name: "viewstate",
|
||||
component: ViewState,
|
||||
meta: {requiresAuth: true}
|
||||
},
|
||||
{
|
||||
path: '/plextv',
|
||||
name: "plextv",
|
||||
|
|
|
@ -6,6 +6,7 @@ import poeditor from './modules/poeditor';
|
|||
import et from './modules/et';
|
||||
import language from './modules/language';
|
||||
import pms from './modules/pms';
|
||||
import viewstate from './modules/viewstate';
|
||||
|
||||
Vue.use(Vuex);
|
||||
|
||||
|
@ -18,7 +19,7 @@ export default new Vuex.Store({
|
|||
state: {
|
||||
},
|
||||
mutations: {},
|
||||
getters: {
|
||||
getters: {
|
||||
},
|
||||
actions: {},
|
||||
modules: {
|
||||
|
@ -26,7 +27,8 @@ export default new Vuex.Store({
|
|||
poeditor,
|
||||
et,
|
||||
language,
|
||||
pms
|
||||
pms,
|
||||
viewstate
|
||||
},
|
||||
plugins: [vuexLocal.plugin]
|
||||
})
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
//import {et, excel2} from '../../components/modules/ExportTools/scripts/et'
|
||||
//import {et} from '../../components/modules/ExportTools/scripts/et'
|
||||
import { etHelper } from '../../components/modules/ExportTools/scripts/ethelper'
|
||||
|
||||
const log = require('electron-log');
|
||||
|
|
|
@ -15,7 +15,8 @@ const state = {
|
|||
authToken: '',
|
||||
avatar: '',
|
||||
plexname: '',
|
||||
users: {}
|
||||
users: {},
|
||||
MeId: ''
|
||||
};
|
||||
|
||||
const mutations = {
|
||||
|
@ -44,6 +45,9 @@ const mutations = {
|
|||
UPDATE_PLEXNAME(state, value){
|
||||
state.plexname = value;
|
||||
},
|
||||
UPDATE_MeId(state, value){
|
||||
state.MeId = value;
|
||||
},
|
||||
UPDATE_USERS(state, value){
|
||||
state.users = value;
|
||||
}
|
||||
|
@ -56,7 +60,7 @@ const actions = {
|
|||
header['X-Plex-Token'] = getters.getAuthToken;
|
||||
await axios({
|
||||
method: 'get',
|
||||
url: 'https://plex.tv/api/v2/friends',
|
||||
url: `${wtutils.plexTVApi}v2/friends`,
|
||||
headers: header
|
||||
})
|
||||
.then((response) => {
|
||||
|
@ -84,7 +88,7 @@ const actions = {
|
|||
header['X-Plex-Token'] = getters.getAuthToken;
|
||||
axios({
|
||||
method: 'get',
|
||||
url: 'https://plex.tv/api/v2/resources',
|
||||
url: `${wtutils.plexTVApi}v2/resources`,
|
||||
headers: header,
|
||||
params: {
|
||||
'includeHttps' : '1',
|
||||
|
@ -134,7 +138,7 @@ const actions = {
|
|||
},
|
||||
loginToPlex({ commit }, payload){
|
||||
log.info("loginToPlex called")
|
||||
var url = 'https://plex.tv/api/v2/users/signin';
|
||||
var url = `${wtutils.plexTVApi}v2/users/signin`;
|
||||
url = url + '?login=' + require('querystring').escape(payload.username);
|
||||
url = url + '&password=' + require('querystring').escape(payload.password);
|
||||
if ( payload.twoFA ){
|
||||
|
@ -151,6 +155,7 @@ const actions = {
|
|||
commit('UPDATE_AUTHENTICATED', true)
|
||||
commit('UPDATE_AVATAR', response.data.thumb)
|
||||
commit('UPDATE_PLEXNAME', response.data.username)
|
||||
commit('UPDATE_MeId', response.data.id)
|
||||
router.replace({name: "home"});
|
||||
})
|
||||
.catch(function (error) {
|
||||
|
@ -183,18 +188,24 @@ const actions = {
|
|||
},
|
||||
loginToPlexWithToken({ commit }, payload){
|
||||
log.info("loginToPlex called, using a Token")
|
||||
let header = wtutils.PMSHeader;
|
||||
//header['X-Plex-Token'] = payload.token;
|
||||
//const url = `${wtutils.plexTVApi}v2/users/signin.json?X-Plex-Token=${payload.token}`;
|
||||
const url = 'https://plex.tv/users/sign_in.json?X-Plex-Token=' + payload.token;
|
||||
axios({
|
||||
method: 'POST',
|
||||
url: url,
|
||||
headers: wtutils.PMSHeader
|
||||
headers: header
|
||||
})
|
||||
.then(function (response) {
|
||||
log.debug('loginToPlex: Response from fetchPlexServers recieved')
|
||||
|
||||
console.log('Gedd 66 Me: ' + JSON.stringify(response.data.user))
|
||||
commit('UPDATE_AUTHTOKEN', response.data.user.authToken)
|
||||
commit('UPDATE_AUTHENTICATED', true)
|
||||
commit('UPDATE_AVATAR', response.data.user.thumb)
|
||||
commit('UPDATE_PLEXNAME', response.data.user.username)
|
||||
commit('UPDATE_MeId', response.data.id)
|
||||
router.replace({name: "home"});
|
||||
})
|
||||
.catch(function (error) {
|
||||
|
@ -227,6 +238,7 @@ const getters = {
|
|||
getAuthToken: state => state.authToken,
|
||||
getAvatar: state => state.avatar,
|
||||
getPlexName: state => state.plexname,
|
||||
getMeId: state => state.MeId,
|
||||
getSelectedServer: state => state.selectedServer,
|
||||
getSelectedServerAddress: state => state.selectedServerAddress,
|
||||
getSelectedServerAddressUpdateInProgress: state => state.selectedServerAddressUpdateInProgress,
|
||||
|
|
27
src/store/modules/viewstate.js
Normal file
27
src/store/modules/viewstate.js
Normal file
|
@ -0,0 +1,27 @@
|
|||
//import { etHelper } from '../../components/modules/ExportTools/scripts/ethelper'
|
||||
|
||||
const log = require('electron-log');
|
||||
console.log = log.log;
|
||||
|
||||
const state = {
|
||||
viewStateStatus: ''
|
||||
};
|
||||
|
||||
const mutations = {
|
||||
UPDATE_viewStateStatus(state, payload) {
|
||||
state.viewStateStatus = payload
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const getters = {
|
||||
getViewStateStatus: state => state.viewStateStatus
|
||||
};
|
||||
|
||||
const viewstateModule = {
|
||||
state,
|
||||
mutations,
|
||||
getters
|
||||
}
|
||||
|
||||
export default viewstateModule;
|
Loading…
Reference in a new issue