Merge branch 'master' into translate

This commit is contained in:
UKDTOM 2022-01-01 23:40:48 +01:00
commit 683a91841f
27 changed files with 6745 additions and 3866 deletions

33
.github/workflows/release.yml vendored Normal file
View file

@ -0,0 +1,33 @@
name: Build/release
on:
push:
branches:
- release
jobs:
release:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [macos-latest, ubuntu-latest, windows-latest]
# os: [macos-latest]
# os: [ubuntu-latest, windows-latest]
# os: [windows-latest]
steps:
- name: Check out Git repository
uses: actions/checkout@v1
- name: Setup Node.js
uses: actions/setup-node@master
with:
node-version: 14.16
- name: Install dependencies
run: npm install
- name: see directory with dependencies
run: ls
- name: Deploy Releases
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: npm run deploy

View file

@ -1,16 +1,52 @@
# ![Logo](https://github.com/WebTools-NG/WebTools-NG/blob/master/src/assets/WebTools-48x48.png) WebTools-ng Change log
## V0.3.12
## V0.3.13
**Note**: This version is an Beta version
**Note 2**: This version is a huge refactoring of Export module, due to memory issues
**Note 3**: In this version, the following is disabled:
* Export to xlsx format ([See #331](https://github.com/WebTools-NG/WebTools-NG/issues/331))
* Photo export
**Changes**:
* [#395 Show alert if we can't connect to plex.tv](https://github.com/WebTools-NG/WebTools-NG/issues/395)
* [#399 [RFE] ET: Consider splitting outfile into many](https://github.com/WebTools-NG/WebTools-NG/issues/399)
* [#396 [RFE] ET: Seperate xlsx and csv export](https://github.com/WebTools-NG/WebTools-NG/issues/396)
* [#410 [RFE] ET: Add sub category to export file name](https://github.com/WebTools-NG/WebTools-NG/issues/410)
* [#407 Can't export libraries with a forward slash (/) in the name](https://github.com/WebTools-NG/WebTools-NG/issues/407)
* [#412 [RFE] ET: Export should allow us to export in smaller chunks](https://github.com/WebTools-NG/WebTools-NG/issues/412)
* [#413 Translations should be in it's own branch](https://github.com/WebTools-NG/WebTools-NG/issues/413)
* [#418 If selected qualifier in string things break](https://github.com/WebTools-NG/WebTools-NG/issues/418)
* [#386 When exporting using ExportTools, the ' is missing from the Column "Part File Combined"](https://github.com/WebTools-NG/WebTools-NG/issues/386)
* [#420 ET Refactor Movies Verify all fields are quoted correctly](https://github.com/WebTools-NG/WebTools-NG/issues/420)
* [#404 Exporting issues with delimiters under windows](https://github.com/WebTools-NG/WebTools-NG/issues/404)
* [#408 Poster export stops when no poster attached to a Plex movie](https://github.com/WebTools-NG/WebTools-NG/issues/408)
* Removed `YEAR` from Episode, since not avail
* Added `Item Counts` to Shows Export
* [#425 ET Level 1 Export progress](https://github.com/WebTools-NG/WebTools-NG/issues/425)
* [#426 Replace format chars in text fields](https://github.com/WebTools-NG/WebTools-NG/issues/426)
## V0.3.12 (20210709)
**Note**: This version is an Beta version
* [#382 Exporting Posters and Art not working (Revisit)](https://github.com/WebTools-NG/WebTools-NG/issues/382)
* [#381 Duplicate setting in Global Settings](https://github.com/WebTools-NG/WebTools-NG/issues/381)
## V0.3.11
## V0.3.11 (20210707)
**Note**: This version is an Beta version
* [#384 I need better error logging for Poster Export](https://github.com/WebTools-NG/WebTools-NG/issues/384)
* [#382 Exporting Posters and Art not working](https://github.com/WebTools-NG/WebTools-NG/issues/382)
## V0.3.10
## V0.3.10 (20210531)
**Note**: This version is an Beta version
* [#366 if possible allow lan only connections](https://github.com/WebTools-NG/WebTools-NG/issues/366)
* [#373 Remove setting from ExportTools Settings](https://github.com/WebTools-NG/WebTools-NG/issues/373)
@ -18,7 +54,9 @@
NOTE: Hight and Width has been reversed for Poster and Art Export!
## V0.3.9
## V0.3.9 (20210520)
**Note**: This version is an Beta version
* [#359 ET: Log time it took](https://github.com/WebTools-NG/WebTools-NG/issues/359)
* [#364 ET: Make status windows better when exporting](https://github.com/WebTools-NG/WebTools-NG/issues/364)
@ -26,20 +64,29 @@ NOTE: Hight and Width has been reversed for Poster and Art Export!
## V0.3.8
**Note**: This version is an Beta version
* [#357 Default "Original Title" to "Title", if empty](https://github.com/WebTools-NG/WebTools-NG/issues/357)
* [#358 PMS page size](https://github.com/WebTools-NG/WebTools-NG/issues/358)
* [#360 ET Audio Export is empty](https://github.com/WebTools-NG/WebTools-NG/issues/360)
/issues/358)
## V0.3.7
**Note**: This version is an Beta version
* [#355 ET no output produced](https://github.com/WebTools-NG/WebTools-NG/issues/355)
## V0.3.6
**Note**: This version is an Beta version
* [#353 Levels can't be selected](https://github.com/WebTools-NG/WebTools-NG/issues/353)
## V0.3.5
**Note**: This version is an Beta version
* [#339 IMDB ID not available for movies](https://github.com/WebTools-NG/WebTools-NG/issues/339)
* [#342 Rename "Export Arts"](https://github.com/WebTools-NG/WebTools-NG/issues/342)
* [#345 Switch ET Export type selection](https://github.com/WebTools-NG/WebTools-NG/issues/345)
@ -48,6 +95,8 @@ NOTE: Hight and Width has been reversed for Poster and Art Export!
## V0.3.4
**Note**: This version is an Beta version
* [#306 Export posters and Art](https://github.com/WebTools-NG/WebTools-NG/issues/306)
## V0.3.3

View file

@ -7,6 +7,7 @@
[![master](https://img.shields.io/badge/master-stable-green.svg?maxAge=2592000)]('')
![Maintenance](https://img.shields.io/badge/Maintained-Yes-green.svg)
[![CodeQL](https://github.com/WebTools-NG/WebTools-NG/workflows/CodeQL/badge.svg)](https://github.com/WebTools-NG/WebTools-NG/actions?query=workflow%3ACodeQL)
[![Build/release](https://github.com/WebTools-NG/WebTools-NG/actions/workflows/build.yml/badge.svg?branch=release)](https://github.com/WebTools-NG/WebTools-NG/actions/workflows/build.yml)
NOTE: This is currently in **BETA**

7797
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,7 +1,7 @@
{
"name": "webtools-ng",
"productName": "WebTools-NG",
"version": "0.3.12",
"version": "0.3.13",
"description": "WebTools Next Generation 4 Plex",
"author": "dane22 & CPSO",
"license": "MPL-2.0",
@ -14,6 +14,9 @@
"build": "run-script-os",
"build:darwin:linux": "chmod +x script/getGitVer.sh && . script/getGitVer.sh && vue-cli-service electron:build && unset AppRev",
"build:win32": "script\\getGitVer.cmd && vue-cli-service electron:build",
"deploy": "run-script-os",
"deploy:win32": "script\\getGitVer.cmd && vue-cli-service electron:build --publish always",
"deploy:darwin:linux": "chmod +x script/getGitVer.sh && . script/getGitVer.sh && vue-cli-service electron:build --publish always && unset AppRev",
"lint": "vue-cli-service lint",
"i18n:report": "vue-cli-service i18n:report --src './src/**/*.?(js|vue)' --locales './src/locales/**/*.json'",
"postinstall": "electron-builder install-app-deps",

View file

@ -40,7 +40,9 @@
"LoginBtn": "Sign in",
"twoFA": "2Factor Authentication verification code",
"twoFAPrompt": "If using 2FA, enter your code here, else leave as blank (optional)",
"Missing2FACode": "Please enter the verification code"
"Missing2FACode": "Please enter the verification code",
"LoginConnectErrToken": "Could not connect to plex.tv with a Token",
"LoginConnectErr": "Could not connect to plex.tv"
},
"SelServer": "Select Server",
"Menu": {
@ -143,13 +145,19 @@
"SortTitleNull": "Default \"Sort Title\" to \"Title\", if empty",
"AutoXLSCol": "Autosize column (xlsx only)",
"AutoXLSRow": "Autosize row (xlsx only)",
"ExportToExcel": "Export to xlsx as well as csv",
"ExportToExcel": "Export to xlsx",
"ExportToCSV": "Export to csv",
"NotAvailIndicator": "What to use if a field can't be found",
"QualifierCSV": "Qualifier to use with a text based field for CSV (Use space for none)",
"Posters_Dimensions": "Poster width * height",
"Posters_Dimensions_TT": "Poster width*height, If 'Export Posters' is a field in the export. Can be separated by a comma, for multiple exports, like `75*75, 1024*768`. Note: dimensions might be altered slightly in order to preserve the aspect ratio of the poster",
"Art_Dimensions": "Art width * height",
"Art_Dimensions_TT": "Art width*height, If 'Export Art' is a field in the export. Can be seperated by a comma, for multiple exports, like `75*75, 1024*768`. Note: dimensions might be altered slightly in order to preserve the aspect ratio of the art"
"Art_Dimensions_TT": "Art width*height, If 'Export Art' is a field in the export. Can be seperated by a comma, for multiple exports, like `75*75, 1024*768`. Note: dimensions might be altered slightly in order to preserve the aspect ratio of the art",
"ChReturn": "Replace Return character with",
"ChReturn_TT": "Leave blank to not replace",
"ChNewLine": "Replace NewLine character with",
"ChNewLine_TT": "Leave blank to not replace"
},
"LevelInfo": "Export level determines which data are going to be exported.",
"SelectLevel": "Select level",
@ -181,6 +189,8 @@
"ErrorBadSep": "Column separator can only be one character",
"ErrorNoServerSelectedTitle": "No server selected",
"ErrorNoServerSelectedMsg": "You need to select a server to export from",
"ErrorNoOutputFormatTitle": "No output format selected",
"ErrorNoOutputFormatMsg": "You need to select an output format in the @:Modules.ET.Name settings, like csv or xlsx",
"Custom": {
"Title": "Custom levels",
"Description": "A custom level allows you to create your own export levels",
@ -246,7 +256,16 @@
"ttExpLibrary": "Here you select the library to export",
"ttExpTypeSec": "Here you select the sub type",
"ttExpType": "Here you select the type of library you want to export",
"SecPlaylists": "Playlists"
"SecPlaylists": "Playlists",
"itemStart": "The starting item (Normally 0)",
"itemEnd": "The ending item (Normally the last item in the library)",
"startStopDesc": "Here you have the option to define what item to start exporting with,",
"startStopDesc2": "as well as specifying the item to end the export.",
"startStopDesc3": "Use this to split export files into smaller chuncks (files) if needed.",
"startStopDesc4": "We default to export everything.",
"startStopStartingItem": "Item to start with",
"startStopEndingItem": "Item to end with",
"startStopTitle": "Limit Export"
}
},
"About": {

28
script/release.sh Executable file
View file

@ -0,0 +1,28 @@
# Release from master into a draft release
# Get current branch
CURBRANCH=$(git rev-parse --abbrev-ref HEAD)
echo $CURBRANCH
# Checkout Master Branch
git checkout master
# Make sure Master Branch locally is updated
git pull
# Checkout Release Branch
git checkout release
# Update Release Branch from Master
git merge master
# Get current version
CURVER=$(cat package.json|grep -oP '(?<="version": ")[^"]*')
echo $CURVER
# Get git root directory
root=$(git rev-parse --show-toplevel 2>&1)
# get commit hash for version file
rev=$(git rev-parse --short HEAD 2>&1)
echo Committing v$CURVER.$rev
# Commit to Release Branch
git commit -am v$CURVER.$rev
# Tag Release Branch
git tag v$CURVER.$rev
# Upload and trigger a release
git push && git push --tags
git checkout $CURBRANCH

View file

@ -0,0 +1,18 @@
# Release Note
For a complete manual, see the [Wiki](https://github.com/WebTools-NG/WebTools-NG/wiki)
What's new:
Please see the [Change Log](https://github.com/WebTools-NG/WebTools-NG/blob/master/CHANGELOG.md)
This is a BETA release
Note that the binaries are not signed, since we cannot afford a signing certificate nor a dev membership with Apple
* See [Special MAC Work Around](https://github.com/WebTools-NG/WebTools-NG/wiki/Known-Issues#-mac-os)
Depending on your workstation OS, grab the following file from the assets below:
Windows: Use the exe file
Mac: Use the dmg file
Linux: Use the AppImage file

View file

@ -30,6 +30,7 @@ function createWindow () {
// Create the browser window.
win = new BrowserWindow({ width: 1024, height: 768, icon: __dirname + "/../src/assets/WebTools-512.png", webPreferences: {
nodeIntegration: true,
contextIsolation: false,
webSecurity: false,
enableRemoteModule: true
} })
@ -127,11 +128,11 @@ ipcMain.on('downloadFile', function (event, data) {
event.sender.send('downloadEnd');
})
response.data.on('error', (error) => {
log.error(`Failed to download ${item.split('&X-Plex-Token=')[0]}`);
log.error(`background (downloadFile): Failed to download ${item.split('&X-Plex-Token=')[0]}`);
event.sender.send('downloadError', error);
})
}).catch((error) => {
log.error(`Failed to download ${item.split('&X-Plex-Token=')[0]}`);
log.error(`background (downloadFile): ${item.split('&X-Plex-Token=')[0]}`);
event.sender.send('downloadError', error);
})
})

View file

@ -267,10 +267,9 @@
var fields = def['fields'];
// Release def memory again
def = null;
//const revSelMediaType = et.getLibTypeName(this.selMediaType);
//const levelFields = wtconfig.get(`ET.CustomLevels.${revSelMediaType}.level.${this.selCustLevel}`);
const levelFields = wtconfig.get(`ET.CustomLevels.${this.selMediaType}.level.${this.selCustLevel}`);
let curLevel = 0;
let includeFields = '';
levelFields.forEach(function (item) {
// Get field level
var count = fields[item]['call'];
@ -278,9 +277,24 @@
{
curLevel = count;
}
// Get Include
var includeField = fields[item]['include'];
if ( typeof includeField !== 'undefined' && includeField )
{
if ( includeFields == '')
{
includeFields = includeField;
}
else if ( !includeFields.includes(includeField))
{
includeFields = includeFields + '&' + includeField;
}
}
});
log.info(`LevelCount for "${this.selCustLevel}" of the type "${this.selMediaType}" was calculated as:${curLevel}`);
wtconfig.set(`ET.CustomLevels.${this.selMediaType}.LevelCount.${this.selCustLevel}`, curLevel);
log.info(`includeFields for "${this.selCustLevel}" of the type "${this.selMediaType}" was calculated as:${includeFields}`);
wtconfig.set(`ET.CustomLevels.${this.selMediaType}.Include.${this.selCustLevel}`, includeFields);
},
changeType: function() {
// Triggers when lib type is changed

View file

@ -62,7 +62,7 @@
</b-form-row>
<b-form-row> <!-- Select Export Level -->
<b-col>
<div>
<div>
<b-form-group id="etLevelGroup" v-bind:label="$t('Modules.ET.optExpType.lblExportLevel')" label-size="lg" label-class="font-weight-bold pt-0" :disabled=this.etLevelGroupDisabled>
<b-tooltip target="etLevelGroup" triggers="hover">
{{ $t('Modules.ET.optExpType.ttExpLevel') }}
@ -72,6 +72,7 @@
v-model="selLevel"
id="selLevel"
:options="exportLevels"
@change="selLevelChanged"
name="selLevel">
</b-form-select>
</b-form-group>
@ -81,12 +82,13 @@
<div class="buttons"> <!-- Buttons -->
<b-button
type="is-primary"
@click="getMedia"
@click="showStartEnd"
icon-left="fas fa-file-download"
icon-pack="fas"
:disabled="btnDisable == true"
variant="success"
>{{ $t("Modules.ET.optExpType.lblBtnExportMedia") }}</b-button>
>
{{ $t("Modules.ET.optExpType.lblBtnExportMedia") }}</b-button>
</div>
<br>
<b-container fluid> <!-- Status -->
@ -106,6 +108,26 @@
</b-col>
</b-row>
</b-container>
<b-modal ref="startEnd" hide-footer v-bind:title=this.startEnd>
<div class="d-block">
{{ this.startEndBody }}
{{ this.startEndBody2 }}
<br>
{{ this.startEndBody3 }}
<br>
<br>
{{ this.startEndBody4 }}
<br>
<br>
<b-input-group id="itemStart" :prepend="$t('Modules.ET.optExpType.startStopStartingItem')" class="mt-3">
<b-form-input id="itemStartNo" name="itemStartNo" type="number" class="form-control" v-model="itemStartNo" :min=0 :max=this.sectionMaxItems.toString() :disabled=false @change.native="setItemStartNo()"></b-form-input>
</b-input-group>
<b-input-group id="itemEnd" :prepend="$t('Modules.ET.optExpType.startStopEndingItem')" class="mt-3">
<b-form-input id="itemEndNo" name="itemEndNo" type="number" class="form-control" v-model="itemEndNo" :disabled=false :min=this.itemStartNo.toString() :max=this.sectionMaxItems.toString() @change.native="setItemEndNo()"></b-form-input>
</b-input-group>
</div>
<b-button class="mt-3" variant="success" block @click="getMedia">{{ this.startEndBtn }}</b-button>
</b-modal>
</div>
</b-container>
</template>
@ -114,6 +136,7 @@
import { et } from "./scripts/et";
import i18n from '../../../i18n';
import { wtconfig } from '../General/wtutils';
import { etHelper } from "./scripts/ethelper";
const log = require("electron-log");
@ -136,7 +159,8 @@
},
{
"text": i18n.t('Modules.ET.optExpType.MainPhoto'),
"value": et.ETmediaType.Photo
"value": et.ETmediaType.Photo,
"disabled": true
},
{
"text": i18n.t('Modules.ET.optExpType.MainPlaylist'),
@ -159,14 +183,22 @@
pListGrpDisabled: true,
etLibraryGroupDisabled: false,
etLevelGroupDisabled: false,
statusMsg: 'Idle'
statusMsg: 'Idle',
startEnd: i18n.t("Modules.ET.optExpType.startStopTitle"),
startEndBody: i18n.t("Modules.ET.optExpType.startStopDesc"),
startEndBody2: i18n.t("Modules.ET.optExpType.startStopDesc2"),
startEndBody3: i18n.t("Modules.ET.optExpType.startStopDesc3"),
startEndBody4: i18n.t("Modules.ET.optExpType.startStopDesc4"),
startEndBtn: i18n.t("Modules.ET.optExpType.lblBtnExportMedia"),
itemStartNo: etHelper.Settings.currentItem,
itemEndNo: 0,
sectionMaxItems: 0
};
},
watch: {
// Watch for status update
ETStatus: function() {
this.statusMsg = this.$store.getters.getETStatus;
//this.genStatusMsg();
},
// Watch for when selected server address is updated
selectedServerAddress: async function(){
@ -191,7 +223,8 @@
},
created() {
log.info("ET Created");
et.updateStatusMsg( et.rawMsgType.Status, i18n.t("Modules.ET.Status.Idle"));
this.serverSelected();
etHelper.updateStatusMsg( etHelper.RawMsgType.Status, i18n.t("Modules.ET.Status.Idle"));
},
computed: {
ETStatus: function(){
@ -225,6 +258,47 @@
},
},
methods: {
setItemStartNo: async function(){
// Update settings with new start value
etHelper.Settings.startItem = this.itemStartNo;
},
setItemEndNo: async function(){
// Update settings with new start value
if (Number(this.sectionMaxItems) < Number(this.itemEndNo)){
this.itemEndNo = this.sectionMaxItems
}
etHelper.Settings.endItem = this.itemEndNo;
},
showStartEnd: async function(){
// Will ask for a starting item as well as an ending item, then export
// Start by getting the maximum and min items
etHelper.Settings.currentItem = 0;
etHelper.Settings.baseURL = this.$store.getters.getSelectedServerAddress;
etHelper.Settings.accessToken = this.$store.getters.getSelectedServerToken;
etHelper.Settings.totalItems = await etHelper.getSectionSize();
this.itemEndNo = etHelper.Settings.totalItems;
etHelper.Settings.endItem = this.itemEndNo;
this.sectionMaxItems = this.itemEndNo;
this.$refs['startEnd'].show();
},
hideStartEnd: async function(){
// Hide StartEnd modal
this.$refs['startEnd'].hide();
},
async serverSelected() {
etHelper.resetETHelper();
let serverCheck = this.$store.getters.getSelectedServer;
if (serverCheck == "none") {
log.debug("serverCheck is none");
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'
});
}
},
// Get levels for the selected media type
getLevels: async function(){
log.verbose(`Getting levels for: ${this.selExpTypeSec}`);
@ -331,13 +405,31 @@
}
log.verbose(`Sections to select among are: ${JSON.stringify(this.selLibraryOptions)}`);
},
selLibraryChanged: async function(){
getText: async function search(nameKey, myArray){
for (var i=0; i < myArray.length; i++) {
if (myArray[i].value == nameKey) {
return myArray[i].text;
}
}
},
selLevelChanged: async function(myarg){
log.verbose(`Level to export selected as: ${this.selLevel}`);
etHelper.resetETHelper();
etHelper.Settings.Level = this.selLevel;
etHelper.Settings.levelName = await this.getText(myarg, this.exportLevels);
},
selLibraryChanged: async function(myarg){
etHelper.resetETHelper();
log.verbose(`Library key to export selected as: ${this.selLibrary}`);
et.expSettings.selLibKey = this.selLibrary;
etHelper.Settings.selLibKey = this.selLibrary;
etHelper.Settings.LibName = await this.getText(myarg, this.selLibraryOptions);
},
selExpTypeSecChanged: async function(){
// Triggers when exp type is changed
log.verbose(`Secondary export type selected as: ${arguments[0]}`);
etHelper.Settings.fileMinor = this.optExpTypeSec.filter(it => it.value === arguments[0])[0]['text'];
etHelper.Settings.selType = arguments[0];
etHelper.Settings.libTypeSec = arguments[0];
// Set selMediaType to the type we want, and has to handle exceptions
switch(arguments[0]) {
// Set type for episodes to shows
@ -380,8 +472,9 @@
this.selLibrary = '';
this.selLibraryOptions = [];
this.exportLevels = [];
this.selExpTypeMain= arguments[0];
this.optExpTypeSec = et.selSecOption[arguments[0]]
this.selExpTypeMain = arguments[0];
this.optExpTypeSec = et.selSecOption[arguments[0]];
etHelper.Settings.fileMajor = this.optExpTypeMain.filter(it => it.value === arguments[0])[0]['text'];
log.verbose(`Export Main type selected: ${arguments[0]}`);
},
getPMSSections: async function(){
@ -437,6 +530,7 @@
},
async getMedia() {
log.info("getMedia Called");
this.hideStartEnd();
if (wtconfig.get('General.ExportPath', "") == "")
{
log.info('ET: No output dir defined')
@ -449,15 +543,28 @@
})
return
}
et.clearStatus();
et.updateStatusMsg( et.rawMsgType.Status, i18n.t("Modules.ET.Status.Running"));
if ( !wtconfig.get("ET.ExpCSV"))
{
if ( !wtconfig.get("ET.ExpXLSX"))
{
log.error('ET: No output format defined')
this.$bvToast.toast(this.$t("Modules.ET.ErrorNoOutputFormatMsg"), {
title: this.$t("Modules.ET.ErrorNoOutputFormatTitle"),
autoHideDelay: 3000,
solid: true,
variant: 'primary',
toaster: 'b-toaster-bottom-right'
})
return
}
}
await etHelper.clearStatus();
etHelper.updateStatusMsg( etHelper.RawMsgType.Status, i18n.t("Modules.ET.Status.Running"));
// Populate et. settings with the selected values
et.expSettings.baseURL = this.$store.getters.getSelectedServerAddress;
et.expSettings.accessToken = this.$store.getters.getSelectedServerToken;
et.expSettings.libType = this.selMediaType;
et.expSettings.libTypeSec = this.selExpTypeSec;
et.expSettings.exportLevel = this.selLevel;
await et.exportMedias();
etHelper.Settings.libType = this.selMediaType;
etHelper.Settings.Level = this.selLevel;
etHelper.Settings.libTypeSec = this.selExpTypeSec;
await etHelper.exportMedias();
},
async checkSrvSelected() {
log.debug("checkSrvSelected started");

View file

@ -27,6 +27,18 @@
</b-tooltip>
<b-form-input id="ArtDim" name="ArtDim" type="text" class="form-control" v-model="ArtDim" :disabled=false @change="setArt_Dimensions()"></b-form-input>
</b-input-group>
<b-input-group id="ChReturn" :prepend="$t('Modules.ET.Settings.ChReturn')" class="mt-3">
<b-tooltip target="ChReturn" triggers="hover">
{{ $t('Modules.ET.Settings.ChReturn_TT') }}
</b-tooltip>
<b-form-input id="ChReturn" name="ChReturn" type="text" class="form-control" v-model="ChReturn" :disabled=false @change="setChReturn()"></b-form-input>
</b-input-group>
<b-input-group id="ChNewLine" :prepend="$t('Modules.ET.Settings.ChNewLine')" class="mt-3">
<b-tooltip target="ChNewLine" triggers="hover">
{{ $t('Modules.ET.Settings.ChNewLine_TT') }}
</b-tooltip>
<b-form-input id="ChNewLine" name="ChNewLine" type="text" class="form-control" v-model="ChNewLine" :disabled=false @change="setChNewLine()"></b-form-input>
</b-input-group>
<b-form-group id="b-form-group">
<b-form-checkbox-group
stacked
@ -56,6 +68,7 @@
{
this.ColumnSep = wtconfig.get('ET.ColumnSep');
}
alert('For this version, export to XLSX is currently disabled');
},
data() {
return {
@ -67,15 +80,18 @@
ArtDim: wtconfig.get('ET.Art_Dimensions', '75*75'),
cbSelected: [],
cbOptions: [
{ text: i18n.t('Modules.ET.Settings.ExportToExcel'), value: 'ExpExcel' },
{ text: i18n.t('Modules.ET.Settings.ExportToCSV'), value: 'ExpCSV' },
{ text: i18n.t('Modules.ET.Settings.ExportToExcel'), value: 'ExpXLSX', disabled: true },
{ text: i18n.t('Modules.ET.Settings.OrgTitleNull'), value: 'OrgTitleNull' },
{ text: i18n.t('Modules.ET.Settings.SortTitleNull'), value: 'SortTitleNull' }
]
],
ChReturn: wtconfig.get('ET.ChReturn', '<RETURN>'),
ChNewLine: wtconfig.get('ET.ChNewLine', '<NEWLINE>')
};
},
methods: {
getcbDefaults(){
const cbItems = ["ExpExcel", "OrgTitleNull", "SortTitleNull"];
const cbItems = ["ExpCSV","ExpXLSX", "OrgTitleNull", "SortTitleNull"];
for(let i = 0; i < cbItems.length; i++){
if (wtconfig.get("ET." + cbItems[i], false)){
this.cbSelected.push(cbItems[i]);
@ -84,7 +100,7 @@
},
filterTable(){
this.$nextTick(()=>{console.log(this.cbSelected);})
for( var cbItem of ["ExpExcel","OrgTitleNull", "SortTitleNull", "AutoXLSCol", "AutoXLSRow"]){
for( var cbItem of ["ExpCSV","ExpXLSX","OrgTitleNull", "SortTitleNull", "AutoXLSCol", "AutoXLSRow"]){
wtconfig.set("ET." + cbItem, (this.cbSelected.includes(cbItem)))
}
},
@ -115,6 +131,12 @@
setArraySep: function(){
wtconfig.set('ET.ArraySep', this.ArraySep)
},
setChReturn: function(){
wtconfig.set('ET.ChReturn', this.ChReturn)
},
setChNewLine: function(){
wtconfig.set('ET.ChNewLine', this.ChNewLine)
},
setTextQualifierCSV: function(){
wtconfig.set('ET.TextQualifierCSV', this.TextQualifierCSV)
},

View file

@ -164,8 +164,7 @@
"Video Stream Title",
"Video Stream Width",
"View Count",
"Writers",
"Year"
"Writers"
]
}
}

View file

@ -70,7 +70,8 @@
{
"key": "audienceRating",
"call": 1,
"type": "string"
"type": "string",
"postProcess": true
},
"Audio Stream Album Gain":
{
@ -262,7 +263,8 @@
"call": 2,
"type": "array",
"subtype": "string",
"subkey": "$.requiredBandwidths"
"subkey": "$.requiredBandwidths",
"include": "includeBandwidths=1"
},
"Audio Stream Sampling Rate":
{
@ -318,13 +320,15 @@
{
"key": "$..Chapter[*]",
"call": 2,
"type": "array-count"
"type": "array-count",
"include": "includeChapters=1"
},
"Chapter Source":
{
"key": "$.chapterSource",
"call": 2,
"type": "string"
"type": "string",
"include": "includeChapters=1"
},
"Chapter Title":
{
@ -332,7 +336,8 @@
"call": 2,
"type": "array",
"subtype": "string",
"subkey": "$.tag"
"subkey": "$.tag",
"include": "includeChapters=1"
},
"Collections":
{
@ -434,61 +439,71 @@
{
"key": "$.Extras.size",
"call": 2,
"type": "int"
"type": "int",
"include": "includeExtras=1"
},
"Extras-behindthescenes":
{
"key": "$..Extras.Metadata[?(@.subtype=='behindTheScenes')].ratingKey",
"call": 2,
"type": "array-count"
"type": "array-count",
"include": "includeExtras=1"
},
"Extras-deleted":
{
"key": "$..Extras.Metadata[?(@.subtype=='deleted')].ratingKey",
"call": 2,
"type": "array-count"
"type": "array-count",
"include": "includeExtras=1"
},
"Extras-featurette":
{
"key": "$..Extras.Metadata[?(@.subtype=='featurette')].ratingKey",
"call": 2,
"type": "array-count"
"type": "array-count",
"include": "includeExtras=1"
},
"Extras-interview":
{
"key": "$..Extras.Metadata[?(@.subtype=='interview')].ratingKey",
"call": 2,
"type": "array-count"
"type": "array-count",
"include": "includeExtras=1"
},
"Extras-music video":
{
"key": "$..Extras.Metadata[?(@.subtype=='musicVideo')].ratingKey",
"call": 2,
"type": "array-count"
"type": "array-count",
"include": "includeExtras=1"
},
"Extras-scene":
{
"key": "$..Extras.Metadata[?(@.subtype=='scene')].ratingKey",
"call": 2,
"type": "array-count"
"type": "array-count",
"include": "includeExtras=1"
},
"Extras-sceneOrSample":
{
"key": "$..Extras.Metadata[?(@.subtype=='sceneOrSample')].ratingKey",
"call": 2,
"type": "array-count"
"type": "array-count",
"include": "includeExtras=1"
},
"Extras-short":
{
"key": "$..Extras.Metadata[?(@.subtype=='short')].ratingKey",
"call": 2,
"type": "array-count"
"type": "array-count",
"include": "includeExtras=1"
},
"Extras-trailer":
{
"key": "$..Extras.Metadata[?(@.subtype=='trailer')].ratingKey",
"call": 2,
"type": "array-count"
"type": "array-count",
"include": "includeExtras=1"
},
"Filters":
{
@ -818,7 +833,8 @@
"call": 2,
"type": "array",
"subtype": "string",
"subkey": "$.accessible"
"subkey": "$.accessible",
"include": "checkFiles=1"
},
"Part Container":
{
@ -851,7 +867,8 @@
"call": 2,
"type": "array",
"subtype": "string",
"subkey": "$.exists"
"subkey": "$.exists",
"include": "checkFiles=1"
},
"Part File":
{
@ -925,7 +942,8 @@
"call": 2,
"type": "array",
"subtype": "string",
"subkey": "$.requiredBandwidths"
"subkey": "$.requiredBandwidths",
"include": "includeBandwidths=1"
},
"Part Size":
{
@ -998,7 +1016,8 @@
{
"key": "$.rating",
"call": 1,
"type": "string"
"type": "string",
"postProcess": true
},
"Refreshing":
{
@ -1157,7 +1176,8 @@
"call": 2,
"type": "array",
"subtype": "string",
"subkey": "requiredBandwidths"
"subkey": "requiredBandwidths",
"include": "includeBandwidths=1"
},
"Subtitle Stream Selected":
{
@ -1231,7 +1251,7 @@
"TMDB ID":
{
"key": "$.Guid[*]",
"call": 1,
"call": 2,
"type": "array",
"subtype": "string",
"subkey": "$.id",
@ -1240,7 +1260,7 @@
"TMDB Link":
{
"key": "$.Guid[*]",
"call": 1,
"call": 2,
"type": "array",
"subtype": "string",
"subkey": "$.id",
@ -1464,7 +1484,8 @@
"call": 2,
"type": "array",
"subtype": "string",
"subkey": "requiredBandwidths"
"subkey": "requiredBandwidths",
"include": "includeBandwidths=1"
},
"Video Stream Scan Type":
{

View file

@ -8,7 +8,8 @@
"LevelCount": {
"Level 1": 1,
"Level 2": 1,
"All": 2
"All": 2,
"all": 2
}
},
"8": {
@ -20,7 +21,8 @@
"LevelCount": {
"Level 1": 1,
"Level 2": 1,
"All": 2
"All": 2,
"all": 2
}
},
"4": {
@ -32,23 +34,35 @@
"LevelCount": {
"Level 1": 1,
"Level 2": 1,
"All": 2
"All": 2,
"all": 2
},
"Include": {
"Level 1": "",
"Level 2": "",
"all": "checkFiles=1&includeExtras=1&includeBandwidths=1&includeChapters=1"
}
},
"1" : {
"levels": {
"Level 1": "level1",
"Level 2": "level2",
"All": "all",
"dev tommy": "devTommy"
"All": "all"
},
"LevelCount": {
"Level 1": 1,
"Level 2": 1,
"All": 2,
"devTommy": 2
"all": 2
},
"Include": {
"Level 11": "",
"Level 21": "",
"all": "checkFiles=1&includeExtras=1&includeBandwidths=1&includeChapters=1",
"Missing1": "includeAllConcerts=1&includeChildren=1&includeConcerts=1&includeFields=1&includeGeolocation=1&includeLoudnessRamps=1&includeMarkers=1&includeOnDeck=1&includePopularLeaves=1&includePreferences=1&includeRelated=1&includeRelatedCount=1&includeReviews=1&includeStations=1",
"Everything1": "checkFiles=1&includeAllConcerts=1&includeBandwidths=1&includeChapters=1&includeChildren=1&includeConcerts=1&includeExtras=1&includeFields=1&includeGeolocation=1&includeLoudnessRamps=1&includeMarkers=1&includeOnDeck=1&includePopularLeaves=1&includePreferences=1&includeRelated=1&includeRelatedCount=1&includeReviews=1&includeStations=1"
}
},
"2": {
"levels": {
@ -59,7 +73,14 @@
"LevelCount": {
"Level 1": 1,
"Level 2": 1,
"All": 2
"All": 2,
"all": 2
},
"Include": {
"Level 1": "",
"Level 2": "",
"1all": "checkFiles=1&includeExtras=1&includeBandwidths=1&includeChapters=1,includeAllConcerts=1&includeChildren=1&includeConcerts=1&includeFields=1&includeGeolocation=1&includeLoudnessRamps=1&includeMarkers=1&includeOnDeck=1&includePopularLeaves=1&includePreferences=1&includeRelated=1&includeRelatedCount=1&includeReviews=1&includeStations=1",
"all": ""
}
},
"10": {
@ -71,7 +92,8 @@
"LevelCount": {
"Level 1": 1,
"Level 2": 1,
"All": 2
"All": 2,
"all": 2
}
},
"13": {
@ -83,7 +105,8 @@
"LevelCount": {
"Level 1": 1,
"Level 2": 1,
"All": 2
"All": 2,
"all": 2
}
},
"2001": {
@ -95,7 +118,8 @@
"LevelCount": {
"Level 1": 1,
"Level 2": 1,
"All": 2
"All": 2,
"all": 2
}
},
"2003": {
@ -107,7 +131,8 @@
"LevelCount": {
"Level 1": 1,
"Level 2": 1,
"All": 2
"All": 2,
"all": 2
}
},
"2002": {
@ -119,7 +144,8 @@
"LevelCount": {
"Level 1": 1,
"Level 2": 1,
"All": 2
"All": 2,
"all": 2
}
},
"1002": {
@ -127,7 +153,8 @@
"All": "all"
},
"LevelCount": {
"All": 1
"All": 1,
"all": 1
}
},
"3001": {
@ -135,7 +162,8 @@
"All": "all"
},
"LevelCount": {
"All": 1
"All": 1,
"all": 1
}
}
}

View file

@ -36,6 +36,7 @@
"Genre",
"IMDB ID",
"IMDB Link",
"Item Counts",
"Key",
"Labels",
"Location",

View file

@ -0,0 +1,35 @@
// This file handles CSV exports
//import {wtconfig, wtutils} from '../../General/wtutils';
import {wtconfig} from '../../General/wtutils';
const log = require('electron-log');
console.log = log.log;
const csv = new class CSV {
constructor() {
}
async addHeaderToTmp({ stream: stream, item: item})
{
// Walk each item, and add Qualifier
let headerArray = [];
let x = 0;
for (x=0; x<item.length; x++) {
headerArray.push(wtconfig.get('ET.TextQualifierCSV', "\"") + item[x] + wtconfig.get('ET.TextQualifierCSV', "\""));
}
const strHeader = headerArray.join(wtconfig.get('ET.ColumnSep', ','));
// Add the header
await stream.write( strHeader + "\n");
log.info(`Added CSV Header as: ${strHeader}`);
}
async addRowToTmp({ stream: stream, item: item})
{
await stream.write( item + "\n");
}
}
export { csv };

View file

@ -4,22 +4,25 @@ var defFields = JSON.parse(JSON.stringify(require('./../defs/def-Fields.json')))
const log = require('electron-log');
console.log = log.log;
const defpostURI = '?checkFiles=1&includeRelated=0&includeExtras=1&includeBandwidths=1&includeChapters=1'
//const defpostURI = '?checkFiles=1&includeRelated=0&includeExtras=1&includeBandwidths=1&includeChapters=1'
import {wtconfig, wtutils} from '../../General/wtutils';
import i18n from '../../../../i18n';
//import {etHelper} from './ethelper';
//import i18n from '../../../../i18n';
import i18n from '../../../../i18n'
import {ipcRenderer} from 'electron';
//const fs = require('fs');
import filesize from 'filesize';
var path = require("path");
const fetch = require('node-fetch');
const {JSONPath} = require('jsonpath-plus');
import axios from 'axios'
import store from '../../../../store';
//import store from '../../../../store';
const et = new class ET {
constructor() {
@ -73,6 +76,10 @@ const et = new class ET {
2003: 'Photo',
3001: 'Playlists'
},
this.selSecOption2 = {
1: ['Modules.ET.optExpType.SecMovies'],
2: ['Modules.ET.optExpType.SecTVEpisodes']
}
this.selSecOption = {
1: [
{
@ -150,18 +157,7 @@ const et = new class ET {
this.StartTime = null,
this.EndTime = null,
this.OutFile = null,
this.rawMsgType = {
'Status': 1,
'Info': 2,
'Chuncks': 3,
'Items': 4,
'OutFile': 5,
'StartTime': 6,
'EndTime': 7,
'TimeElapsed': 8,
'RunningTime': 9
},
this.revRawMsgType = {
this.revRawMsgTypeOLDDELGED = {
1: 'Status',
2: 'Info',
3: 'Chuncks',
@ -169,10 +165,10 @@ const et = new class ET {
5: 'OutFile',
6: 'StartTime',
7: 'EndTime',
8: 'TimeElapsed',
8: '1TimeElapsed',
9: 'RunningTime'
},
this.msgType = {
this.msgTypeOLDDELGED = {
1: i18n.t("Modules.ET.Status.Names.Status"),
2: i18n.t("Modules.ET.Status.Names.Info"),
3: i18n.t("Modules.ET.Status.Names.Chuncks"),
@ -185,115 +181,13 @@ const et = new class ET {
}
}
async getStartEndTime(StartEnd){
let now;
if (StartEnd == 'start')
{
now = et.StartTime;
}
else
{
now = et.EndTime;
}
return now.getHours() + ':' + now.getMinutes() + ':' + now.getSeconds();
}
async clearStatus()
{
this.statusmsg = {};
store.commit("UPDATE_SELECTEDETStatus", '');
}
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_SELECTEDETStatus", newMsg);
}
async getTimeElapsed(){
let elapsedSeconds = Math.floor((et.EndTime.getTime() - et.StartTime.getTime()) / 1000);
let elapsedStr = elapsedSeconds.toString().replaceAll('.', '');
const hours = Math.floor(parseFloat(elapsedStr) / 3600);
elapsedSeconds = parseFloat(elapsedStr) - hours * 3600;
const minutes = Math.floor(elapsedSeconds / 60);
const seconds = elapsedSeconds - minutes * 60;
return hours + ':' + minutes + ':' + seconds
}
async getRunningTimeElapsed(){
const now = new Date();
let elapsedSeconds = Math.floor((now.getTime() - et.StartTime.getTime()) / 1000);
let elapsedStr = elapsedSeconds.toString().replaceAll('.', '');
const hours = Math.floor(parseFloat(elapsedStr) / 3600);
elapsedSeconds = parseFloat(elapsedStr) - hours * 3600;
const minutes = Math.floor(elapsedSeconds / 60);
const seconds = elapsedSeconds - minutes * 60;
return hours + ':' + minutes + ':' + seconds
}
async getNowTime(StartEnd){
let now = new Date();
if (StartEnd == 'start')
{
et.StartTime = now;
}
else
{
et.EndTime = now;
}
let hours = now.getHours();
let minutes = now.getMinutes();
let seconds = now.getSeconds();
return hours + ':' + minutes + ':' + seconds;
}
async exportMedias() {
et.updateStatusMsg( et.rawMsgType.StartTime, await this.getNowTime('start'));
this.expSettings.libName = et.getLibDisplayName(this.expSettings.selLibKey, store.getters.getPmsSections);
if ([ et.ETmediaType.Libraries, et.ETmediaType.Playlists].indexOf(this.expSettings.libType) > -1)
{
this.expSettings.levelName = 'All'
}
else
{
this.expSettings.levelName = et.getLevelDisplayName(this.expSettings.exportLevel, this.expSettings.libType);
}
await excel2.createOutFile( {
libName: this.expSettings.libName,
level: this.expSettings.levelName,
libType: this.expSettings.libType,
baseURL: this.expSettings.baseURL,
accessToken: this.expSettings.accessToken,
exType: this.expSettings.libType,
pListType: this.expSettings.libTypeSec,
libTypeSec: this.expSettings.libTypeSec
});
// Update status window
et.clearStatus();
et.updateStatusMsg( et.rawMsgType.Status, i18n.t("Modules.ET.Status.Finished"));
et.updateStatusMsg( et.rawMsgType.StartTime, await this.getStartEndTime('start'));
this.getNowTime('end');
et.updateStatusMsg( et.rawMsgType.EndTime, await this.getStartEndTime('end'));
et.updateStatusMsg( et.rawMsgType.TimeElapsed, await this.getTimeElapsed());
et.updateStatusMsg( et.rawMsgType.OutFile, et.OutFile.split('.').slice(0, -1).join('.'));
}
async getSectionData()
async GEDDELETE_getSectionData()
{
const sectionData = []
// Find LibType steps
const step = wtconfig.get("PMS.ContainerSize." + this.expSettings.libType, 20)
log.debug(`Got Step size as: ${step}`)
log.debug(`!!!! et (getSectionData): Got Step size as: ${step}`)
let element
// Now read the fields and level defs
// Current item
@ -302,33 +196,29 @@ const et = new class ET {
let chuncks, postURI
let size
do {
if (this.expSettings.libType == et.ETmediaType.Photo)
{
element = '/library/sections/' + this.expSettings.selLibKey + '/all';
postURI = `?addedAt>>=-2208992400&X-Plex-Container-Start=${idx}&X-Plex-Container-Size=${step}&type=${this.expSettings.libTypeSec}&${this.uriParams}`;
switch (this.expSettings.libType) {
case et.ETmediaType.Photo:
element = '/library/sections/' + this.expSettings.selLibKey + '/all';
postURI = `?addedAt>>=-2208992400&X-Plex-Container-Start=${idx}&X-Plex-Container-Size=${step}&type=${this.expSettings.libTypeSec}&${this.uriParams}`;
break;
case et.ETmediaType.Playlist:
element = '/playlists/' + this.expSettings.selLibKey;
postURI = `/items?X-Plex-Container-Start=${idx}&X-Plex-Container-Size=${step}`;
break;
case et.ETmediaType.Libraries:
element = '/library/sections/all';
postURI = `?X-Plex-Container-Start=${idx}&X-Plex-Container-Size=${step}`;
break;
case et.ETmediaType.Playlists:
element = '/playlists/all';
postURI = `?X-Plex-Container-Start=${idx}&X-Plex-Container-Size=${step}`;
break;
default:
element = '/library/sections/' + this.expSettings.selLibKey + '/all';
postURI = `?X-Plex-Container-Start=${idx}&X-Plex-Container-Size=${step}&type=${this.expSettings.libTypeSec}&${this.uriParams}`;
}
else if (this.expSettings.libType == et.ETmediaType.Playlist)
{
element = '/playlists/' + this.expSettings.selLibKey;
postURI = `/items?X-Plex-Container-Start=${idx}&X-Plex-Container-Size=${step}`;
}
else if (this.expSettings.libType == et.ETmediaType.Libraries)
{
element = '/library/sections/all';
postURI = `?X-Plex-Container-Start=${idx}&X-Plex-Container-Size=${step}`;
}
else if (this.expSettings.libType == et.ETmediaType.Playlists)
{
element = '/playlists/all';
postURI = `?X-Plex-Container-Start=${idx}&X-Plex-Container-Size=${step}`;
}
else
{
element = '/library/sections/' + this.expSettings.selLibKey + '/all';
postURI = `?X-Plex-Container-Start=${idx}&X-Plex-Container-Size=${step}&type=${this.expSettings.libTypeSec}&${this.uriParams}`;
}
log.info(`Calling getSectionData url ${this.expSettings.baseURL + element + postURI}`);
chuncks = await et.getItemData({baseURL: this.expSettings.baseURL, accessToken: this.expSettings.accessToken, element: element, postURI: postURI});
size = JSONPath({path: '$.MediaContainer.size', json: chuncks});
const totalSize = JSONPath({path: '$.MediaContainer.totalSize', json: chuncks});
@ -339,22 +229,11 @@ const et = new class ET {
log.debug(`Pushed chunk as ${JSON.stringify(chuncks)}`)
idx = idx + step;
} while (size > 1);
log.silly(`SectionData to return is:`);
log.silly(JSON.stringify(sectionData));
log.debug(`SectionData to return is:`);
log.debug(JSON.stringify(sectionData));
return sectionData;
}
async getItemData({baseURL, accessToken, element, postURI=defpostURI})
{
const url = baseURL + element + postURI;
this.PMSHeader["X-Plex-Token"] = accessToken;
log.verbose(`Calling url in getItemData: ${url}`)
let response = await fetch(url, { method: 'GET', headers: this.PMSHeader});
let resp = await response.json();
log.silly(`Response in getItemData: ${JSON.stringify(resp)}`)
return resp
}
getRealLevelName(level, libType) {
// First get the real name of the level, and not just the display name
let levelName
@ -545,16 +424,6 @@ const et = new class ET {
return out;
}
async getLevelCall (libType, level) {
if (libType == et.ETmediaType.Playlist)
{
libType = et.expSettings.libTypeSec;
}
const count = await defLevels[libType]['LevelCount'][level]
log.debug('Count needed is: ' + count)
return count
}
getLevels(libType) {
// Returns an json of levels for a selected type og medias, like 'movie'
const levels = defLevels[libType]['levels'];
@ -815,25 +684,13 @@ const excel2 = new class Excel {
return sheet
}
GetHeader(Level, libType) {
const columns = []
log.verbose(`GetHeader level: ${Level} - libType: ${libType}`)
// Get level fields
const fields = et.getLevelFields(Level, libType)
for (var i=0; i<fields.length; i++) {
log.verbose(`Column: ${fields[i]}`)
columns.push(fields[i])
}
return columns
}
async AddHeader(Sheet, Level, libType) {
const columns = []
log.verbose(`AddHeader level: ${Level} - libType: ${libType}`)
// Get level fields
const fields = et.getLevelFields(Level, libType)
for (var i=0; i<fields.length; i++) {
log.verbose('Column: ' + fields[i] + ' - ' + fields[i])
log.verbose('Column12: ' + fields[i] + ' - ' + fields[i])
let column = { header: fields[i], key: fields[i], width: 5 }
columns.push(column)
}
@ -854,30 +711,6 @@ const excel2 = new class Excel {
return true;
}
async getFileName({ Library, Level, Type, Module, exType }){
const dateFormat = require('dateformat');
const OutDir = wtconfig.get('General.ExportPath');
const timeStamp=dateFormat(new Date(), "yyyy.mm.dd_h.MM.ss");
const path = require('path');
let outFile = store.getters.getSelectedServer.name + '_';
outFile += Library + '_';
outFile += et.RevETmediaType[exType.toString()] + '_';
outFile += Level + '_';
outFile += timeStamp + '.' + Type;
et.OutFile = outFile;
const targetDir = path.join(
OutDir, wtutils.AppName, Module);
const outFileWithPath = path.join(
targetDir, outFile);
// Make sure target dir exists
const fs = require('fs')
if (!fs.existsSync(targetDir)) {
fs.mkdirSync(targetDir);
}
log.info(`OutFile is ${outFileWithPath}`);
return outFileWithPath;
}
async SaveWorkbook({ Workbook, Library, Level, Type, exType } ) {
const fs = require('fs');
const name = await this.getFileName( { Library: Library, Level: Level, Type: Type, Module: i18n.t('Modules.ET.Name'), exType: exType });
@ -888,277 +721,6 @@ const excel2 = new class Excel {
return true;
}
async postProcess( {name, val, title=""} ){
const valArray = val.split(wtconfig.get('ET.ArraySep', ' * '));
let retArray = [];
let x, retVal, start, strStart, end, result;
try {
switch ( String(name) ){
case "Part File":
for (x=0; x<valArray.length; x++) {
retArray.push(path.basename(valArray[x]))
}
retVal = retArray.join(wtconfig.get('ET.ArraySep', ' * '))
break;
case "Part File Path":
for (x=0; x<valArray.length; x++) {
retArray.push(path.dirname(valArray[x]));
}
retVal = retArray.join(wtconfig.get('ET.ArraySep', ' * '));
break;
case "Part Size":
for (x=0; x<valArray.length; x++) {
let theSize = valArray[x].replaceAll('"', '').replaceAll(wtconfig.get('ET.TextQualifierCSV'),'');
if (theSize.startsWith('"')){
theSize = theSize.slice(1,-1);
}
try{
retArray.push(filesize(theSize));
}
catch (error)
{
log.error(`Error getting Part Size was ${error} for ${theSize}`);
}
}
retVal = retArray.join(wtconfig.get('ET.ArraySep', ' * '))
break;
case "Original Title":
if (wtconfig.get('ET.OrgTitleNull'))
{
let compNA = (wtconfig.get('ET.TextQualifierCSV') + wtconfig.get('ET.NotAvail') + wtconfig.get('ET.TextQualifierCSV')).trim();
// Override with title if not found
if (val == compNA)
{
retVal = title;
}
else { retVal = val; }
}
else
{
retVal = val;
}
break;
case "Sort title":
if (wtconfig.get('ET.SortTitleNull'))
{
// Override with title if not found
let compNA = (wtconfig.get('ET.TextQualifierCSV') + wtconfig.get('ET.NotAvail') + wtconfig.get('ET.TextQualifierCSV')).trim();
if (val == compNA)
{
retVal = title;
}
else {
retVal = val;
}
}
else
{
let compNA = (wtconfig.get('ET.TextQualifierCSV') + 'undefined' + wtconfig.get('ET.TextQualifierCSV')).trim();
if (val == compNA)
{
retVal = wtconfig.get('ET.NotAvail');
}
else {
retVal = val;
}
}
break;
case "IMDB ID":
if (val == wtconfig.get('ET.NotAvail'))
{
retVal = val;
break;
}
start = val.indexOf("imdb://");
if (start == -1)
{
retVal = wtconfig.get('ET.NotAvail');
break;
}
strStart = val.substring(start);
end = strStart.indexOf(wtconfig.get('ET.ArraySep'));
result = ''
if (end == -1)
{ result = strStart.substring(7) }
else
{ result = strStart.substring(7, end) }
retVal = result;
break;
case "IMDB ID (Legacy)":
if (val == wtconfig.get('ET.NotAvail'))
{
retVal = val;
break;
}
// Cut off start of string
start = val.indexOf("tt");
if (start == -1)
{
retVal = wtconfig.get('ET.NotAvail');
break;
}
strStart = val.substring(start);
result = strStart.split('?')[0]
retVal = result;
break;
case "IMDB Language (Legacy)":
if (val == wtconfig.get('ET.NotAvail'))
{
retVal = val;
break;
}
if (val.indexOf("imdb://") == -1)
{
retVal = wtconfig.get('ET.NotAvail');
break;
}
retVal = val.split('=')[1];
if (retVal == 'undefined')
{
retVal = wtconfig.get('ET.NotAvail');
}
break;
case "IMDB Link":
if (val == wtconfig.get('ET.NotAvail'))
{
retVal = val;
break;
}
start = val.indexOf("imdb://");
if (start == -1)
{
retVal = wtconfig.get('ET.NotAvail');
break;
}
strStart = val.substring(start);
end = strStart.indexOf(wtconfig.get('ET.ArraySep'));
result = ''
if (end == -1)
{ result = strStart.substring(7) }
else
{ result = strStart.substring(7, end) }
result = 'https://www.imdb.com/title/' + result;
retVal = result;
break;
case "IMDB Link (Legacy)":
if (val == wtconfig.get('ET.NotAvail'))
{
retVal = val;
break;
}
if (val.indexOf("imdb://") == -1)
{
retVal = wtconfig.get('ET.NotAvail');
}
else
{
retVal = 'https://imdb.com/' + val.split('//')[1];
retVal = retVal.split('?')[0];
}
break;
case "TVDB ID":
if (val == wtconfig.get('ET.NotAvail'))
{
retVal = val;
break;
}
start = val.indexOf("tvdb://");
if (start == -1)
{
retVal = wtconfig.get('ET.NotAvail');
break;
}
strStart = val.substring(start);
end = strStart.indexOf(wtconfig.get('ET.ArraySep'));
result = ''
if (end == -1)
{ result = strStart.substring(7) }
else
{ result = strStart.substring(7, end) }
retVal = result;
break;
case "TVDB ID (Legacy)":
if (val == wtconfig.get('ET.NotAvail'))
{
retVal = val;
break;
}
// Cut off start of string
start = val.indexOf("thetvdb://");
if (start == -1)
{
retVal = wtconfig.get('ET.NotAvail');
break;
}
strStart = val.substring(start);
result = strStart.split('?')[0]
retVal = result;
break;
case "TVDB Language (Legacy)":
if (val == wtconfig.get('ET.NotAvail'))
{
retVal = val;
break;
}
if (val.indexOf("tvdb://") == -1)
{
retVal = wtconfig.get('ET.NotAvail');
break;
}
retVal = val.split('=')[1];
if (retVal == 'undefined')
{
retVal = wtconfig.get('ET.NotAvail');
}
break;
case "TMDB ID":
if (val == wtconfig.get('ET.NotAvail'))
{
retVal = val;
break;
}
start = val.indexOf("tmdb://");
if (start == -1)
{
retVal = wtconfig.get('ET.NotAvail');
break;
}
strStart = val.substring(start);
end = strStart.indexOf(wtconfig.get('ET.ArraySep'));
result = ''
if (end == -1)
{ result = strStart.substring(7) }
else
{ result = strStart.substring(7, end) }
retVal = result;
break;
case "TMDB Link":
if (val == wtconfig.get('ET.NotAvail'))
{
retVal = val;
break;
}
start = val.indexOf("tmdb://");
strStart = val.substring(start);
end = strStart.indexOf(wtconfig.get('ET.ArraySep'));
result = ''
if (end == -1)
{ result = strStart.substring(7) }
else
{ result = strStart.substring(7, end) }
result = 'https://www.themoviedb.org/movie/' + result;
retVal = result;
break;
default:
log.error(`postProcess no hit for: ${name}`)
break;
}
} catch (error) {
retVal = 'ERROR'
}
return await retVal;
}
isEmpty( { val })
{
if ([null, 'undefined', ''].indexOf(val) > -1)
@ -1171,7 +733,7 @@ const excel2 = new class Excel {
}
}
async forceDownload(url, target) {
async OLDDELforceDownload(url, target) {
const _this = this;
return new Promise((resolve, reject) => {
try
@ -1208,7 +770,7 @@ const excel2 = new class Excel {
})
}
async exportPics( { type: extype, data, baseURL, accessToken} ) {
async OLD_DELexportPics( { type: extype, data, baseURL, accessToken} ) {
let ExpDir, picUrl, resolutions;
log.verbose(`Going to export ${extype}`);
try
@ -1267,144 +829,6 @@ const excel2 = new class Excel {
}
}
async addRowToTmp( { libType, level, data, stream, fields }) {
et.updateStatusMsg( et.rawMsgType.RunningTime, await et.getRunningTimeElapsed());
log.debug(`Start addRowToTmp. libType: ${libType} - level: ${level}`)
log.silly(`Data is: ${JSON.stringify(data)}`)
let date, year, month, day, hours, minutes, seconds
let lookup, val, array, i, valArray, valArrayVal, subType, subKey
let str = ''
let result = ''
let textSep = wtconfig.get('ET.TextQualifierCSV', '"');
if ( textSep === ' ')
{
textSep = '';
}
for (var x=0; x<fields.length; x++) {
var name = Object.keys(fields[x]);
lookup = JSONPath({path: '$..key', json: fields[x]})[0];
switch(String(JSONPath({path: '$..type', json: fields[x]}))) {
case "string":
val = String(JSONPath({path: String(lookup), json: data})[0]);
// Make N/A if not found
val = this.isEmpty( { val: val });
// Remove CR, LineFeed ' and " from the
// string if present, and replace with a space
val = val.replace(/'|"|\r|\n/g, ' ');
val = textSep + val + textSep;
break;
case "array":
array = JSONPath({path: lookup, json: data});
if (array === undefined || array.length == 0) {
val = wtconfig.get('ET.NotAvail', 'N/A');
}
else
{
valArray = []
for (i=0; i<array.length; i++) {
subType = JSONPath({path: '$..subtype', json: fields[x]});
subKey = JSONPath({path: '$..subkey', json: fields[x]});
switch(String(subType)) {
case "string":
valArrayVal = String(JSONPath({path: String(subKey), json: array[i]})[0]);
// Make N/A if not found
valArrayVal = this.isEmpty( { val: valArrayVal });
// Remove CR, LineFeed ' and " from the string if present
valArrayVal = valArrayVal.replace(/'|"|\r|\n/g, ' ');
break;
case "time":
valArrayVal = JSONPath({path: String(subKey), json: array[i]});
// Make N/A if not found
if (valArrayVal == null || valArrayVal == "")
{
valArrayVal = wtconfig.get('ET.NotAvail', 'N/A')
}
else
{
const total = valArrayVal.length
for (let i=0; i<total; i++) {
seconds = '0' + (Math.round(valArrayVal[i]/1000)%60).toString();
minutes = '0' + (Math.round((valArrayVal[i]/(1000 * 60))) % 60).toString();
hours = (Math.trunc(valArrayVal[i] / (1000 * 60 * 60)) % 24).toString();
// Will display time in 10:30:23 format
valArrayVal = hours + ':' + minutes.substr(-2) + ':' + seconds.substr(-2);
}
}
break;
default:
log.error('NO ARRAY HIT (addRowToSheet-array)')
}
valArray.push(valArrayVal)
}
val = valArray.join(wtconfig.get('ET.ArraySep', ' * '))
if ( String(subType) == 'string')
{
val = textSep + val + textSep;
}
}
break;
case "array-count":
val = JSONPath({path: String(lookup), json: data}).length;
break;
case "int":
val = JSONPath({path: String(lookup), json: data})[0];
break;
case "time":
val = JSONPath({path: String(lookup), json: data});
if ( typeof val !== 'undefined' && val && val != '')
{
seconds = '0' + (Math.round(val/1000)%60).toString();
minutes = '0' + (Math.round((val/(1000 * 60))) % 60).toString();
hours = (Math.trunc(val / (1000 * 60 * 60)) % 24).toString();
// Will display time in 10:30:23 format
val = hours + ':' + minutes.substr(-2) + ':' + seconds.substr(-2);
}
else
{
val = wtconfig.get('ET.NotAvail', 'N/A')
}
break;
case "datetime":
val = JSONPath({path: String(lookup), json: data});
if ( typeof val !== 'undefined' && val && val != '')
{
// Create a new JavaScript Date object based on the timestamp
// multiplied by 1000 so that the argument is in milliseconds, not seconds.
date = new Date(val * 1000);
year = date.getFullYear().toString();
month = ('0' + date.getMonth().toString()).substr(-2);
day = ('0' + date.getDate().toString()).substr(-2);
hours = date.getHours();
minutes = "0" + date.getMinutes();
seconds = "0" + date.getSeconds();
// Will display time in 10:30:23 format
val = year+'-'+month+'-'+day+' '+hours + ':' + minutes.substr(-2) + ':' + seconds.substr(-2);
}
else
{
val = wtconfig.get('ET.NotAvail', 'N/A')
}
break;
}
let doPostProc = JSONPath({path: '$..postProcess', json: fields[x]})
if ( doPostProc == 'true')
{
if (!["Original Title","Sort title"].includes(name)){
const title = JSONPath({path: String('$.title'), json: data})[0];
val = await this.postProcess( {name: name, val: val, title: title} );
}
else {
val = await this.postProcess( {name: name, val: val} );
}
}
str += wtconfig.get('ET.ColumnSep') + val;
}
// Remove first character
result = str.substr(1);
//await stream.write( result + "\n");
stream.write( result + "\n");
}
async sleep(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
@ -1478,103 +902,8 @@ const excel2 = new class Excel {
});
}
async createOutFile( {libName, level, libType, baseURL, accessToken, exType, pListType} )
{
const header = excel2.GetHeader(level, libType, pListType);
log.debug(`header: ${header}`);
const strHeader = header.join(wtconfig.get('ET.ColumnSep', ','));
// Now we need to find out how many calls to make
const call = await et.getLevelCall(libType, level);
// Open a file stream
const tmpFile = await excel2.getFileName({ Library: libName, Level: level, Type: 'tmp', Module: i18n.t('Modules.ET.Name'), exType: exType });
var fs = require('fs');
var stream = fs.createWriteStream(tmpFile, {flags:'a'});
// Add the header
stream.write( strHeader + "\n");
var sectionData, x;
{
// Get all the items in small chuncks
sectionData = await et.getSectionData();
log.verbose(`Amount of chunks in sectionData are: ${sectionData.length}`);
let item;
let counter = 1;
const totalSize = JSONPath({path: '$..totalSize', json: sectionData[0]});
let jPath, sectionChunk;
if (libType == et.ETmediaType.Libraries)
{
jPath = "$.MediaContainer.Directory[*]";
}
else if (libType == et.ETmediaType.Playlists)
{
jPath = "$.MediaContainer.Metadata[*]";
}
else
{
jPath = "$.MediaContainer.Metadata[*]";
}
const bExportPosters = wtconfig.get(`ET.CustomLevels.${et.expSettings.libTypeSec}.Posters.${et.expSettings.levelName}`, false);
const bExportArt = wtconfig.get(`ET.CustomLevels.${et.expSettings.libTypeSec}.Art.${et.expSettings.levelName}`, false);
for (x=0; x<sectionData.length; x++)
{
et.updateStatusMsg(et.rawMsgType.Chuncks, i18n.t('Modules.ET.Status.Processing-Chunk', {current: x, total: sectionData.length -1}));
sectionChunk = await JSONPath({path: jPath, json: sectionData[x]});
const fields = et.getFields( libType, level);
if ( call == 1 )
{
for (item of sectionChunk){
et.updateStatusMsg(et.rawMsgType.Items, i18n.t('Modules.ET.Status.ProcessItem', {count: counter, total: totalSize}));
await excel2.addRowToTmp( { libType: libType, level: level, data: item, stream: stream, fields: fields } );
if (bExportPosters)
{
await this.exportPics( { type: 'posters', data: item, baseURL: baseURL, accessToken: accessToken } )
}
if (bExportArt)
{
await this.exportPics( { type: 'arts', data: item, baseURL: baseURL, accessToken: accessToken } )
}
counter += 1;
await new Promise(resolve => setTimeout(resolve, 1));
}
}
else
{
// Get ratingKeys in the chunk
const urls = await JSONPath({path: '$..ratingKey', json: sectionChunk});
let urlStr = urls.join(',');
log.verbose(`Items to lookup are: ${urlStr}`);
et.updateStatusMsg(et.rawMsgType.Chuncks, i18n.t('Modules.ET.Status.Processing-Chunk', {current: x, total: sectionData.length -1}));
const urlWIthPath = '/library/metadata/' + urlStr + '?' + this.uriParams;
log.verbose(`Items retrieved`);
const contents = await et.getItemData({baseURL: baseURL, accessToken: accessToken, element: urlWIthPath});
const contentsItems = await JSONPath({path: '$.MediaContainer.Metadata[*]', json: contents});
for (item of contentsItems){
et.updateStatusMsg(et.rawMsgType.Items, i18n.t('Modules.ET.Status.ProcessItem', {count: counter, total: totalSize}));
if (bExportPosters)
{
await this.exportPics( { type: 'posters', data: item, baseURL: baseURL, accessToken: accessToken } )
}
if (bExportArt)
{
await this.exportPics( { type: 'arts', data: item, baseURL: baseURL, accessToken: accessToken } )
}
await excel2.addRowToTmp( { libType: libType, level: level, data: item, stream: stream, fields: fields } );
counter += 1;
await new Promise(resolve => setTimeout(resolve, 1));
}
}
}
}
stream.end();
// Rename to real file name
var newFile = tmpFile.replace('.tmp', '.csv')
fs.renameSync(tmpFile, newFile);
// Need to export to xlsx as well?
if (wtconfig.get('ET.ExpExcel')){
log.info('We need to create an xlsx file as well');
et.updateStatusMsg( et.rawMsgType.Info, i18n.t('Modules.ET.Status.CreateExlsFile'));
await excel2.createXLSXFile( {csvFile: newFile, level: level, libType: libType, libName: libName, exType: exType, pListType: pListType});
}
}
}
export { et, excel2 };

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,8 @@
// This file holds Excel export stuff
const excel = new class EXCEL {
constructor() {
}
}
export { excel };

View file

@ -291,6 +291,15 @@ const wtutils = new class WTUtils {
wtconfig.set('PMS.ContainerSize.3001', 20)
}
// ET Settings
if ( wtconfig.get('ET.ChReturn', 'N/A') == 'N/A' ){
wtconfig.set('ET.ChReturn', '<RETURN>')
}
if ( wtconfig.get('ET.ChNewLine', 'N/A') == 'N/A' ){
wtconfig.set('ET.ChNewLine', '<NEWLINE>')
}
if ( wtconfig.get('ET.TextQualifierCSV', 'N/A') == 'N/A' ){
wtconfig.set('ET.TextQualifierCSV', '"')
}
if ( wtconfig.get('ET.ArraySep', 'N/A') == 'N/A' ){
wtconfig.set('ET.ArraySep', '-')
}

View file

@ -312,6 +312,18 @@
case "20Mb":
size = "20971520";
break;
case "40Mb":
size = "41943040";
break;
case "60Mb":
size = "62914560";
break;
case "100Mb":
size = "104857600";
break;
case "200Mb":
size = "209715200";
break;
default:
size = "1048576"
}
@ -329,7 +341,7 @@
return options;
},
LogLevelSizes: function() {
const options = ['1Mb', '2Mb', '4Mb', '8Mb', '10Mb', '20Mb'];
const options = ['1Mb', '2Mb', '4Mb', '8Mb', '10Mb', '20Mb', '40Mb', '60Mb', '100Mb', '200Mb'];
return options;
},
BetaLevels: function() {

View file

@ -36,7 +36,6 @@
},
methods: {
async serverSelected() {
let serverCheck = this.$store.getters.getSelectedServer;
if (serverCheck == "none") {
log.debug("serverCheck is none");

View file

@ -8,15 +8,15 @@ log.transports.file.fileName = wtutils.logFileName;
Vue.use(VueI18n)
function loadLocaleMessages () {
function loadLocaleMessages () {
wtutils.MoveToHome();
const messages = {}
const fs = require('fs')
// Force read en lang, since it's the fallback
const langCode = 'en'
var langFile = wtutils.Home + '/locales/' + langCode + '.json'
log.debug(`Loading language: ${langCode}`)
messages[langCode] = JSON.parse(fs.readFileSync(langFile, 'utf8'));
var langFile = wtutils.Home + '/locales/' + langCode + '.json'
log.debug(`Loading language: ${langCode}`)
messages[langCode] = JSON.parse(fs.readFileSync(langFile, 'utf8'));
log.debug(`Defined language: ${wtconfig.get('General.language')}`)
if (wtconfig.get('General.language', 'en') != 'en'){
// We need to preload an additional language

View file

@ -1,4 +1,6 @@
import {et, excel2} from '../../components/modules/ExportTools/scripts/et'
//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');
console.log = log.log;
@ -43,38 +45,12 @@ const mutations = {
};
const actions = {
async fetchSections({ commit, getters }) {
log.info("fetchSections called")
var baseURL = getters.getSelectedServerAddress
var accessToken = getters.getSelectedServerToken
commit('UPDATE_SECTIONS', await et.getSections(baseURL, accessToken))
},
exportMedias({ getters }) {
var baseURL = getters.getSelectedServerAddress;
var accessToken = getters.getSelectedServerToken;
var libType = getters.getLibType;
var pListType = getters.getSelectedLibTypeSec;
let levelName;
var libName = et.getLibDisplayName(getters.getSelectedSection, getters.getPmsSections);
if ([ et.ETmediaType.Libraries, et.ETmediaType.Playlists].indexOf(libType) > -1)
{
levelName = 'All'
}
else
{
levelName = et.getLevelDisplayName(getters.getSelectedExportLevel, libType);
}
excel2.createOutFile( {
libName: libName,
level: levelName,
libType: libType,
baseURL: baseURL,
accessToken: accessToken,
exType: libType,
pListType: pListType,
libTypeSec: getters.getSelectedLibTypeSec
} );
}
async fetchSections({ commit, getters }) {
log.info("fetchSections called")
var baseURL = getters.getSelectedServerAddress
var accessToken = getters.getSelectedServerToken
commit('UPDATE_SECTIONS', await et.getSections(baseURL, accessToken))
}
}
const getters = {

View file

@ -173,7 +173,9 @@ const actions = {
// The request was made but no response was received
// `error.request` is an instance of XMLHttpRequest in the browser and an instance of
// http.ClientRequest in node.js
log.error('loginToPlex: ' + error.request)
// log.error('loginToPlex: ' + error.request)
log.error('Could not connect to plex.tv');
alert(i18n.t('Common.Login.LoginConnectErr'));
} else {
// Something happened in setting up the request that triggered an Error
log.error('loginToPlex: ' + error.message)
@ -199,18 +201,20 @@ const actions = {
if (error.response) {
// The request was made and the server responded with a status code
// that falls out of the range of 2xx
log.error('loginToPlex: ' + error.response.status);
log.error('loginToPlex: ' + JSON.stringify(error.response.data));
log.error('loginToPlexToken1: ' + error.response.status);
log.error('loginToPlexToken2: ' + JSON.stringify(error.response.data));
alert(error.response.data.error)
//this.danger(error.response.status, error.response.data.error);
} else if (error.request) {
// The request was made but no response was received
// `error.request` is an instance of XMLHttpRequest in the browser and an instance of
// http.ClientRequest in node.js
log.error('loginToPlex: ' + error.request)
// log.error('loginToPlexToken3: ' + JSON.stringify(error.request));
log.error('Could not connect to plex.tv with a Token');
alert(i18n.t('Common.Login.LoginConnectErrToken'));
} else {
// Something happened in setting up the request that triggered an Error
log.error('loginToPlex: ' + error.message)
log.error('loginToPlexToken4: ' + error.message)
}})
},
updatingServerAddress({ commit}, status){

View file

@ -9,12 +9,12 @@ module.exports = {
enableInSFC: false
},
electronBuilder: {
builderOptions: {
builderOptions: {
appId: "com.webtools.webtools-ng",
artifactName: "${productName}-${version}.${env.AppRev}.${ext}",
directories: {
"buildResources": "src/assets"
},
},
"extraResources": [
{
"from": "./public/locales",
@ -28,7 +28,7 @@ module.exports = {
linux: {
category: "Utility",
icon: './src/assets/WebTools-512.png',
target: 'AppImage'
target: 'AppImage'
},
win: {
icon: './src/assets/WebTools-512.png'
@ -36,8 +36,13 @@ module.exports = {
mac: {
icon: './src/assets/WebTools-512.icns',
target: 'dmg'
},
"nsis": {
"differentialPackage": false
},
"dmg": {
"writeUpdateInfo": false
}
}
}
}