stremiok 2.2.0 → 2.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +37 -0
- package/README.md +8 -6
- package/config.xml +1 -1
- package/css/style.css +11 -8
- package/index.html +33 -33
- package/js/app.js +24 -22
- package/js/focus.js +5 -5
- package/js/iptv.js +15 -2
- package/js/player-core.js +71 -9
- package/js/player-lang.js +66 -5
- package/js/player-store.js +4 -3
- package/js/player-subs.js +67 -13
- package/js/stremio.js +154 -23
- package/js/util.js +55 -13
- package/js/view-core.js +43 -13
- package/js/view-detail.js +36 -8
- package/js/view-discover.js +1 -1
- package/js/view-guide.js +41 -2
- package/js/view-home.js +33 -8
- package/js/view-settings.js +208 -57
- package/js/views.js +2 -2
- package/js/ytplay.js +4 -3
- package/package.json +2 -1
- package/service/index.js +33 -9
package/js/view-settings.js
CHANGED
|
@@ -98,11 +98,35 @@
|
|
|
98
98
|
}
|
|
99
99
|
|
|
100
100
|
// ================= SUBTITLE CONFIG =================
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
['
|
|
101
|
+
// Every language player-lang recognizes on a track (its LANG_ALIASES), by name.
|
|
102
|
+
var SUB_LANGS = [['off', 'Off'], ['afr', 'Afrikaans'], ['alb', 'Albanian'], ['ara', 'Arabic'],
|
|
103
|
+
['arg', 'Aragonese'], ['arm', 'Armenian'], ['ast', 'Asturian'], ['aze', 'Azerbaijani'],
|
|
104
|
+
['baq', 'Basque'], ['bel', 'Belarusian'], ['ben', 'Bengali'], ['bos', 'Bosnian'],
|
|
105
|
+
['bre', 'Breton'], ['bul', 'Bulgarian'], ['bur', 'Burmese'], ['cat', 'Catalan'],
|
|
106
|
+
['chi', 'Chinese'], ['hrv', 'Croatian'], ['cze', 'Czech'], ['dan', 'Danish'], ['prs', 'Dari'],
|
|
107
|
+
['dut', 'Dutch'], ['eng', 'English'], ['epo', 'Esperanto'], ['est', 'Estonian'],
|
|
108
|
+
['ext', 'Extremaduran'], ['fil', 'Filipino'], ['fin', 'Finnish'], ['fre', 'French'],
|
|
109
|
+
['glg', 'Galician'], ['geo', 'Georgian'], ['ger', 'German'], ['gre', 'Greek'],
|
|
110
|
+
['heb', 'Hebrew'], ['hin', 'Hindi'], ['hun', 'Hungarian'], ['ice', 'Icelandic'],
|
|
111
|
+
['ibo', 'Igbo'], ['ind', 'Indonesian'], ['ina', 'Interlingua'], ['gle', 'Irish'],
|
|
112
|
+
['ita', 'Italian'], ['jpn', 'Japanese'], ['kan', 'Kannada'], ['kaz', 'Kazakh'],
|
|
113
|
+
['khm', 'Khmer'], ['kor', 'Korean'], ['kur', 'Kurdish'], ['lav', 'Latvian'],
|
|
114
|
+
['lit', 'Lithuanian'], ['ltz', 'Luxembourgish'], ['mac', 'Macedonian'], ['may', 'Malay'],
|
|
115
|
+
['mal', 'Malayalam'], ['mni', 'Manipuri'], ['mar', 'Marathi'], ['mon', 'Mongolian'],
|
|
116
|
+
['mne', 'Montenegrin'], ['nav', 'Navajo'], ['nep', 'Nepali'], ['sme', 'Northern Sami'],
|
|
117
|
+
['nor', 'Norwegian'], ['oci', 'Occitan'], ['ori', 'Odia'], ['pus', 'Pashto'],
|
|
118
|
+
['per', 'Persian'], ['pol', 'Polish'], ['por', 'Portuguese'], ['pan', 'Punjabi'],
|
|
119
|
+
['rum', 'Romanian'], ['rus', 'Russian'], ['sat', 'Santali'], ['gla', 'Scottish Gaelic'],
|
|
120
|
+
['srp', 'Serbian'], ['snd', 'Sindhi'], ['sin', 'Sinhala'], ['slo', 'Slovak'],
|
|
121
|
+
['slv', 'Slovenian'], ['som', 'Somali'], ['spa', 'Spanish'], ['swa', 'Swahili'],
|
|
122
|
+
['swe', 'Swedish'], ['syr', 'Syriac'], ['tam', 'Tamil'], ['tat', 'Tatar'], ['tel', 'Telugu'],
|
|
123
|
+
['tha', 'Thai'], ['tok', 'Toki Pona'], ['tur', 'Turkish'], ['tuk', 'Turkmen'],
|
|
124
|
+
['ukr', 'Ukrainian'], ['urd', 'Urdu'], ['uzb', 'Uzbek'], ['vie', 'Vietnamese'],
|
|
125
|
+
['wel', 'Welsh']];
|
|
104
126
|
// A second choice, turned on when nothing is in the default language (from any source).
|
|
105
127
|
var SUB_LANGS2 = [['none', 'None']].concat(SUB_LANGS.slice(1));
|
|
128
|
+
// The subtitle menu with only the three languages above (and tracks of no known language).
|
|
129
|
+
var SUB_ONLY = [['off', 'Off'], ['on', 'On']];
|
|
106
130
|
var SUB_SIZES = [['small', 'Small'], ['medium', 'Medium'], ['large', 'Large'], ['xlarge', 'Extra Large']];
|
|
107
131
|
|
|
108
132
|
function labelFor(list, v) {
|
|
@@ -169,9 +193,13 @@
|
|
|
169
193
|
var bgs = { dark: 1, black: 1, gray: 1, white: 1 };
|
|
170
194
|
return { accent: ACCENT_NAMES[accent] ? accent : 'indigo', bg: bgs[bg] ? bg : 'dark' };
|
|
171
195
|
}
|
|
196
|
+
// Zoom: everything bigger (see U.setZoom), in percent.
|
|
197
|
+
var ZOOMS = [['100', '100%'], ['110', '110%'], ['120', '120%'], ['130', '130%'], ['140', '140%']];
|
|
198
|
+
function zoomPct() { return Stremio.getPrefs().zoom; }
|
|
172
199
|
function applyAppearance() {
|
|
173
200
|
var a = appearance();
|
|
174
201
|
U.applyTheme(a.accent, a.bg);
|
|
202
|
+
U.setZoom(zoomPct() / 100);
|
|
175
203
|
}
|
|
176
204
|
function settingsAppearance(wrap) {
|
|
177
205
|
var store = { get: appearance, set: function (cfg) {
|
|
@@ -183,6 +211,10 @@
|
|
|
183
211
|
wrap.appendChild(U.el('h2', null, 'Appearance'));
|
|
184
212
|
wrap.appendChild(subPickRow('Background', BACKGROUNDS, 'bg', store));
|
|
185
213
|
wrap.appendChild(subPickRow('Accent color', accents, 'accent', store));
|
|
214
|
+
wrap.appendChild(subPickRow('Zoom', ZOOMS, 'zoom', {
|
|
215
|
+
get: function () { return { zoom: '' + zoomPct() }; },
|
|
216
|
+
set: function (cfg) { Stremio.setPref('zoom', +cfg.zoom); applyAppearance(); }
|
|
217
|
+
}));
|
|
186
218
|
wrap.appendChild(subPickRow('Poster orientation', POSTER_SHAPES, 'posterShape', {
|
|
187
219
|
get: function () { return { posterShape: Stremio.getPrefs().posterShape }; },
|
|
188
220
|
set: function (cfg) { Stremio.setPref('posterShape', cfg.posterShape); markHomeDirty(); } // Home redraws on return
|
|
@@ -314,6 +346,7 @@
|
|
|
314
346
|
var SETTINGS_GROUPS = {
|
|
315
347
|
content: { title: 'Content', rows: [
|
|
316
348
|
['Addons', 'Catalog, stream & subtitle addons', 'addons'],
|
|
349
|
+
['Streaming server', 'Stremio’s streaming server or TorrServer on your network: torrents, and videos the TV can’t play', 'server'],
|
|
317
350
|
['Integrations', 'API keys (OMDb, TMDB, MDBList), where-to-watch country', 'integrations'],
|
|
318
351
|
['IPTV', 'Manage M3U playlist URLs', 'iptv'],
|
|
319
352
|
['YouTube', 'Your YouTube channels, playlists and searches; YouTube in Search', 'youtube'],
|
|
@@ -338,7 +371,7 @@
|
|
|
338
371
|
// BACK goes up one level, onto the row it came from: from a section to its group (on
|
|
339
372
|
// that section, not the first one), from Home feeds / Search results to Appearance,
|
|
340
373
|
// from a group to the Settings list (on that group).
|
|
341
|
-
var SECTION_PARENT = { menuorder: 'appearance', feeds: 'appearance', searchfeeds: 'appearance', aiomanager: 'addons' };
|
|
374
|
+
var SECTION_PARENT = { menuorder: 'appearance', feeds: 'appearance', searchfeeds: 'appearance', aiomanager: 'addons', subtitlelook: 'subtitles', rankfilters: 'ranking', rankplay: 'ranking' };
|
|
342
375
|
Object.keys(SETTINGS_GROUPS).forEach(function (g) {
|
|
343
376
|
SETTINGS_GROUPS[g].rows.forEach(function (row) { SECTION_PARENT[row[2]] = g; });
|
|
344
377
|
});
|
|
@@ -365,12 +398,15 @@
|
|
|
365
398
|
else if (_settingsSection === 'integrations') { settingsIntegrations(wrap); }
|
|
366
399
|
else if (_settingsSection === 'audio') { settingsAudio(wrap); }
|
|
367
400
|
else if (_settingsSection === 'subtitles') { settingsSubtitles(wrap); }
|
|
401
|
+
else if (_settingsSection === 'subtitlelook') { settingsSubtitleLook(wrap); }
|
|
368
402
|
else if (_settingsSection === 'skipping') { settingsSkipping(wrap); }
|
|
369
403
|
else if (_settingsSection === 'seeking') { settingsSeeking(wrap); }
|
|
370
404
|
else if (_settingsSection === 'menuorder') { settingsFeeds(wrap, 'menu'); }
|
|
371
405
|
else if (_settingsSection === 'feeds') { settingsFeeds(wrap, 'home'); }
|
|
372
406
|
else if (_settingsSection === 'searchfeeds') { settingsFeeds(wrap, 'search'); }
|
|
373
407
|
else if (_settingsSection === 'ranking') { settingsFeeds(wrap, 'ranking'); }
|
|
408
|
+
else if (_settingsSection === 'rankfilters') { settingsRankFilters(wrap); }
|
|
409
|
+
else if (_settingsSection === 'rankplay') { settingsRankPlay(wrap); }
|
|
374
410
|
else if (SETTINGS_GROUPS[_settingsSection]) { settingsGroup(wrap, _settingsSection); }
|
|
375
411
|
else if (_settingsSection === 'logs') { settingsLogs(wrap); }
|
|
376
412
|
else if (_settingsSection === 'storage') { settingsStorage(wrap); }
|
|
@@ -380,6 +416,7 @@
|
|
|
380
416
|
else if (_settingsSection === 'appshortcuts') { settingsAppShortcuts(wrap); }
|
|
381
417
|
else if (_settingsSection === 'import') { settingsImport(wrap); }
|
|
382
418
|
else if (_settingsSection === 'aiomanager') { settingsAiom(wrap); }
|
|
419
|
+
else if (_settingsSection === 'server') { settingsServer(wrap); }
|
|
383
420
|
else if (_settingsSection === 'appearance') { settingsAppearance(wrap); }
|
|
384
421
|
else if (_settingsSection === 'formats') { settingsFormats(wrap); }
|
|
385
422
|
else { settingsMenu(wrap); }
|
|
@@ -422,7 +459,7 @@
|
|
|
422
459
|
wrap.appendChild(U.el('h2', null, 'Settings'));
|
|
423
460
|
wrap.appendChild(sectionRow('Content', 'Addons, API keys, IPTV playlists, streaming apps, importing a configuration file', 'content'));
|
|
424
461
|
wrap.appendChild(sectionRow('Playback', 'Audio and subtitles, source ranking, feed sources, formats', 'playback'));
|
|
425
|
-
wrap.appendChild(sectionRow('Appearance', 'Background, accent color, poster orientation, Home feeds, Search results', 'appearance'));
|
|
462
|
+
wrap.appendChild(sectionRow('Appearance', 'Background, accent color, zoom, poster orientation, Home feeds, Search results', 'appearance'));
|
|
426
463
|
wrap.appendChild(sectionRow('Diagnostics', 'Logs, storage, installed apps; how StremioK was installed', 'diagnostics'));
|
|
427
464
|
if (typeof YTPlay !== 'undefined' && YTPlay.installMode && YTPlay.installMode() === 'tizenbrew') { wrap.appendChild(U.el('div', 'hint', TIZENBREW_NOTE)); }
|
|
428
465
|
focusBack(wrap);
|
|
@@ -945,6 +982,60 @@
|
|
|
945
982
|
}
|
|
946
983
|
});
|
|
947
984
|
}
|
|
985
|
+
// Streaming server: Stremio's or TorrServer, on your network (see Stremio.server). Picking one
|
|
986
|
+
// asks for its address; Test says whether it answers.
|
|
987
|
+
var SERVERS = [['', 'Off'], ['stremio', 'Stremio server'], ['torrserver', 'TorrServer']];
|
|
988
|
+
var SERVER_PORT = { stremio: 11470, torrserver: 8090 };
|
|
989
|
+
var TORRENT_WAITS = [['45', '45 seconds'], ['60', '1 minute'], ['120', '2 minutes'], ['180', '3 minutes'], ['300', '5 minutes']];
|
|
990
|
+
function askServerAddress(kind, url) {
|
|
991
|
+
var eg = 'http://192.168.0.10:' + SERVER_PORT[kind];
|
|
992
|
+
App.openEntry({
|
|
993
|
+
title: (kind === 'stremio' ? 'Stremio server' : 'TorrServer') + ': address',
|
|
994
|
+
hint: 'Its address on your network, like ' + eg + '. RETURN cancels.',
|
|
995
|
+
value: url || 'http://', placeholder: eg, phone: 'server',
|
|
996
|
+
validate: function (v) { return Stremio.serverAddressProblem(v); },
|
|
997
|
+
onConfirm: function (v) { Stremio.setServer({ kind: kind, url: v }); App.back(); renderSettings(); }
|
|
998
|
+
});
|
|
999
|
+
}
|
|
1000
|
+
function settingsServer(wrap) {
|
|
1001
|
+
wrap.appendChild(U.el('h2', null, 'Streaming server'));
|
|
1002
|
+
wrap.appendChild(U.el('div', 'hint', 'Torrent-only sources play through it; Stremio’s can also convert a video the TV can’t play.'));
|
|
1003
|
+
var sv = Stremio.server();
|
|
1004
|
+
wrap.appendChild(subPickRow('Server', SERVERS, 'kind', {
|
|
1005
|
+
get: function () { return { kind: Stremio.server().kind }; },
|
|
1006
|
+
set: function (cfg) {
|
|
1007
|
+
var cur = Stremio.server();
|
|
1008
|
+
if (!cfg.kind) { Stremio.setServer({ kind: '' }); renderSettings(); return; }
|
|
1009
|
+
askServerAddress(cfg.kind, cur.kind === cfg.kind ? cur.url : '');
|
|
1010
|
+
}
|
|
1011
|
+
}));
|
|
1012
|
+
if (!sv.kind) { return; }
|
|
1013
|
+
var addr = U.el('div', 'addon-item focusable cfg-row');
|
|
1014
|
+
addr.appendChild(U.el('div', 'a-name', 'Address: ' + sv.url));
|
|
1015
|
+
addr.appendChild(U.el('div', 'a-url', 'Press OK to change'));
|
|
1016
|
+
addr.__onselect = function () { askServerAddress(sv.kind, sv.url); };
|
|
1017
|
+
wrap.appendChild(addr);
|
|
1018
|
+
var test = U.el('div', 'addon-item focusable cfg-row'), said = U.el('div', 'a-url', 'Press OK to see whether it answers');
|
|
1019
|
+
test.appendChild(U.el('div', 'a-name', 'Test'));
|
|
1020
|
+
test.appendChild(said);
|
|
1021
|
+
test.__onselect = function () {
|
|
1022
|
+
said.textContent = 'Asking…';
|
|
1023
|
+
Stremio.testServer().then(function (r) { said.textContent = (r.ok ? '✓ ' : '✗ ') + r.text; });
|
|
1024
|
+
};
|
|
1025
|
+
wrap.appendChild(test);
|
|
1026
|
+
wrap.appendChild(subPickRow('Wait for a torrent to start', TORRENT_WAITS, 'wait', {
|
|
1027
|
+
get: function () { return { wait: '' + Stremio.server().wait }; },
|
|
1028
|
+
set: function (cfg) { Stremio.setServer({ kind: Stremio.server().kind, wait: +cfg.wait }); }
|
|
1029
|
+
}));
|
|
1030
|
+
if (sv.kind === 'stremio') {
|
|
1031
|
+
wrap.appendChild(subPickRow('Convert videos the TV can’t play', [['on', 'On'], ['off', 'Off']], 'convert', {
|
|
1032
|
+
get: function () { return { convert: Stremio.server().convert ? 'on' : 'off' }; },
|
|
1033
|
+
set: function (cfg) { Stremio.setServer({ kind: 'stremio', convert: cfg.convert === 'on' }); }
|
|
1034
|
+
}));
|
|
1035
|
+
}
|
|
1036
|
+
}
|
|
1037
|
+
|
|
1038
|
+
var IPTV_EVERY = [['0', 'Off'], ['1', 'Every hour'], ['3', 'Every 3 hours'], ['6', 'Every 6 hours'], ['12', 'Every 12 hours']];
|
|
948
1039
|
function settingsIptv(wrap) {
|
|
949
1040
|
wrap.appendChild(U.el('h2', null, 'IPTV'));
|
|
950
1041
|
var playlists = Stremio.iptvGetPlaylists ? Stremio.iptvGetPlaylists() : [];
|
|
@@ -1031,6 +1122,10 @@
|
|
|
1031
1122
|
xt.appendChild(U.el('div', 'a-url', 'Its server, username and password: its channels and TV guide added'));
|
|
1032
1123
|
xt.__onselect = addXtream;
|
|
1033
1124
|
wrap.appendChild(xt);
|
|
1125
|
+
if (playlists.length && Stremio.iptvRefreshEvery) { // (all of them, with their guides, as Reload does)
|
|
1126
|
+
wrap.appendChild(subPickRow('Auto-refresh', IPTV_EVERY, 'every',
|
|
1127
|
+
{ get: function () { return { every: String(Stremio.iptvRefreshEvery()) }; }, set: function (c) { Stremio.iptvSetRefreshEvery(+c.every); } }));
|
|
1128
|
+
}
|
|
1034
1129
|
|
|
1035
1130
|
wrap.appendChild(U.el('div', 'hint',
|
|
1036
1131
|
'Channels are grouped into IPTV and Radio rows on Home. ▲ / ▼ set the playlists\' order: a channel in two playlists comes from the first.'));
|
|
@@ -1399,14 +1494,7 @@
|
|
|
1399
1494
|
wrap.appendChild(subPickRow('Default language', SUB_LANGS, 'lang'));
|
|
1400
1495
|
wrap.appendChild(subPickRow('Second choice', SUB_LANGS2, 'lang2'));
|
|
1401
1496
|
wrap.appendChild(subPickRow('Second subtitle (at the top)', SUB_LANGS, 'second'));
|
|
1402
|
-
wrap.appendChild(subPickRow('
|
|
1403
|
-
// [id, label] for the picker (colors with a swatch)
|
|
1404
|
-
function plain(list) { return list.map(function (x) { return [x[0], x[1]]; }); }
|
|
1405
|
-
wrap.appendChild(subPickRow('Color', Player.SUB_COLORS.map(function (x) { return [x[0], x[1], null, x[2]]; }), 'color'));
|
|
1406
|
-
wrap.appendChild(subPickRow('Background', plain(Player.SUB_BGS), 'bg'));
|
|
1407
|
-
wrap.appendChild(subPickRow('Edge', plain(Player.SUB_EDGES), 'edge'));
|
|
1408
|
-
wrap.appendChild(subPickRow('Position', plain(Player.SUB_POSITIONS), 'pos'));
|
|
1409
|
-
wrap.appendChild(subPickRow('Font', Player.SUB_FONTS, 'font'));
|
|
1497
|
+
wrap.appendChild(subPickRow('Only my languages', SUB_ONLY, 'only'));
|
|
1410
1498
|
// lines to leave out: those with one of your words (a subtitle site's ads, a file's name…)
|
|
1411
1499
|
var skip = Player.getSubCfg().skip || [];
|
|
1412
1500
|
var sk = U.el('div', 'addon-item focusable cfg-row');
|
|
@@ -1419,6 +1507,21 @@
|
|
|
1419
1507
|
onConfirm: function (v) { var c = Player.getSubCfg(); c.skip = ('' + v).split(','); Player.setSubCfg(c); App.back(); renderSettings(); } });
|
|
1420
1508
|
};
|
|
1421
1509
|
wrap.appendChild(sk);
|
|
1510
|
+
var look = sectionRow('Appearance ›', 'Size, color, background, edge, position, font', 'subtitlelook'); // (their own page: settingsSubtitleLook)
|
|
1511
|
+
wrap.appendChild(look);
|
|
1512
|
+
if (_focusChild === 'subtitlelook') { _focusChild = null; Focus.setScope(scr('settings'), look); } else { focusSettings(); }
|
|
1513
|
+
}
|
|
1514
|
+
// Subtitles › Appearance: how subtitles look.
|
|
1515
|
+
function settingsSubtitleLook(wrap) {
|
|
1516
|
+
wrap.appendChild(U.el('h2', null, 'Subtitle appearance'));
|
|
1517
|
+
wrap.appendChild(subPickRow('Size', SUB_SIZES, 'size'));
|
|
1518
|
+
// [id, label] for the picker (colors with a swatch)
|
|
1519
|
+
function plain(list) { return list.map(function (x) { return [x[0], x[1]]; }); }
|
|
1520
|
+
wrap.appendChild(subPickRow('Color', Player.SUB_COLORS.map(function (x) { return [x[0], x[1], null, x[2]]; }), 'color'));
|
|
1521
|
+
wrap.appendChild(subPickRow('Background', plain(Player.SUB_BGS), 'bg'));
|
|
1522
|
+
wrap.appendChild(subPickRow('Edge', plain(Player.SUB_EDGES), 'edge'));
|
|
1523
|
+
wrap.appendChild(subPickRow('Position', plain(Player.SUB_POSITIONS), 'pos'));
|
|
1524
|
+
wrap.appendChild(subPickRow('Font', Player.SUB_FONTS, 'font'));
|
|
1422
1525
|
focusSettings();
|
|
1423
1526
|
}
|
|
1424
1527
|
|
|
@@ -1928,7 +2031,7 @@
|
|
|
1928
2031
|
list: function () { return Promise.resolve(Stremio.getRanking().criteria); }, keyOf: function (c) { return c.key; },
|
|
1929
2032
|
move: function (k, d) { Stremio.moveRanking(k, d); return Promise.resolve(); }, toggle: function (k) { Stremio.toggleRanking(k); },
|
|
1930
2033
|
hidden: function (k) { return !Stremio.getRanking().criteria.some(function (c) { return c.key === k && c.on; }); },
|
|
1931
|
-
before: function (wrap) { // played before, above the resolution groups
|
|
2034
|
+
before: function (wrap) { // played before, above the resolution groups; then the two pages
|
|
1932
2035
|
var played = Stremio.getRanking().played;
|
|
1933
2036
|
var r = U.el('div', 'addon-item focusable cfg-row feed-extra');
|
|
1934
2037
|
r.setAttribute('data-fk', 'played'); r.setAttribute('data-ctl', 'extra');
|
|
@@ -1937,48 +2040,9 @@
|
|
|
1937
2040
|
: 'Sources you played rank like any other') + ' · OK to turn ' + (played ? 'off' : 'on')));
|
|
1938
2041
|
r.__onselect = function () { Stremio.setPlayedFirst(!played); refeed('ranking', 'played', 'extra'); };
|
|
1939
2042
|
wrap.appendChild(r);
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
un.setAttribute('data-fk', 'unplayable'); un.setAttribute('data-ctl', 'extra');
|
|
1944
|
-
un.appendChild(U.el('div', 'a-name', 'Sources the TV can’t play: ' + (hideUn ? 'Hidden' : 'Shown')));
|
|
1945
|
-
un.appendChild(U.el('div', 'a-url', (hideUn ? 'Left out (torrents, links it can’t open): direct links only; where-to-watch apps stay'
|
|
1946
|
-
: 'Listed, dimmed, at the bottom (torrents, links it can’t open)') + ' · OK to ' + (hideUn ? 'show them' : 'hide them')));
|
|
1947
|
-
un.__onselect = function () { Stremio.setPref('hideUnplayable', !hideUn); refeed('ranking', 'unplayable', 'extra'); };
|
|
1948
|
-
wrap.appendChild(un);
|
|
1949
|
-
// skip the source list: Play plays the top source at once
|
|
1950
|
-
var skipList = Stremio.getPrefs().skipSourceList;
|
|
1951
|
-
var sl = U.el('div', 'addon-item focusable cfg-row feed-extra');
|
|
1952
|
-
sl.setAttribute('data-fk', 'skiplist'); sl.setAttribute('data-ctl', 'extra');
|
|
1953
|
-
sl.appendChild(U.el('div', 'a-name', 'Skip the source list: ' + (skipList ? 'On' : 'Off')));
|
|
1954
|
-
sl.appendChild(U.el('div', 'a-url', (skipList ? '▶ Play, OK on an episode and ▶ Play SxEx play the top source at once (hold OK on an episode › Details for the list)'
|
|
1955
|
-
: '▶ Play and OK on an episode show the sources to pick from') + ' · OK to turn ' + (skipList ? 'off' : 'on')));
|
|
1956
|
-
sl.__onselect = function () { Stremio.setPref('skipSourceList', !skipList); refeed('ranking', 'skiplist', 'extra'); };
|
|
1957
|
-
wrap.appendChild(sl);
|
|
1958
|
-
// a source that doesn't start: the next one
|
|
1959
|
-
var nextOn = Stremio.getPrefs().nextOnFail;
|
|
1960
|
-
var nx = U.el('div', 'addon-item focusable cfg-row feed-extra');
|
|
1961
|
-
nx.setAttribute('data-fk', 'nextonfail'); nx.setAttribute('data-ctl', 'extra');
|
|
1962
|
-
nx.appendChild(U.el('div', 'a-name', 'The next source if one doesn’t start: ' + (nextOn ? 'On' : 'Off')));
|
|
1963
|
-
nx.appendChild(U.el('div', 'a-url', (nextOn ? 'A source the TV refuses, or that hasn’t started after 45 s, gives way to the next best one (up to 3 more)'
|
|
1964
|
-
: 'A source that doesn’t start takes you back to the list') + ' · OK to turn ' + (nextOn ? 'off' : 'on')));
|
|
1965
|
-
nx.__onselect = function () { Stremio.setPref('nextOnFail', !nextOn); refeed('ranking', 'nextonfail', 'extra'); };
|
|
1966
|
-
wrap.appendChild(nx);
|
|
1967
|
-
// size limits: movies and series apart
|
|
1968
|
-
[['movie', 'Movies’ sizes'], ['series', 'Series’ sizes (an episode)']].forEach(function (k) { wrap.appendChild(sizeRow(k[0], k[1])); });
|
|
1969
|
-
// your words: sources with one of them at the bottom, for every title
|
|
1970
|
-
var words = Stremio.getPrefs().hideWords;
|
|
1971
|
-
var w = U.el('div', 'addon-item focusable cfg-row feed-extra');
|
|
1972
|
-
w.setAttribute('data-fk', 'words'); w.setAttribute('data-ctl', 'extra');
|
|
1973
|
-
w.appendChild(U.el('div', 'a-name', 'Hide sources with these words: ' + (words.length ? words.join(', ') : 'None')));
|
|
1974
|
-
w.appendChild(U.el('div', 'a-url', 'A source with one of them in its name, description or file name (a whole word: “CAM” isn’t in “CAMERA”) goes to the bottom, for every title · OK to change'));
|
|
1975
|
-
w.__onselect = function () {
|
|
1976
|
-
App.openEntry({ title: 'Hide sources with these words', value: words.join(', '), placeholder: 'CAM, HDTS, TELESYNC',
|
|
1977
|
-
hint: 'Words separated by commas, capitals or not. Sources with one go to the bottom and are never picked on their own. Leave it empty for none.',
|
|
1978
|
-
validate: function () { return null; },
|
|
1979
|
-
onConfirm: function (v) { App.back(); Stremio.setHideWords(v); refeed('ranking', 'words', 'extra'); } });
|
|
1980
|
-
};
|
|
1981
|
-
wrap.appendChild(w);
|
|
2043
|
+
wrap.appendChild(rankPageRow('Filters ›', filtersSummary(), 'rankfilters'));
|
|
2044
|
+
wrap.appendChild(rankPageRow('When you press Play ›', onPlaySummary(), 'rankplay'));
|
|
2045
|
+
if (_focusChild === 'rankfilters' || _focusChild === 'rankplay') { _feedFocus = { key: _focusChild, ctl: 'extra' }; _focusChild = null; } // (BACK from one: on its row)
|
|
1982
2046
|
wrap.appendChild(U.el('div', 'formats-group', 'Then, in this order'));
|
|
1983
2047
|
},
|
|
1984
2048
|
after: function (wrap) {
|
|
@@ -1997,7 +2061,94 @@
|
|
|
1997
2061
|
}, function () { wrap.appendChild(U.el('div', 'hint', 'Your addons couldn\'t be read just now.')); });
|
|
1998
2062
|
} }
|
|
1999
2063
|
};
|
|
2000
|
-
//
|
|
2064
|
+
// Source ranking's two pages (rankfilters, rankplay): a row on it that opens one, saying
|
|
2065
|
+
// what's set there.
|
|
2066
|
+
function rankPageRow(title, summary, section) {
|
|
2067
|
+
var r = U.el('div', 'addon-item focusable cfg-row feed-extra');
|
|
2068
|
+
r.setAttribute('data-fk', section); r.setAttribute('data-ctl', 'extra');
|
|
2069
|
+
r.appendChild(U.el('div', 'a-name', title));
|
|
2070
|
+
r.appendChild(U.el('div', 'a-url', summary));
|
|
2071
|
+
r.__onselect = function () { _settingsSection = section; renderSettings(); };
|
|
2072
|
+
return r;
|
|
2073
|
+
}
|
|
2074
|
+
function filtersSummary() {
|
|
2075
|
+
var P = Stremio.getPrefs(), bits = ['Sources the TV can’t play: ' + (P.hideUnplayable ? 'Hidden' : 'Shown')], sizes = [];
|
|
2076
|
+
[['movie', 'Movies'], ['series', 'Series']].forEach(function (k) { var L = P.sizeLimits[k[0]]; if (L.min || L.max || L.perHour) { sizes.push(k[1] + ' ' + sizeSummary(L)); } });
|
|
2077
|
+
bits.push(sizes.length ? sizes.join(', ') : 'No size limits');
|
|
2078
|
+
bits.push(P.hideWords.length ? 'Words: ' + P.hideWords.join(', ') : 'No words');
|
|
2079
|
+
return bits.join(' · ');
|
|
2080
|
+
}
|
|
2081
|
+
function onPlaySummary() {
|
|
2082
|
+
var P = Stremio.getPrefs();
|
|
2083
|
+
return 'Source list: ' + (P.skipSourceList ? 'skipped' : 'shown') + ' · The next source if one doesn’t start: ' + (P.nextOnFail ? 'On' : 'Off');
|
|
2084
|
+
}
|
|
2085
|
+
// A page of its own: its title, a hint, its rows; focus back on the one just changed.
|
|
2086
|
+
function rankPage(wrap, title, hint, rows) {
|
|
2087
|
+
wrap.appendChild(U.el('h2', null, 'Playback › Source ranking › ' + title));
|
|
2088
|
+
wrap.appendChild(U.el('div', 'hint feeds-hint', hint));
|
|
2089
|
+
rows.forEach(function (r) { wrap.appendChild(r); });
|
|
2090
|
+
var pref = null;
|
|
2091
|
+
if (_feedFocus) { pref = rows.filter(function (r) { return r.getAttribute('data-fk') === _feedFocus.key; })[0] || null; _feedFocus = null; }
|
|
2092
|
+
Focus.setScope(scr('settings'), pref || rows[0]);
|
|
2093
|
+
}
|
|
2094
|
+
// Filters: what's left out, or sent to the bottom.
|
|
2095
|
+
function settingsRankFilters(wrap) {
|
|
2096
|
+
rankPage(wrap, 'Filters', 'Sources these leave out, or send to the bottom of the list: never picked on their own.',
|
|
2097
|
+
[unplayableRow(), sizeRow('movie', 'Movies’ sizes'), sizeRow('series', 'Series’ sizes (an episode)'), wordsRow()]);
|
|
2098
|
+
}
|
|
2099
|
+
// When you press Play: whether the list shows, and a source that doesn't start.
|
|
2100
|
+
function settingsRankPlay(wrap) {
|
|
2101
|
+
rankPage(wrap, 'When you press Play', 'What ▶ Play does with the ranked list.', [skipListRow(), nextOnFailRow()]);
|
|
2102
|
+
}
|
|
2103
|
+
// direct links only: the sources the TV can't play left out of the list
|
|
2104
|
+
function unplayableRow() {
|
|
2105
|
+
var hideUn = Stremio.getPrefs().hideUnplayable;
|
|
2106
|
+
var un = U.el('div', 'addon-item focusable cfg-row feed-extra');
|
|
2107
|
+
un.setAttribute('data-fk', 'unplayable'); un.setAttribute('data-ctl', 'extra');
|
|
2108
|
+
un.appendChild(U.el('div', 'a-name', 'Sources the TV can’t play: ' + (hideUn ? 'Hidden' : 'Shown')));
|
|
2109
|
+
un.appendChild(U.el('div', 'a-url', (hideUn ? 'Left out (torrents, links it can’t open): direct links only; where-to-watch apps stay'
|
|
2110
|
+
: 'Listed, dimmed, at the bottom (torrents, links it can’t open)') + ' · OK to ' + (hideUn ? 'show them' : 'hide them')));
|
|
2111
|
+
un.__onselect = function () { Stremio.setPref('hideUnplayable', !hideUn); refeed('ranking', 'unplayable', 'extra'); };
|
|
2112
|
+
return un;
|
|
2113
|
+
}
|
|
2114
|
+
// skip the source list: Play plays the top source at once
|
|
2115
|
+
function skipListRow() {
|
|
2116
|
+
var skipList = Stremio.getPrefs().skipSourceList;
|
|
2117
|
+
var sl = U.el('div', 'addon-item focusable cfg-row feed-extra');
|
|
2118
|
+
sl.setAttribute('data-fk', 'skiplist'); sl.setAttribute('data-ctl', 'extra');
|
|
2119
|
+
sl.appendChild(U.el('div', 'a-name', 'Skip the source list: ' + (skipList ? 'On' : 'Off')));
|
|
2120
|
+
sl.appendChild(U.el('div', 'a-url', (skipList ? '▶ Play, OK on an episode and ▶ Play SxEx play the top source at once (hold OK on an episode › Details for the list)'
|
|
2121
|
+
: '▶ Play and OK on an episode show the sources to pick from') + ' · OK to turn ' + (skipList ? 'off' : 'on')));
|
|
2122
|
+
sl.__onselect = function () { Stremio.setPref('skipSourceList', !skipList); refeed('ranking', 'skiplist', 'extra'); };
|
|
2123
|
+
return sl;
|
|
2124
|
+
}
|
|
2125
|
+
// a source that doesn't start: the next one
|
|
2126
|
+
function nextOnFailRow() {
|
|
2127
|
+
var nextOn = Stremio.getPrefs().nextOnFail;
|
|
2128
|
+
var nx = U.el('div', 'addon-item focusable cfg-row feed-extra');
|
|
2129
|
+
nx.setAttribute('data-fk', 'nextonfail'); nx.setAttribute('data-ctl', 'extra');
|
|
2130
|
+
nx.appendChild(U.el('div', 'a-name', 'The next source if one doesn’t start: ' + (nextOn ? 'On' : 'Off')));
|
|
2131
|
+
nx.appendChild(U.el('div', 'a-url', (nextOn ? 'A source the TV refuses, or that hasn’t started after 45 s, gives way to the next best one (up to 3 more)'
|
|
2132
|
+
: 'A source that doesn’t start takes you back to the list') + ' · OK to turn ' + (nextOn ? 'off' : 'on')));
|
|
2133
|
+
nx.__onselect = function () { Stremio.setPref('nextOnFail', !nextOn); refeed('ranking', 'nextonfail', 'extra'); };
|
|
2134
|
+
return nx;
|
|
2135
|
+
}
|
|
2136
|
+
// your words: sources with one of them at the bottom, for every title
|
|
2137
|
+
function wordsRow() {
|
|
2138
|
+
var words = Stremio.getPrefs().hideWords;
|
|
2139
|
+
var w = U.el('div', 'addon-item focusable cfg-row feed-extra');
|
|
2140
|
+
w.setAttribute('data-fk', 'words'); w.setAttribute('data-ctl', 'extra');
|
|
2141
|
+
w.appendChild(U.el('div', 'a-name', 'Hide sources with these words: ' + (words.length ? words.join(', ') : 'None')));
|
|
2142
|
+
w.appendChild(U.el('div', 'a-url', 'A source with one of them in its name, description or file name (a whole word: “CAM” isn’t in “CAMERA”) goes to the bottom, for every title · OK to change'));
|
|
2143
|
+
w.__onselect = function () {
|
|
2144
|
+
App.openEntry({ title: 'Hide sources with these words', value: words.join(', '), placeholder: 'CAM, HDTS, TELESYNC',
|
|
2145
|
+
hint: 'Words separated by commas, capitals or not. Sources with one go to the bottom and are never picked on their own. Leave it empty for none.',
|
|
2146
|
+
validate: function () { return null; },
|
|
2147
|
+
onConfirm: function (v) { App.back(); Stremio.setHideWords(v); refeed('ranking', 'words', 'extra'); } });
|
|
2148
|
+
};
|
|
2149
|
+
return w;
|
|
2150
|
+
}
|
|
2151
|
+
// Size limits (Settings › Source ranking › Filters): smallest, largest and most per hour, for movies or
|
|
2001
2152
|
// series; OK on the row: which one, then its value.
|
|
2002
2153
|
var SIZE_CHOICES = {
|
|
2003
2154
|
min: { label: 'Smallest', none: 'None', values: [0.1, 0.3, 0.5, 1, 2] },
|
package/js/views.js
CHANGED
|
@@ -7,14 +7,14 @@ var Views = (function (V) {
|
|
|
7
7
|
return {
|
|
8
8
|
renderHome: V.renderHome, renderDetail: V.renderDetail, applyAppearance: V.applyAppearance,
|
|
9
9
|
renderPerson: V.renderPerson, detailSnapshot: V.detailSnapshot, restoreDetail: V.restoreDetail, lightSnapshot: V.lightSnapshot, renderSettings: V.renderSettings,
|
|
10
|
-
settingsRoot: V.settingsRoot, backInSettings: V.backInSettings,
|
|
10
|
+
settingsRoot: V.settingsRoot, backInSettings: V.backInSettings, guideBackOn: V.guideBackOn,
|
|
11
11
|
// a screen left: its downloads still running (a title page's details, Discover's
|
|
12
12
|
// pages, a search's rows) stopped
|
|
13
13
|
leaveScreen: function (name) { var f = { detail: V.leaveDetail, discover: V.leaveDiscover, search: V.leaveSearch }[name]; if (f) { f(); } }, backInLocal: V.backInLocal, setHomeTab: V.setHomeTab,
|
|
14
14
|
renderLive: V.renderLive,
|
|
15
15
|
renderSearch: V.renderSearch, searchFor: function (q) { V.searchFor(q); }, renderDiscover: V.renderDiscover, renderEntry: V.renderEntry, backInDetail: V.backInDetail,
|
|
16
16
|
homeDirty: V.homeDirty, refreshHomeIfStale: V.refreshHomeIfStale, alertNewEpisodes: V.alertNewEpisodes, previewTiles: V.previewTiles, withShowInfo: V.withShowInfo,
|
|
17
|
-
isModalOpen: V.isModalOpen, closeModal: V.closeModal, moveKey: V.moveKey, availableTabs: V.availableTabs,
|
|
17
|
+
isModalOpen: V.isModalOpen, closeModal: V.closeModal, confirm: V.confirm, moveKey: V.moveKey, availableTabs: V.availableTabs,
|
|
18
18
|
menuItems: V.menuItems, menuOrder: V.menuOrder, moveMenuItem: V.moveMenuItem
|
|
19
19
|
};
|
|
20
20
|
})(ViewParts);
|
package/js/ytplay.js
CHANGED
|
@@ -65,14 +65,15 @@ var YTPlay = (function () {
|
|
|
65
65
|
// { fix, sure, why, url, cc: [{ ch, lang }] (its closed captions), ccSure }. force: the relay
|
|
66
66
|
// at once (the channel's already known to need it). h: the channel's own User-Agent /
|
|
67
67
|
// Referer ({ ua, ref }). opts (with force): { fix: false (the sound as it is), cc: the caption
|
|
68
|
-
// channels to add as subtitle tracks }.
|
|
69
|
-
|
|
68
|
+
// channels to add as subtitle tracks }. cancel (a U.cancelToken): the look stopped, the
|
|
69
|
+
// service's downloads with it (another channel, the player closed).
|
|
70
|
+
function liveOpen(url, h, force, opts, cancel) {
|
|
70
71
|
if (MODE === 'browser') { return Promise.reject(new Error('no service')); }
|
|
71
72
|
var cc = opts && opts.cc ? opts.cc.map(function (c) { return c.ch + (c.lang ? '-' + c.lang : ''); }).join(',') : '';
|
|
72
73
|
return ensureService().then(entryAuth).then(function (a) {
|
|
73
74
|
var q = '/live/open?u=' + encodeURIComponent(url) + (h && h.ua ? '&ua=' + encodeURIComponent(h.ua) : '') + (h && h.ref ? '&ref=' + encodeURIComponent(h.ref) : '') + (force ? '&force=1' : '') +
|
|
74
75
|
(force && opts && opts.fix === false ? '&fix=0' : '') + (force && cc ? '&cc=' + encodeURIComponent(cc) : '');
|
|
75
|
-
return U.getJSON(PROXY + q + a.q, force ? 5000 : 30000, 65536, null, a.h);
|
|
76
|
+
return U.getJSON(PROXY + q + a.q, force ? 5000 : 30000, 65536, cancel || null, a.h);
|
|
76
77
|
});
|
|
77
78
|
}
|
|
78
79
|
// An HLS stream's quality list, read by the service with the stream's own User-Agent /
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "stremiok",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.2",
|
|
4
4
|
"description": "StremioK streaming client for Tizen 3.0+ Samsung TVs (TizenBrew app module).",
|
|
5
5
|
"packageType": "app",
|
|
6
6
|
"appName": "StremioK",
|
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
"MediaTrackNext",
|
|
29
29
|
"ChannelUp",
|
|
30
30
|
"ChannelDown",
|
|
31
|
+
"Guide",
|
|
31
32
|
"ColorF0Red",
|
|
32
33
|
"ColorF1Green",
|
|
33
34
|
"ColorF2Yellow",
|
package/service/index.js
CHANGED
|
@@ -1589,6 +1589,29 @@ function openPart(fs, part, append, cb) {
|
|
|
1589
1589
|
});
|
|
1590
1590
|
});
|
|
1591
1591
|
}
|
|
1592
|
+
// A partial download's version tag (ETag / Last-Modified), for resuming it after a restart: kept
|
|
1593
|
+
// in StremioK's own folder by the partial file's path (DL_VALIDATORS at most, the oldest dropped),
|
|
1594
|
+
// never on the drive, where a prepared file could be a link elsewhere (read: its contents sent
|
|
1595
|
+
// as If-Range; written: overwritten). None to keep it in (TizenBrew): downloads are closed there.
|
|
1596
|
+
var DL_VALIDATORS = 64;
|
|
1597
|
+
function dlValFile() { var d = tokenDir(); return d ? d + '/dl-validators.json' : null; }
|
|
1598
|
+
function dlValAll() {
|
|
1599
|
+
var f = dlValFile(), o = null;
|
|
1600
|
+
if (!f) { return {}; }
|
|
1601
|
+
try { o = JSON.parse(require('fs').readFileSync(f, 'utf8')); } catch (e) { o = null; }
|
|
1602
|
+
return o && typeof o === 'object' && !Array.isArray(o) ? o : {};
|
|
1603
|
+
}
|
|
1604
|
+
function dlValGet(part) { var v = dlValAll()[part]; return typeof v === 'string' ? v.slice(0, 300) : ''; }
|
|
1605
|
+
function dlValSet(part, v) {
|
|
1606
|
+
var f = dlValFile();
|
|
1607
|
+
if (!f) { return; }
|
|
1608
|
+
var all = dlValAll();
|
|
1609
|
+
delete all[part];
|
|
1610
|
+
if (v) { all[part] = String(v).slice(0, 300); }
|
|
1611
|
+
var keys = Object.keys(all);
|
|
1612
|
+
while (keys.length > DL_VALIDATORS) { delete all[keys.shift()]; }
|
|
1613
|
+
try { require('fs').writeFileSync(f, JSON.stringify(all), { mode: 384 }); } catch (e) { log('download version not kept: ' + (e && (e.code || e.message))); }
|
|
1614
|
+
}
|
|
1592
1615
|
function dlRun(e) {
|
|
1593
1616
|
var fs = require('fs'), part = e.dir + '/' + e.name + '.part';
|
|
1594
1617
|
e.state = 'downloading'; e.err = '';
|
|
@@ -1601,17 +1624,17 @@ function dlRun(e) {
|
|
|
1601
1624
|
fs.mkdir(e.dir, function () {
|
|
1602
1625
|
fsRealOk(e.dir, function (bad) {
|
|
1603
1626
|
if (bad) { dlEnd(e, 'failed', 'the folder: ' + bad.message); return; }
|
|
1604
|
-
fs.
|
|
1627
|
+
fs.lstat(part, function (se, st) { // (not through a link: a partial file is a regular one, see openPart)
|
|
1628
|
+
if (!se && !st.isFile()) { dlEnd(e, 'failed', 'the partial file isn\'t a regular file'); return; }
|
|
1605
1629
|
var have = se ? 0 : st.size;
|
|
1606
1630
|
if (!have || e.answered) { get(e.url, 0, have); return; } // (this one's own, from this run: picked up as it was)
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
if (e.validator) { get(e.url, 0, have); } else { dropPart(function () { get(e.url, 0, 0); }); }
|
|
1610
|
-
});
|
|
1631
|
+
e.validator = dlValGet(part); // (a partial file from before a restart: resumed only with its version kept)
|
|
1632
|
+
if (e.validator) { get(e.url, 0, have); } else { dropPart(function () { get(e.url, 0, 0); }); }
|
|
1611
1633
|
});
|
|
1612
1634
|
});
|
|
1613
1635
|
});
|
|
1614
|
-
|
|
1636
|
+
// (….part.v: where 2.1.17–2.2.1 kept the version, removed; a link removed, not what it points to)
|
|
1637
|
+
function dropPart(then) { dlValSet(part, ''); fs.unlink(part + '.v', function () { fs.unlink(part, function () { then(); }); }); }
|
|
1615
1638
|
function get(u, hops, have) {
|
|
1616
1639
|
if (e.state !== 'downloading') { return; }
|
|
1617
1640
|
var pu = urllib.parse(u), mod = pu.protocol === 'https:' ? https : http;
|
|
@@ -1647,7 +1670,7 @@ function dlRun(e) {
|
|
|
1647
1670
|
if (!resumed) { // (asked again on a resume: If-Range; kept beside the partial file, for one after a restart)
|
|
1648
1671
|
var et = resp.headers.etag;
|
|
1649
1672
|
e.validator = et && !/^W\//.test(et) ? et : (resp.headers['last-modified'] || '');
|
|
1650
|
-
|
|
1673
|
+
dlValSet(part, e.validator);
|
|
1651
1674
|
}
|
|
1652
1675
|
if (isPlaylistAnswer(resp.headers['content-type'], '')) { resp.resume(); closed = true; dlEnd(e, 'failed', 'a streamed playlist (HLS or DASH), not a file: it can\'t be downloaded'); return; }
|
|
1653
1676
|
var total = 0, cr = /\/(\d+)\s*$/.exec(resp.headers['content-range'] || '');
|
|
@@ -1715,7 +1738,7 @@ function dlRun(e) {
|
|
|
1715
1738
|
fs.rename(part, final, function (re) {
|
|
1716
1739
|
if (re) { dlEnd(e, 'failed', 'couldn\'t finish the file: ' + (re.code || re.message)); return; }
|
|
1717
1740
|
e.name = final.split('/').pop(); e.tries = 0;
|
|
1718
|
-
fs.unlink(part + '.v', function () {});
|
|
1741
|
+
dlValSet(part, ''); fs.unlink(part + '.v', function () {});
|
|
1719
1742
|
dlEnd(e, 'done');
|
|
1720
1743
|
});
|
|
1721
1744
|
});
|
|
@@ -3057,7 +3080,8 @@ function epgControl(req, res, path, query) {
|
|
|
3057
3080
|
var ENTRY_PORT = PORT + 10, ENTRY_MS = 5 * 60 * 1000, ENTRY_IDLE_MS = 30000, ENTRY_MAX = 8192;
|
|
3058
3081
|
var ENTRY_OPEN_MAX = 2, ENTRY_OPENS = 12, ENTRY_CONNECTIONS = 8, ENTRY_VISIT_MS = 20000, ENTRY_QUIET_MS = 10000;
|
|
3059
3082
|
var ENTRY_TITLES = { link: 'Play a link on StremioK', addon: 'Add an addon to StremioK', playlist: 'Add an IPTV playlist to StremioK', config: 'Import a configuration file into StremioK',
|
|
3060
|
-
search: 'Search on StremioK', youtube: 'Add a YouTube catalog to StremioK', aiom: 'Your AIOManager address for StremioK', aiomkey: 'Your AIOManager API key for StremioK'
|
|
3083
|
+
search: 'Search on StremioK', youtube: 'Add a YouTube catalog to StremioK', aiom: 'Your AIOManager address for StremioK', aiomkey: 'Your AIOManager API key for StremioK',
|
|
3084
|
+
server: 'Your streaming server’s address for StremioK' };
|
|
3061
3085
|
var ENTRY_TEXT = { search: 'Words to search for', youtube: 'A channel, a playlist link, or words to search YouTube for', aiomkey: 'Your account API key' }; // (plain text, not a link)
|
|
3062
3086
|
var _entries = Object.create(null), _entryServer = null, _entrySockets = [], _entryOpened = [];
|
|
3063
3087
|
function lanAddress() {
|