From 9d243dccff3267413d45549c793e68089d9a2ba1 Mon Sep 17 00:00:00 2001 From: Efox Date: Sun, 23 Jul 2023 22:12:37 -0300 Subject: [PATCH] v17.0.7b - Relevant performance improvement (+ bugfix) on lists indexing. - Fixed back button for Android devices. --- www/nodejs-project/assets/js/app/app.js | 2 +- .../assets/js/index/electron.js | 2 +- www/nodejs-project/assets/js/index/index.js | 2 +- www/nodejs-project/modules/bridge/client.js | 3 + .../modules/diagnostics/diagnostics.js | 3 +- .../modules/discovery/discovery.js | 5 +- www/nodejs-project/modules/explorer/client.js | 2 +- www/nodejs-project/modules/lists/index.js | 152 +++++++++--------- .../modules/lists/list-index-utils.js | 56 +++++-- .../modules/lists/list-index.js | 3 + www/nodejs-project/modules/lists/list.js | 7 +- www/nodejs-project/modules/lists/lists.js | 13 +- www/nodejs-project/modules/lists/loader.js | 19 ++- www/nodejs-project/modules/lists/manager.js | 2 +- .../modules/lists/update-list-index.js | 12 +- .../modules/multi-worker/multi-worker.js | 10 +- .../modules/promoter/promoter.js | 35 ++-- .../modules/stream-state/stream-state.js | 6 +- .../modules/streamer/streamer.js | 4 + 19 files changed, 204 insertions(+), 134 deletions(-) diff --git a/www/nodejs-project/assets/js/app/app.js b/www/nodejs-project/assets/js/app/app.js index 1529aee1..42213bf3 100644 --- a/www/nodejs-project/assets/js/app/app.js +++ b/www/nodejs-project/assets/js/app/app.js @@ -116,7 +116,7 @@ function initApp(){ console.log('FFmpeg checking succeeded', ret) }).catch(err => { console.error('FFmpeg checking error') - osd.show(String(err), 'fas fa-exclamation-triagle faclr-red', 'ffmpeg-dl', 'normal') + osd.show(String(err), 'fas fa-exclamation-triangle faclr-red', 'ffmpeg-dl', 'normal') }) }) } diff --git a/www/nodejs-project/assets/js/index/electron.js b/www/nodejs-project/assets/js/index/electron.js index 2a32a810..00ddc1db 100644 --- a/www/nodejs-project/assets/js/index/electron.js +++ b/www/nodejs-project/assets/js/index/electron.js @@ -68,7 +68,7 @@ class FFmpegDownloader { let err const file = await this.download(folder, osd, mask).catch(e => err = e) if (err) { - osd.show(String(err), 'fas fa-exclamation-triagle faclr-red', 'ffmpeg-dl', 'normal') + osd.show(String(err), 'fas fa-exclamation-triangle faclr-red', 'ffmpeg-dl', 'normal') } else { osd.show(mask.replace('{0}', '100%'), 'fas fa-circle-notch fa-spin', 'ffmpeg-dl', 'normal') this.executableDir = path.dirname(file) diff --git a/www/nodejs-project/assets/js/index/index.js b/www/nodejs-project/assets/js/index/index.js index 78012f98..234bee4c 100644 --- a/www/nodejs-project/assets/js/index/index.js +++ b/www/nodejs-project/assets/js/index/index.js @@ -356,7 +356,7 @@ document.addEventListener('resume', function () { document.addEventListener('backbutton', function (e) { if (app) { e.preventDefault(); - app.contentWindow.postMessage({ action: 'backbutton' }, location.origin); + app.postMessage({ action: 'backbutton' }, location.origin); } }, false); diff --git a/www/nodejs-project/modules/bridge/client.js b/www/nodejs-project/modules/bridge/client.js index a76ad3b5..175dfc99 100644 --- a/www/nodejs-project/modules/bridge/client.js +++ b/www/nodejs-project/modules/bridge/client.js @@ -29,6 +29,9 @@ function frontendBackendReadyCallback(origin){ frontendBackendReady.backendCallbacks.forEach(f => f()) frontendBackendReady.backendCallbacks = [] } + if(!app) { + app = document.querySelector('iframe').contentWindow + } if(frontendBackendReady.frontend && frontendBackendReady.backend){ app.lang = lang app.config = config diff --git a/www/nodejs-project/modules/diagnostics/diagnostics.js b/www/nodejs-project/modules/diagnostics/diagnostics.js index 5bf8914c..b8cb5b29 100644 --- a/www/nodejs-project/modules/diagnostics/diagnostics.js +++ b/www/nodejs-project/modules/diagnostics/diagnostics.js @@ -19,10 +19,9 @@ class Diagnostics extends Events { const listsRequesting = global.lists.requesting const tuning = global.tuning ? global.tuning.logText(false) : '' const processedLists = global.lists.processedLists.keys(); - const processing = global.lists.loader.processes.map(p => { + const processing = global.lists.loader.processes.filter(p => p.started() && !p.done()).map(p => { return { url: p.url, - started: p.started(), priority: p.priority } }); diff --git a/www/nodejs-project/modules/discovery/discovery.js b/www/nodejs-project/modules/discovery/discovery.js index f3353253..e6b6016e 100644 --- a/www/nodejs-project/modules/discovery/discovery.js +++ b/www/nodejs-project/modules/discovery/discovery.js @@ -69,9 +69,10 @@ class PublicIPTVListsDiscovery extends Events { const sortedLists = this.knownLists // .filter(list => this.opts.countries.includes(list.country)) .sort((a, b) => { + if (a.health === -1 && b.health === -1) return 0 if (a.health === -1) return 1 if (b.health === -1) return -1 - return b.health - a.health + return b.health > a.health ? 1 : (b.health < a.health ? -1 : 0) }) return this.domainCap(sortedLists, amount) } @@ -102,7 +103,7 @@ class PublicIPTVListsDiscovery extends Events { }) Object.keys(domains).forEach(dn => domains[dn] = 0) // reset counts and go again until fill limit } - return ret + return ret.slice(0, limit) } details(url) { return this.knownLists.find(l => l.url === url) diff --git a/www/nodejs-project/modules/explorer/client.js b/www/nodejs-project/modules/explorer/client.js index 4c5759b1..7b3811af 100644 --- a/www/nodejs-project/modules/explorer/client.js +++ b/www/nodejs-project/modules/explorer/client.js @@ -1475,7 +1475,7 @@ class ExplorerPrompt extends ExplorerOpenFile { this.endModal() this.emit('prompt-end', id) } - }, config['communitary-mode-lists-amount']) + }, 'submit') this.inputHelper.stop() this.emit('prompt-start') diff --git a/www/nodejs-project/modules/lists/index.js b/www/nodejs-project/modules/lists/index.js index 55c892dc..f3ac649c 100644 --- a/www/nodejs-project/modules/lists/index.js +++ b/www/nodejs-project/modules/lists/index.js @@ -1,4 +1,4 @@ -const async = require('async'), Common = require('../lists/common.js') +const pLimit = require('p-limit'), Common = require('../lists/common.js') class Index extends Common { constructor(opts){ @@ -186,88 +186,88 @@ class Index extends Common { this.searchMapCache[key] = {} return {} } - search(terms, opts={}){ - return new Promise((resolve, reject) => { - if(typeof(terms) == 'string'){ - terms = this.terms(terms, true, true) - } - let start = global.time(), bestResults = [], maybe = [], limit = opts.limit || 256 - if(!terms){ - return [] + async search(terms, opts={}){ + if(typeof(terms) == 'string'){ + terms = this.terms(terms, true, true) + } + let start = global.time(), bestResults = [], maybe = [], limit = opts.limit || 256 + if(!terms){ + return [] + } + const query = this.parseQuery(terms, opts) + let smap = this.searchMap(query, opts), ks = Object.keys(smap) + if(ks.length){ + if(this.debug){ + console.warn('M3U SEARCH PRE', terms, opts, (global.time() - start) +'s (pre time)', Object.assign({}, smap), (global.time() - start) +'s', terms) } - const query = this.parseQuery(terms, opts) - let smap = this.searchMap(query, opts), ks = Object.keys(smap) - if(ks.length){ - if(this.debug){ - console.warn('M3U SEARCH RESULTS', terms, opts, (global.time() - start) +'s (pre time)', Object.assign({}, smap), (global.time() - start) +'s', terms) + let results = [] + ks.forEach(listUrl => { + let ls = smap[listUrl]['n'] + if(opts.group){ + ls.push(...smap[listUrl]['g']) } - let results = [] - ks.forEach(listUrl => { - let ls = smap[listUrl]['n'] - if(opts.group){ - ls.push(...smap[listUrl]['g']) + smap[listUrl] = ls + }) + const limiter = pLimit(4) + const tasks = ks.map(listUrl => { + return async () => { + if(this.debug){ + console.warn('M3U SEARCH ITERATE LIST '+ listUrl, smap[listUrl].slice(0)) } - smap[listUrl] = ls - }) - async.eachOfLimit(ks, 4, (listUrl, i, icb) => { - if(listUrl && typeof(this.lists[listUrl]) != 'undefined' && smap[listUrl].length){ + if(typeof(this.lists[listUrl]) == 'undefined' || !smap[listUrl].length) return + let i = 0 + await this.lists[listUrl].iterate(e => { + i++ if(this.debug){ - console.warn('M3U SEARCH ITERATE', smap[listUrl].slice(0)) + console.warn('M3U SEARCH ITERATE '+ listUrl +':'+ i +' '+ e.url) } - this.lists[listUrl].iterate(e => { - if(this.debug){ - console.warn('M3U SEARCH ITERATE', e) - } - if(opts.type){ - if(this.validateType(e, opts.type, opts.typeStrict === true)){ - if(opts.typeStrict === true) { - e.source = listUrl - bestResults.push(e) - } else { - e.source = listUrl - results.push(e) - } + if(opts.type){ + if(this.validateType(e, opts.type, opts.typeStrict === true)){ + if(opts.typeStrict === true) { + e.source = listUrl + bestResults.push(e) + } else { + e.source = listUrl + results.push(e) } - } else { - bestResults.push(e) } - }, smap[listUrl]).catch(console.error).finally(icb) - } else { - icb() - } - }, () => { - if(this.debug){ - console.warn('M3U SEARCH RESULTS', (global.time() - start) +'s (partial time)', (global.time() - start) +'s', terms, bestResults.slice(0), results.slice(0), maybe.slice(0)) - } - results = bestResults.concat(results) - if(maybe.length){ - if(!results.length){ - results = maybe - maybe = [] - } - } - results = this.tools.dedup(results) // dedup before parentalControl to improve blocking - results = this.prepareEntries(results) - if(opts.parentalControl !== false){ - results = this.parentalControl.filter(results, true) - maybe = this.parentalControl.filter(maybe, true) - } - results = this.adjustSearchResults(results, opts, limit) - if(results.length < limit){ - maybe = this.adjustSearchResults(maybe, opts, limit - results.length) - } else { - maybe = [] - } - if(this.debug){ - console.warn('M3U SEARCH RESULTS', (global.time() - start) +'s (total time)', terms) - } - resolve({results, maybe}) - smap = bestResults = results = maybe = null - }) - } else { - resolve({results:[], maybe: []}) - } - }) + } else { + bestResults.push(e) + } + }, smap[listUrl]) + } + }).map(limiter) + await Promise.allSettled(tasks) + if(this.debug){ + console.warn('M3U SEARCH RESULTS', (global.time() - start) +'s (partial time)', (global.time() - start) +'s', terms, bestResults.slice(0), results.slice(0), maybe.slice(0)) + } + results = bestResults.concat(results) + if(maybe.length){ + if(!results.length){ + results = maybe + maybe = [] + } + } + results = this.tools.dedup(results) // dedup before parentalControl to improve blocking + results = this.prepareEntries(results) + + if(opts.parentalControl !== false){ + results = this.parentalControl.filter(results, true) + maybe = this.parentalControl.filter(maybe, true) + } + results = this.adjustSearchResults(results, opts, limit) + if(results.length < limit){ + maybe = this.adjustSearchResults(maybe, opts, limit - results.length) + } else { + maybe = [] + } + if(this.debug){ + console.warn('M3U SEARCH RESULTS*', (global.time() - start) +'s (total time)', terms) + } + return {results, maybe} + } else { + return {results:[], maybe: []} + } } getDomain(u){ if(u && u.indexOf('//')!=-1){ diff --git a/www/nodejs-project/modules/lists/list-index-utils.js b/www/nodejs-project/modules/lists/list-index-utils.js index ec8253c0..9629acb6 100644 --- a/www/nodejs-project/modules/lists/list-index-utils.js +++ b/www/nodejs-project/modules/lists/list-index-utils.js @@ -22,6 +22,39 @@ class ListIndexUtils extends Events { return 'live' } } + getRangesFromMap(map) { + const ranges = [] + map.forEach(n => ranges.push({start: this.linesMap[n], end: this.linesMap[n + 1] - 1})) + return ranges + } + async readLinesByMap(map) { + const ranges = this.getRangesFromMap(map) + const lines = {} + let fd = null + try { + fd = await fs.promises.open(this.file, 'r') + for (const [index, range] of ranges.entries()) { + const length = range.end - range.start + const buffer = Buffer.alloc(length) + const { bytesRead } = await fd.read(buffer, 0, length, range.start) + if(bytesRead < buffer.length) { + buffer = buffer.slice(0, bytesRead) + } + lines[map[index]] = buffer.toString() + } + } catch (error) { + console.error(error) + } finally { + if (fd !== null) { + try { + await fd.close().catch(console.error) + } catch (error) { + console.error("Error closing file descriptor:", error) + } + } + } + return lines + } readLines(map){ return new Promise((resolve, reject) => { if(map){ @@ -29,6 +62,9 @@ class ListIndexUtils extends Events { return reject('empty map requested') } map.sort() + if(Array.isArray(this.linesMap)) { + return this.readLinesByMap(map).then(resolve).catch(reject) + } } fs.stat(this.file, (err, stat) => { if(err || !stat){ @@ -78,32 +114,32 @@ class ListIndexUtils extends Events { }) }) } - async readLastLine(filePath) { - const bufferSize = 1024 - const { size } = await fs.promises.stat(filePath) - const fd = await fs.promises.open(filePath, 'r') + async readLastLine() { + const bufferSize = 2048 + const { size } = await fs.promises.stat(this.file) + const fd = await fs.promises.open(this.file, 'r') let line = '' let readPosition = Math.max(size - bufferSize, 0) while(readPosition >= 0){ const readSize = Math.min(bufferSize, size - readPosition) - const nextChunk = await fd.read(Buffer.alloc(readSize), 0, readSize, readPosition) - const content = String(nextChunk.buffer) + const { buffer, bytesRead } = await fd.read(Buffer.alloc(readSize), 0, readSize, readPosition) + const content = String(buffer) line = content + line const pos = content.lastIndexOf("\n") if (pos != -1) { line = line.substring(pos + 1) break } - if(!nextChunk.bytesRead) { + if(!bytesRead) { break } - readPosition -= nextChunk.bytesRead + readPosition -= bytesRead } await fd.close().catch(console.error) return line } async readIndex(){ - let line = await this.readLastLine(this.file) + let line = await this.readLastLine() let index = false if(line){ try { @@ -113,6 +149,8 @@ class ListIndexUtils extends Events { } } if(index && typeof(index.length) != 'undefined'){ + this.linesMap = index.linesMap + delete index.linesMap return index } else { console.error('Bad index', String(line).substr(0, 256), this.file) diff --git a/www/nodejs-project/modules/lists/list-index.js b/www/nodejs-project/modules/lists/list-index.js index f52e1e18..eabe571e 100644 --- a/www/nodejs-project/modules/lists/list-index.js +++ b/www/nodejs-project/modules/lists/list-index.js @@ -32,6 +32,9 @@ class ListIndex extends ListIndexUtils { } entries.forEach((s, i) => { entries[i]._ = parseInt(ids[i]) + if(!entries[i].source) { + entries[i].source = this.url + } }) } return entries diff --git a/www/nodejs-project/modules/lists/list.js b/www/nodejs-project/modules/lists/list.js index 18cb1baa..ed90fdeb 100644 --- a/www/nodejs-project/modules/lists/list.js +++ b/www/nodejs-project/modules/lists/list.js @@ -180,11 +180,8 @@ class List extends Events { } const entries = await this.indexer.entries(map) for(const e of entries) { - let ret = fn(e) - if(ret instanceof Promise){ - await ret - } - return ret === this.constants.BREAK + let ret = await fn(e) + if(ret === this.constants.BREAK) break } } async fetchAll(){ diff --git a/www/nodejs-project/modules/lists/lists.js b/www/nodejs-project/modules/lists/lists.js index 397cbb58..b46fc894 100644 --- a/www/nodejs-project/modules/lists/lists.js +++ b/www/nodejs-project/modules/lists/lists.js @@ -383,18 +383,18 @@ class Lists extends ListsEPGTools { return ret } addList(url, priority=9){ - let cancelled, started + let cancel, started, done this.processes.push({ promise: this.queue.add(async () => { - if(cancelled) return + if(cancel) return let err, contentLength if(typeof(this.lists[url]) == 'undefined'){ contentLength = await this.getListContentLength(url) - if(cancelled) return + if(cancel) return await this.loadList(url, contentLength).catch(e => err = e) } else { let contentLength = await this.shouldReloadList(url) - if(cancelled) return + if(cancel) return if(typeof(contentLength) == 'number'){ console.log('List got updated, reload it. '+ this.lists[url].contentLength +' => '+ contentLength) await this.loadList(url, contentLength).catch(e => err = e) @@ -402,9 +402,11 @@ class Lists extends ListsEPGTools { err = 'no need to update' } } + done = true }, { priority }), started: () => started, - cancel: () => cancelled = true, + cancel: () => cancel = true, + done: () => done || cancel, priority, url }) @@ -451,6 +453,7 @@ class Lists extends ListsEPGTools { this.lists[url] = list await list.start().catch(e => err = e) if(err){ + this.processedLists.delete(url) this.loadTimes[url].synced = global.time() if(!this.requesting[url] || this.requesting[url] == 'loading'){ this.requesting[url] = String(err) diff --git a/www/nodejs-project/modules/lists/loader.js b/www/nodejs-project/modules/lists/loader.js index 1285b5e5..50243383 100644 --- a/www/nodejs-project/modules/lists/loader.js +++ b/www/nodejs-project/modules/lists/loader.js @@ -26,12 +26,16 @@ class ListsLoader extends Events { const added = newMyLists.filter(l => !this.myCurrentLists.includes(l)) const removed = this.myCurrentLists.filter(l => !newMyLists.includes(l)) removed.forEach(u => this.master.remove(u)) + newMyLists.forEach(u => { + this.master.processedLists.has(u) && this.master.processedLists.delete(u) + }) this.myCurrentLists = newMyLists this.enqueue(added, 1) } if(keys.includes('communitary-mode-lists-amount')){ if(this.communityListsAmount != data['communitary-mode-lists-amount']){ this.communityListsAmount = data['communitary-mode-lists-amount'] + this.master.processedLists.clear() this.resetLowPriorityUpdates() } } @@ -49,29 +53,30 @@ class ListsLoader extends Events { this.resetLowPriorityUpdates() } async resetLowPriorityUpdates(){ // load community lists - const maxToTry = (this.communityListsAmount * 2) - this.master.processedLists.size - if(maxToTry <= 0) return + const maxListsToTry = 192 + const minListsToTry = Math.max(64, 3 * this.communityListsAmount) + if(minListsToTry < this.master.processedLists.size) return const taskId = Math.random() this.currentTaskId = taskId this.master.updaterFinished(false) this.processes = this.processes.filter(p => { /* Cancel pending processes to reorder it */ - if(p.priority > 1 && !p.started() && !this.myCurrentLists.includes(p.url)) { + if(p.priority > 1 && !p.started() && !p.done()) { p.cancel() return false } return true }) - const lists = await global.discovery.get(maxToTry * 2) // query a bit more to filter it + const lists = await global.discovery.get(maxListsToTry) const communityLists = [] lists.some(({ url }) => { if( !this.myCurrentLists.includes(url) && !this.processes.some(p => p.url == url) && !this.master.processedLists.has(url)) { communityLists.push(url) - return communityLists.length == maxToTry + return communityLists.length == maxListsToTry } }) const communityListsCached = await this.master.filterCachedUrls(communityLists) @@ -157,7 +162,7 @@ class ListsLoader extends Events { this.updater.close() } schedule(url, priority){ - let cancel, started + let cancel, started, done this.processes.some(p => p.url == url) || this.processes.push({ promise: this.queue.add(async () => { await global.Download.waitNetworkConnection() @@ -166,6 +171,7 @@ class ListsLoader extends Events { await this.prepareUpdater() this.results[url] = 'awaiting' this.results[url] = await this.updater.update(url).catch(console.error) + done = true const add = this.results[url] == 'updated' || (this.results[url] == 'already updated' && !this.master.processedLists.has(url)) add && this.master.addList(url, priority) this.updater.close() @@ -174,6 +180,7 @@ class ListsLoader extends Events { return started }, cancel: () => cancel = true, + done: () => done || cancel, priority, url }) diff --git a/www/nodejs-project/modules/lists/manager.js b/www/nodejs-project/modules/lists/manager.js index 8df784d6..be909187 100644 --- a/www/nodejs-project/modules/lists/manager.js +++ b/www/nodejs-project/modules/lists/manager.js @@ -803,7 +803,7 @@ class Manager extends ManagerEPG { {template: 'option', text: lang.SHARE, id: 'yes', fa: 'fas fa-users'} ], 'no') : 'no' // set local files as private if(chosen == 'yes'){ - global.osd.show(global.lang.COMMUNITY_THANKS_YOU, 'fas fa-heart faclr-purple', 'community-lists-thanks', 'normal') + global.osd.show(global.lang.COMMUNITY_THANKS_YOU, 'fas fa-heart faclr-purple', 'communitary-lists-thanks', 'normal') } this.setMeta(value, 'private', chosen != 'yes') let info, i = 20 diff --git a/www/nodejs-project/modules/lists/update-list-index.js b/www/nodejs-project/modules/lists/update-list-index.js index 71eecdf2..d105dddc 100644 --- a/www/nodejs-project/modules/lists/update-list-index.js +++ b/www/nodejs-project/modules/lists/update-list-index.js @@ -14,6 +14,8 @@ class UpdateListIndex extends ListIndexUtils { this.updateMeta = updateMeta this.forceDownload = forceDownload === true this.tmpfile = global.paths.temp +'/'+ parseInt(Math.random() * 100000000000) + '.tmp' + this.linesMapPtr = 0 + this.linesMap = [] this.reset() } ext(file){ @@ -127,7 +129,6 @@ class UpdateListIndex extends ListIndexUtils { } else { const file = path fs.stat(file, (err, stat) => { - console.error('ADDLISTSTAT='+JSON.stringify({file, stat, err, cl: this.updateMeta.contentLength})) if(stat && stat.size){ this.contentLength = stat.size if(stat.size > 0 && stat.size == this.updateMeta.contentLength){ @@ -188,7 +189,6 @@ class UpdateListIndex extends ListIndexUtils { reject('destroyed') } } - console.log('WILLPARSE='+ JSON.stringify(opts)) this.parser && this.parser.destroy() this.parser = new Parser(opts) this.parser.on('meta', meta => { @@ -220,7 +220,10 @@ class UpdateListIndex extends ListIndexUtils { }) } entry = this.indexate(entry, this.indexateIterator) - writer.write(JSON.stringify(entry) + "\r\n") + const line = JSON.stringify(entry) + "\n" + writer.write(line) + this.linesMap.push(this.linesMapPtr) + this.linesMapPtr += Buffer.byteLength(line, 'utf8') if(!this.uniqueStreamsIndexate.has(entry.url)) { this.uniqueStreamsIndexate.set(entry.url, null) this.uniqueStreamsIndexateIterator++ @@ -280,7 +283,6 @@ class UpdateListIndex extends ListIndexUtils { const exists = !err && stat && stat.size this.index.length = this.indexateIterator this.index.uniqueStreamsLength = this.uniqueStreamsIndexateIterator - this.index.rawGroups = this.groups this.index.groupsTypes = this.sniffGroupsTypes(this.groups) if(this.index.length || !exists) { const finish = err => { @@ -301,6 +303,8 @@ class UpdateListIndex extends ListIndexUtils { writer.on('finish', finish) writer.on('close', finish) writer.on('error', finish) + this.linesMap.push(this.linesMapPtr) + this.index.linesMap = this.linesMap writer.write(JSON.stringify(this.index)) writer.end() } else { diff --git a/www/nodejs-project/modules/multi-worker/multi-worker.js b/www/nodejs-project/modules/multi-worker/multi-worker.js index 5266b9d9..549b9be6 100644 --- a/www/nodejs-project/modules/multi-worker/multi-worker.js +++ b/www/nodejs-project/modules/multi-worker/multi-worker.js @@ -70,7 +70,7 @@ const setupConstructor = () => { file, method } - debug && global.osd.show(path.basename(file) +' '+ method, 'fas fas-circle-notch', 'mwrk-'+ id, 'persistent') + debug && global.osd.show(path.basename(file) +' '+ method, 'fas fas-circle-notch', 'mwrk-'+ id, 'long') try { self.worker.postMessage({method, id, file, args}) } catch(e) { @@ -137,18 +137,16 @@ const setupConstructor = () => { this.worker = new this.Worker(path.join(__dirname, 'worker.js'), { workerData, stdout: true, - stderr: true, - resourceLimits: { - maxOldGenerationSizeMb: 512 - } + stderr: true }) this.worker.on('error', err => { let serr = String(err) this.err = err console.error('error '+ err +' '+ serr +' '+ JSON.stringify(this.instances, null, 3), {err, serr}) if(serr.match(new RegExp('(out of memory|out_of_memory)', 'i'))){ + this.finished = true let msg = 'Worker exited out of memory, fix the settings and restart the app.' - global.osd.show(msg, 'fas fa-exclamation-triagle faclr-red', 'out-of-memory', 'persistent') + global.osd.show(msg, 'fas fa-exclamation-triangle faclr-red', 'out-of-memory', 'long') } if(typeof(err.preventDefault) == 'function'){ err.preventDefault() diff --git a/www/nodejs-project/modules/promoter/promoter.js b/www/nodejs-project/modules/promoter/promoter.js index 30e9124a..657a60ed 100644 --- a/www/nodejs-project/modules/promoter/promoter.js +++ b/www/nodejs-project/modules/promoter/promoter.js @@ -5,18 +5,31 @@ class Promoter { global.explorer.applyFilters = this.applyFilters.bind(this) } this.startTime = global.time() - global.ui.on('video-error', () => this.promote()) - global.ui.on('streamer-is-slow', () => this.promote()) - global.streamer.on('hard-failure', () => this.promote()) + this.promoteDialogTime = 0 + this.promoteDialogInterval = 1800 + global.ui.on('video-error', () => this.promoteDialogSignal()) + global.ui.on('streamer-is-slow', () => this.promoteDialogSignal()) + global.streamer.on('hard-failure', () => this.promoteDialogSignal()) + global.streamer.on('stop', () => this.promoteDialog()) } - async promote(){ - if(this.promoteDialogShown) return - const elapsedTime = global.time() - this.startTime - if(elapsedTime < 30) return - const a = await this.offer('dialog') - if(a) { - this.dialogOffer(a).catch(global.displayErr) - } + async promoteDialog(){ + const now = global.time() + if(this.promoteDialogPending !== true) return + // small delay to check if it will not load other stream right after + process.nextTick(() => { + if(this.promoteDialogPending !== true) return + if((now - this.promoteDialogTime) < this.promoteDialogInterval) return + if(global.streamer.active || global.streamer.isTuning()) return + const runningTime = now - this.startTime + if(runningTime < 30) return + this.promoteDialogTime = now + this.promoteDialogPending = false + this.offer('dialog').then(a => this.dialogOffer(a)).catch(console.error) + }) + } + async promoteDialogSignal(){ + this.promoteDialogPending = true + this.promoteDialog().catch(console.error) } async offer(type){ const atts = { diff --git a/www/nodejs-project/modules/stream-state/stream-state.js b/www/nodejs-project/modules/stream-state/stream-state.js index 6199fad5..a0a6c3c9 100644 --- a/www/nodejs-project/modules/stream-state/stream-state.js +++ b/www/nodejs-project/modules/stream-state/stream-state.js @@ -104,12 +104,12 @@ class StreamState extends Events { return null } set(url, state, isTrusted, atts){ - if(typeof(this.data) == 'object'){ - if(!isTrusted && typeof(this.clientFailures[url]) != 'undefined'){ + if(typeof(this.data) == 'object') { + if(!isTrusted && typeof(this.clientFailures[url]) != 'undefined') { return } let isMega = global.mega.isMega(url) - if(!isMega){ + if(!isMega) { let changed, time = global.time() if(typeof(this.waiting[url]) != 'undefined'){ changed = true diff --git a/www/nodejs-project/modules/streamer/streamer.js b/www/nodejs-project/modules/streamer/streamer.js index 95d9e547..5c7e1c12 100644 --- a/www/nodejs-project/modules/streamer/streamer.js +++ b/www/nodejs-project/modules/streamer/streamer.js @@ -96,6 +96,9 @@ class StreamerTools extends Events { delete this.streamInfoCaching[cachingKey] } } + isTuning(){ + return global.tuning && global.tuning.active() + } ext(file){ let basename = String(file).split('?')[0].split('#')[0].split('/').pop() basename = basename.split('.') @@ -1056,6 +1059,7 @@ class Streamer extends StreamerAbout { if(!silent){ global.osd.show(global.lang.NONE_STREAM_WORKED_X.format(name), 'fas fa-exclamation-triangle faclr-red', 'streamer', 'normal') } + this.emit('hard-failure') } else { this.setTuneable(true) }