nuvio-tizen 1.8.4 → 1.8.9
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/css/style.css +14 -3
- package/index.html +9 -9
- package/js/focus.js +30 -3
- package/js/stremio.js +65 -0
- package/js/views.js +81 -16
- package/package.json +1 -1
package/css/style.css
CHANGED
|
@@ -36,6 +36,8 @@ html, body {
|
|
|
36
36
|
.brand .dot { color: #e6e9ef; }
|
|
37
37
|
.header .spacer { flex: 1; }
|
|
38
38
|
.header .gear { font-size: 30px; opacity: 0.7; }
|
|
39
|
+
.header .hchip { font-size: 24px; opacity: 0.9; padding: 10px 24px; border-radius: 30px; background: #1a1f2b; border: 4px solid transparent; }
|
|
40
|
+
.header .hchip.focusable.focused { background: #818cf8; color: #0e1117; border-color: #fff; opacity: 1; }
|
|
39
41
|
|
|
40
42
|
/* --- Rows --- */
|
|
41
43
|
.rows { position: absolute; top: 110px; left: 0; right: 0; bottom: 0; overflow: hidden; }
|
|
@@ -104,13 +106,22 @@ html, body {
|
|
|
104
106
|
.ep-row { display: flex; align-items: flex-start; padding: 12px 16px; }
|
|
105
107
|
.ep-thumb { width: 120px; height: 68px; flex: 0 0 120px; margin-right: 18px; border-radius: 6px; background-color: #0e1117; background-size: cover; background-position: center; }
|
|
106
108
|
.ep-body { flex: 1; min-width: 0; }
|
|
107
|
-
.ep-line { font-size: 22px; }
|
|
108
|
-
.ep-
|
|
109
|
+
.ep-line { display: flex; align-items: flex-start; font-size: 22px; }
|
|
110
|
+
.ep-title { flex: 1 1 auto; min-width: 0; }
|
|
111
|
+
.ep-rating { flex: 0 0 auto; margin-left: 14px; color: #ffd257; font-size: 19px; white-space: nowrap; }
|
|
112
|
+
.ep-rating:empty { margin-left: 0; }
|
|
109
113
|
.ep-ov { display: block; font-size: 17px; color: #9aa2b1; margin-top: 6px; max-height: 44px; overflow: hidden; }
|
|
110
114
|
.list-scroll { position: absolute; top: 0; left: 0; right: 0; bottom: 0; overflow: hidden; }
|
|
111
115
|
|
|
112
116
|
/* Settings */
|
|
113
|
-
.settings-wrap { position: absolute; top: 120px; left: 60px; right: 60px; }
|
|
117
|
+
.settings-wrap { position: absolute; top: 120px; left: 60px; right: 60px; bottom: 40px; overflow: hidden; }
|
|
118
|
+
.back-row { color: #c7cbd4; }
|
|
119
|
+
/* Home Feeds ordering */
|
|
120
|
+
.feed-row { display: flex; align-items: center; margin-bottom: 8px; }
|
|
121
|
+
.feed-btn { width: 60px; text-align: center; padding: 14px 0; margin-right: 8px; background: #161b26; border-radius: 8px; font-size: 22px; border: 4px solid transparent; }
|
|
122
|
+
.feed-name { flex: 1; padding: 14px 18px; background: #161b26; border-radius: 8px; font-size: 22px; border: 4px solid transparent; white-space: normal; }
|
|
123
|
+
.feed-off .feed-name { opacity: 0.5; }
|
|
124
|
+
.feed-btn.focusable.focused, .feed-name.focusable.focused { background: #818cf8; color: #0e1117; border-color: #fff; }
|
|
114
125
|
.settings-wrap h2 { font-size: 30px; margin-bottom: 20px; }
|
|
115
126
|
.addon-item { padding: 16px 20px; margin-bottom: 10px; background: #161b26; border-radius: 8px; font-size: 20px; border: 4px solid transparent; word-break: break-all; white-space: normal; }
|
|
116
127
|
.addon-item .a-name { font-weight: bold; }
|
package/index.html
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
<meta charset="utf-8">
|
|
5
5
|
<meta name="viewport" content="width=1920, height=1080, user-scalable=no">
|
|
6
6
|
<title>Nuvio</title>
|
|
7
|
-
<link rel="stylesheet" href="css/style.css?v=1.8.
|
|
7
|
+
<link rel="stylesheet" href="css/style.css?v=1.8.9">
|
|
8
8
|
</head>
|
|
9
9
|
<body>
|
|
10
10
|
<!-- CSS-applied sentinel (kept off-screen); app.js waits for its width before rendering -->
|
|
@@ -47,13 +47,13 @@
|
|
|
47
47
|
|
|
48
48
|
<!-- Load order matters: polyfills -> util -> data -> input -> player -> views -> app -->
|
|
49
49
|
<!-- ?v= busts the TV webview cache on every release (keep in sync with package.json) -->
|
|
50
|
-
<script src="js/polyfills.js?v=1.8.
|
|
51
|
-
<script src="js/util.js?v=1.8.
|
|
52
|
-
<script src="js/stremio.js?v=1.8.
|
|
53
|
-
<script src="js/keys.js?v=1.8.
|
|
54
|
-
<script src="js/focus.js?v=1.8.
|
|
55
|
-
<script src="js/player.js?v=1.8.
|
|
56
|
-
<script src="js/views.js?v=1.8.
|
|
57
|
-
<script src="js/app.js?v=1.8.
|
|
50
|
+
<script src="js/polyfills.js?v=1.8.9"></script>
|
|
51
|
+
<script src="js/util.js?v=1.8.9"></script>
|
|
52
|
+
<script src="js/stremio.js?v=1.8.9"></script>
|
|
53
|
+
<script src="js/keys.js?v=1.8.9"></script>
|
|
54
|
+
<script src="js/focus.js?v=1.8.9"></script>
|
|
55
|
+
<script src="js/player.js?v=1.8.9"></script>
|
|
56
|
+
<script src="js/views.js?v=1.8.9"></script>
|
|
57
|
+
<script src="js/app.js?v=1.8.9"></script>
|
|
58
58
|
</body>
|
|
59
59
|
</html>
|
package/js/focus.js
CHANGED
|
@@ -20,6 +20,16 @@ var Focus = (function () {
|
|
|
20
20
|
|
|
21
21
|
function setFocus(node) {
|
|
22
22
|
if (!node) { return; }
|
|
23
|
+
// Moving to a non-input control must blur any text field that still holds
|
|
24
|
+
// DOM keyboard focus — otherwise the remote's OK/Enter is delivered to the
|
|
25
|
+
// input (e.g. re-running a search) instead of the visually-focused element.
|
|
26
|
+
try {
|
|
27
|
+
var ae = document.activeElement;
|
|
28
|
+
if (ae && ae !== node && (ae.tagName === 'INPUT' || ae.tagName === 'TEXTAREA') &&
|
|
29
|
+
node.tagName !== 'INPUT' && node.tagName !== 'TEXTAREA') {
|
|
30
|
+
ae.blur();
|
|
31
|
+
}
|
|
32
|
+
} catch (e) {}
|
|
23
33
|
if (_current && _current !== node && _current.classList) { _current.classList.remove('focused'); }
|
|
24
34
|
_current = node;
|
|
25
35
|
if (node.classList) { node.classList.add('focused'); }
|
|
@@ -56,8 +66,10 @@ var Focus = (function () {
|
|
|
56
66
|
|
|
57
67
|
var r = _current.getBoundingClientRect();
|
|
58
68
|
var cx = r.left + r.width / 2, cy = r.top + r.height / 2;
|
|
59
|
-
var best = null, bestScore = Infinity;
|
|
60
69
|
|
|
70
|
+
// Collect candidates in the pressed direction with their primary (distance
|
|
71
|
+
// along the axis of travel) and cross (offset on the other axis).
|
|
72
|
+
var cands = [];
|
|
61
73
|
for (var i = 0; i < list.length; i++) {
|
|
62
74
|
var node = list[i];
|
|
63
75
|
if (node === _current) { continue; }
|
|
@@ -69,8 +81,23 @@ var Focus = (function () {
|
|
|
69
81
|
else if (dir === 'RIGHT') { if (dx < 1) { continue; } primary = dx; cross = Math.abs(dy); }
|
|
70
82
|
else if (dir === 'UP') { if (dy > -1) { continue; } primary = -dy; cross = Math.abs(dx); }
|
|
71
83
|
else { if (dy < 1) { continue; } primary = dy; cross = Math.abs(dx); }
|
|
72
|
-
|
|
73
|
-
|
|
84
|
+
cands.push({ node: node, primary: primary, cross: cross });
|
|
85
|
+
}
|
|
86
|
+
if (!cands.length) { return; }
|
|
87
|
+
|
|
88
|
+
// Two-phase: land in the NEAREST row/column first (so vertical moves never
|
|
89
|
+
// skip a row just because a farther element is better horizontally aligned),
|
|
90
|
+
// then pick the closest within that band.
|
|
91
|
+
var minP = Infinity;
|
|
92
|
+
for (var j = 0; j < cands.length; j++) { if (cands[j].primary < minP) { minP = cands[j].primary; } }
|
|
93
|
+
var BAND = 120;
|
|
94
|
+
var best = null, bestCross = Infinity, bestP = Infinity;
|
|
95
|
+
for (var k = 0; k < cands.length; k++) {
|
|
96
|
+
var c = cands[k];
|
|
97
|
+
if (c.primary > minP + BAND) { continue; }
|
|
98
|
+
if (c.cross < bestCross || (c.cross === bestCross && c.primary < bestP)) {
|
|
99
|
+
best = c.node; bestCross = c.cross; bestP = c.primary;
|
|
100
|
+
}
|
|
74
101
|
}
|
|
75
102
|
if (best) { setFocus(best); }
|
|
76
103
|
}
|
package/js/stremio.js
CHANGED
|
@@ -178,6 +178,69 @@ var Stremio = (function () {
|
|
|
178
178
|
.then(function (res) { return (res && res.metas) ? res.metas : []; });
|
|
179
179
|
}
|
|
180
180
|
|
|
181
|
+
// ---- Home feed ordering / visibility ----
|
|
182
|
+
var FEEDS_KEY = 'nuvio.feeds';
|
|
183
|
+
function catalogKey(cat) {
|
|
184
|
+
var aid = (cat.addon.manifest && cat.addon.manifest.id) || cat.addon.url;
|
|
185
|
+
return cat.type + '|' + cat.id + '|' + aid;
|
|
186
|
+
}
|
|
187
|
+
function getFeedCfg() {
|
|
188
|
+
var f = U.store.get(FEEDS_KEY, {}) || {};
|
|
189
|
+
return { order: f.order || [], hidden: f.hidden || [] };
|
|
190
|
+
}
|
|
191
|
+
function setFeedCfg(cfg) { U.store.set(FEEDS_KEY, cfg); }
|
|
192
|
+
|
|
193
|
+
function sortCatalogsByPref(cats) {
|
|
194
|
+
var order = getFeedCfg().order;
|
|
195
|
+
var pos = {};
|
|
196
|
+
order.forEach(function (k, i) { pos[k] = i; });
|
|
197
|
+
var withIdx = cats.map(function (c, i) { return { c: c, i: i, k: catalogKey(c) }; });
|
|
198
|
+
withIdx.sort(function (a, b) {
|
|
199
|
+
var pa = (pos[a.k] !== undefined) ? pos[a.k] : (100000 + a.i);
|
|
200
|
+
var pb = (pos[b.k] !== undefined) ? pos[b.k] : (100000 + b.i);
|
|
201
|
+
return pa - pb;
|
|
202
|
+
});
|
|
203
|
+
return withIdx.map(function (x) { return x.c; });
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// All catalogs in the user's order (for the ordering settings page).
|
|
207
|
+
function listCatalogsOrdered() {
|
|
208
|
+
return listCatalogs().then(function (cats) { return sortCatalogsByPref(cats); });
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Ordered + visible catalogs (for the home page).
|
|
212
|
+
function catalogsForHome() {
|
|
213
|
+
return listCatalogs().then(function (cats) {
|
|
214
|
+
var hidden = {};
|
|
215
|
+
getFeedCfg().hidden.forEach(function (k) { hidden[k] = 1; });
|
|
216
|
+
return sortCatalogsByPref(cats).filter(function (c) { return !hidden[catalogKey(c)]; });
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function moveFeed(key, dir) {
|
|
221
|
+
return listCatalogs().then(function (cats) {
|
|
222
|
+
var ordered = sortCatalogsByPref(cats).map(catalogKey);
|
|
223
|
+
var i = ordered.indexOf(key);
|
|
224
|
+
if (i < 0) { return; }
|
|
225
|
+
var j = i + dir;
|
|
226
|
+
if (j < 0 || j >= ordered.length) { return; }
|
|
227
|
+
var t = ordered[i]; ordered[i] = ordered[j]; ordered[j] = t;
|
|
228
|
+
var cfg = getFeedCfg(); cfg.order = ordered; setFeedCfg(cfg);
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
function toggleFeed(key) {
|
|
233
|
+
var cfg = getFeedCfg();
|
|
234
|
+
var h = {};
|
|
235
|
+
cfg.hidden.forEach(function (k) { h[k] = 1; });
|
|
236
|
+
if (h[key]) { delete h[key]; } else { h[key] = 1; }
|
|
237
|
+
cfg.hidden = Object.keys(h);
|
|
238
|
+
setFeedCfg(cfg);
|
|
239
|
+
}
|
|
240
|
+
function isFeedHidden(key) {
|
|
241
|
+
return getFeedCfg().hidden.indexOf(key) !== -1;
|
|
242
|
+
}
|
|
243
|
+
|
|
181
244
|
// ---- Meta ----
|
|
182
245
|
function getMeta(type, id) {
|
|
183
246
|
return loadAddons().then(function (addons) {
|
|
@@ -450,6 +513,8 @@ var Stremio = (function () {
|
|
|
450
513
|
tmdbFindTvId: tmdbFindTvId, tmdbSeasonEpisodes: tmdbSeasonEpisodes, tmdbImg: tmdbImg,
|
|
451
514
|
omdbSeasonRatings: omdbSeasonRatings,
|
|
452
515
|
loadAddons: loadAddons, listCatalogs: listCatalogs, getCatalog: getCatalog,
|
|
516
|
+
catalogsForHome: catalogsForHome, listCatalogsOrdered: listCatalogsOrdered,
|
|
517
|
+
catalogKey: catalogKey, moveFeed: moveFeed, toggleFeed: toggleFeed, isFeedHidden: isFeedHidden,
|
|
453
518
|
getMeta: getMeta, getStreams: getStreams, getSubtitles: getSubtitles,
|
|
454
519
|
getSearchCatalogs: getSearchCatalogs, search: search,
|
|
455
520
|
isPlayable: isPlayable, streamLabel: streamLabel, streamName: streamName,
|
package/js/views.js
CHANGED
|
@@ -59,14 +59,14 @@ var Views = (function () {
|
|
|
59
59
|
h.appendChild(brand);
|
|
60
60
|
h.appendChild(U.el('div', 'spacer'));
|
|
61
61
|
if (withSearch) {
|
|
62
|
-
var srch = U.el('div', 'gear focusable', '🔍');
|
|
63
|
-
srch.style.marginRight = '
|
|
62
|
+
var srch = U.el('div', 'gear hchip focusable', 'Search 🔍');
|
|
63
|
+
srch.style.marginRight = '20px';
|
|
64
64
|
srch.__onselect = function () { App.openSearch(); };
|
|
65
65
|
srch.__navDOWN = focusFirstRowItem;
|
|
66
66
|
h.appendChild(srch);
|
|
67
67
|
}
|
|
68
68
|
if (withGear) {
|
|
69
|
-
var g = U.el('div', 'gear focusable', '⚙');
|
|
69
|
+
var g = U.el('div', 'gear hchip focusable', 'Settings ⚙');
|
|
70
70
|
g.__onselect = function () { App.openSettings(); };
|
|
71
71
|
g.__navDOWN = focusFirstRowItem;
|
|
72
72
|
h.appendChild(g);
|
|
@@ -163,8 +163,8 @@ var Views = (function () {
|
|
|
163
163
|
}
|
|
164
164
|
|
|
165
165
|
U.spinner(true);
|
|
166
|
-
Stremio.
|
|
167
|
-
var pick = cats.slice(0,
|
|
166
|
+
Stremio.catalogsForHome().then(function (cats) {
|
|
167
|
+
var pick = cats.slice(0, 15);
|
|
168
168
|
var rowNodes = pick.map(function (cat) { var ph = buildRow(cat.name, []); rows.appendChild(ph); return ph; });
|
|
169
169
|
focusHome(s);
|
|
170
170
|
U.spinner(false);
|
|
@@ -282,6 +282,7 @@ var Views = (function () {
|
|
|
282
282
|
}
|
|
283
283
|
Focus.setScope(s, _d._epFocus);
|
|
284
284
|
_d.target = null; // consume: don't re-jump after the user navigates
|
|
285
|
+
_d._focusSeason = null;
|
|
285
286
|
}
|
|
286
287
|
|
|
287
288
|
function movieActions() {
|
|
@@ -310,7 +311,9 @@ var Views = (function () {
|
|
|
310
311
|
var bar = U.el('div', 'season-bar');
|
|
311
312
|
ss.forEach(function (sn) {
|
|
312
313
|
var p = U.el('div', 'pill focusable' + (sn === _d.season ? ' season-sel' : ''), 'Season ' + sn);
|
|
313
|
-
p.__onselect = function () { _d.season = sn; drawDetail(); };
|
|
314
|
+
p.__onselect = function () { _d.season = sn; _d._focusSeason = sn; drawDetail(); };
|
|
315
|
+
// keep focus on the season pill the user just picked
|
|
316
|
+
if (_d._focusSeason === sn) { _d._epFocus = p; }
|
|
314
317
|
bar.appendChild(p);
|
|
315
318
|
});
|
|
316
319
|
panel.appendChild(bar);
|
|
@@ -332,8 +335,9 @@ var Views = (function () {
|
|
|
332
335
|
|
|
333
336
|
var body = U.el('div', 'ep-body');
|
|
334
337
|
var line = U.el('div', 'ep-line');
|
|
335
|
-
|
|
338
|
+
var title = U.el('span', 'ep-title', (watched ? '✓ ' : '') + 'E' + (v.episode || '?') + ' ' + (v.title || v.name || ''));
|
|
336
339
|
var rating = U.el('span', 'ep-rating', '');
|
|
340
|
+
line.appendChild(title);
|
|
337
341
|
line.appendChild(rating);
|
|
338
342
|
body.appendChild(line);
|
|
339
343
|
var ov = U.el('span', 'ep-ov', v.overview || '');
|
|
@@ -366,7 +370,7 @@ var Views = (function () {
|
|
|
366
370
|
if (!map || _d.season !== seasonAtFetch) { return; }
|
|
367
371
|
epRefs.forEach(function (r) {
|
|
368
372
|
var rt = map[r.num];
|
|
369
|
-
if (rt) { r.rating.textContent = '
|
|
373
|
+
if (rt) { r.rating.textContent = '★ ' + rt + ' IMDb'; }
|
|
370
374
|
});
|
|
371
375
|
});
|
|
372
376
|
}
|
|
@@ -379,8 +383,9 @@ var Views = (function () {
|
|
|
379
383
|
var ep = map[r.num];
|
|
380
384
|
if (!ep) { return; }
|
|
381
385
|
if (ep.still && !r.thumb.style.backgroundImage) { r.thumb.style.backgroundImage = 'url("' + ep.still + '")'; }
|
|
382
|
-
//
|
|
383
|
-
|
|
386
|
+
// Fill the rating only if OMDb didn't provide one for this episode
|
|
387
|
+
// (OMDb's dataset is missing IMDb ratings for some episodes).
|
|
388
|
+
if (ep.rating && !r.rating.textContent) { r.rating.textContent = '★ ' + (Math.round(ep.rating * 10) / 10) + ' TMDb'; }
|
|
384
389
|
if (ep.overview && !r.ov.textContent) { r.ov.textContent = ep.overview; }
|
|
385
390
|
});
|
|
386
391
|
});
|
|
@@ -555,6 +560,10 @@ var Views = (function () {
|
|
|
555
560
|
var go = U.el('div', 'pill focusable search-go', 'Search');
|
|
556
561
|
go.__onselect = function () { runSearch(input.value); };
|
|
557
562
|
bar.appendChild(go);
|
|
563
|
+
|
|
564
|
+
var back = U.el('div', 'pill focusable search-go', '← Back');
|
|
565
|
+
back.__onselect = function () { App.back(); };
|
|
566
|
+
bar.appendChild(back);
|
|
558
567
|
wrap.appendChild(bar);
|
|
559
568
|
|
|
560
569
|
var results = U.el('div', 'search-results');
|
|
@@ -701,6 +710,7 @@ var Views = (function () {
|
|
|
701
710
|
if (_settingsSection === 'addons') { settingsAddons(wrap); }
|
|
702
711
|
else if (_settingsSection === 'integrations') { settingsIntegrations(wrap); }
|
|
703
712
|
else if (_settingsSection === 'subtitles') { settingsSubtitles(wrap); }
|
|
713
|
+
else if (_settingsSection === 'feeds') { settingsFeeds(wrap); }
|
|
704
714
|
else if (_settingsSection === 'display') { settingsDisplay(wrap); }
|
|
705
715
|
else { settingsMenu(wrap); }
|
|
706
716
|
}
|
|
@@ -713,13 +723,20 @@ var Views = (function () {
|
|
|
713
723
|
return r;
|
|
714
724
|
}
|
|
715
725
|
|
|
726
|
+
function backRow() {
|
|
727
|
+
var r = U.el('div', 'addon-item focusable back-row', '← Back');
|
|
728
|
+
r.__onselect = function () { App.back(); };
|
|
729
|
+
return r;
|
|
730
|
+
}
|
|
731
|
+
|
|
716
732
|
function settingsMenu(wrap) {
|
|
717
733
|
wrap.appendChild(U.el('h2', null, 'Settings'));
|
|
718
734
|
wrap.appendChild(sectionRow('Addons', 'Catalog, stream & subtitle addons', 'addons'));
|
|
719
|
-
wrap.appendChild(sectionRow('Integrations', 'API keys (TMDB, MDBList)', 'integrations'));
|
|
735
|
+
wrap.appendChild(sectionRow('Integrations', 'API keys (OMDb, TMDB, MDBList)', 'integrations'));
|
|
720
736
|
wrap.appendChild(sectionRow('Subtitle Options', 'Default language, size, style', 'subtitles'));
|
|
737
|
+
wrap.appendChild(sectionRow('Home Feeds', 'Order & show/hide the home rows', 'feeds'));
|
|
721
738
|
wrap.appendChild(sectionRow('Display', 'Poster orientation', 'display'));
|
|
722
|
-
wrap.appendChild(
|
|
739
|
+
wrap.appendChild(backRow());
|
|
723
740
|
Focus.setScope(scr('settings'));
|
|
724
741
|
}
|
|
725
742
|
|
|
@@ -772,7 +789,8 @@ var Views = (function () {
|
|
|
772
789
|
wrap.appendChild(addRow);
|
|
773
790
|
|
|
774
791
|
wrap.appendChild(U.el('div', 'hint',
|
|
775
|
-
'Nuvio hosts no content — add Stremio addon manifest URLs for catalogs, streams and subtitles.
|
|
792
|
+
'Nuvio hosts no content — add Stremio addon manifest URLs for catalogs, streams and subtitles.'));
|
|
793
|
+
wrap.appendChild(backRow());
|
|
776
794
|
Focus.setScope(scr('settings'));
|
|
777
795
|
});
|
|
778
796
|
}
|
|
@@ -800,7 +818,8 @@ var Views = (function () {
|
|
|
800
818
|
wrap.appendChild(keyRow('OMDb API key', 'omdb', 'OMDb API key', Stremio.omdbValidate));
|
|
801
819
|
wrap.appendChild(keyRow('TMDB API key (v3)', 'tmdb', 'TMDB v3 API key', Stremio.tmdbValidate));
|
|
802
820
|
wrap.appendChild(keyRow('MDBList API key', 'mdblist', 'MDBList API key', Stremio.mdblistValidate));
|
|
803
|
-
wrap.appendChild(U.el('div', 'hint', 'Keys are stored on this TV only. OMDb gives real IMDb per-episode ratings (used first when set); TMDB adds episode images & ratings.
|
|
821
|
+
wrap.appendChild(U.el('div', 'hint', 'Keys are stored on this TV only. OMDb gives real IMDb per-episode ratings (used first when set); TMDB adds episode images & ratings.'));
|
|
822
|
+
wrap.appendChild(backRow());
|
|
804
823
|
Focus.setScope(scr('settings'));
|
|
805
824
|
}
|
|
806
825
|
|
|
@@ -809,7 +828,7 @@ var Views = (function () {
|
|
|
809
828
|
wrap.appendChild(subCycleRow('Default language', SUB_LANGS, 'lang'));
|
|
810
829
|
wrap.appendChild(subCycleRow('Size', SUB_SIZES, 'size'));
|
|
811
830
|
wrap.appendChild(subCycleRow('Style', SUB_STYLES, 'style'));
|
|
812
|
-
wrap.appendChild(
|
|
831
|
+
wrap.appendChild(backRow());
|
|
813
832
|
Focus.setScope(scr('settings'));
|
|
814
833
|
}
|
|
815
834
|
|
|
@@ -828,10 +847,56 @@ var Views = (function () {
|
|
|
828
847
|
render();
|
|
829
848
|
};
|
|
830
849
|
wrap.appendChild(row);
|
|
831
|
-
wrap.appendChild(U.el('div', 'hint', 'Landscape uses wide artwork when available (falls back to the poster).
|
|
850
|
+
wrap.appendChild(U.el('div', 'hint', 'Landscape uses wide artwork when available (falls back to the poster).'));
|
|
851
|
+
wrap.appendChild(backRow());
|
|
832
852
|
Focus.setScope(scr('settings'));
|
|
833
853
|
}
|
|
834
854
|
|
|
855
|
+
// ----- Home Feeds ordering -----
|
|
856
|
+
var _feedFocus = null;
|
|
857
|
+
function refeed(key, ctl) { _feedFocus = { key: key, ctl: ctl }; markHomeDirty(); clearCatalogCache(); renderSettings(); }
|
|
858
|
+
|
|
859
|
+
function settingsFeeds(wrap) {
|
|
860
|
+
wrap.appendChild(U.el('h2', null, 'Home Feeds'));
|
|
861
|
+
wrap.appendChild(U.el('div', 'hint', '▲/▼ reorder a feed · OK on the name shows/hides it.'));
|
|
862
|
+
Stremio.listCatalogsOrdered().then(function (cats) {
|
|
863
|
+
cats.forEach(function (cat) {
|
|
864
|
+
var key = Stremio.catalogKey(cat);
|
|
865
|
+
var hidden = Stremio.isFeedHidden(key);
|
|
866
|
+
var frow = U.el('div', 'feed-row' + (hidden ? ' feed-off' : ''));
|
|
867
|
+
|
|
868
|
+
var up = U.el('div', 'feed-btn focusable', '▲');
|
|
869
|
+
up.setAttribute('data-fk', key); up.setAttribute('data-ctl', 'up');
|
|
870
|
+
up.__onselect = function () { Stremio.moveFeed(key, -1).then(function () { refeed(key, 'up'); }); };
|
|
871
|
+
|
|
872
|
+
var down = U.el('div', 'feed-btn focusable', '▼');
|
|
873
|
+
down.setAttribute('data-fk', key); down.setAttribute('data-ctl', 'down');
|
|
874
|
+
down.__onselect = function () { Stremio.moveFeed(key, 1).then(function () { refeed(key, 'down'); }); };
|
|
875
|
+
|
|
876
|
+
var name = U.el('div', 'feed-name focusable', cat.name + (hidden ? ' (hidden)' : ''));
|
|
877
|
+
name.setAttribute('data-fk', key); name.setAttribute('data-ctl', 'name');
|
|
878
|
+
name.__onselect = function () { Stremio.toggleFeed(key); refeed(key, 'name'); };
|
|
879
|
+
|
|
880
|
+
frow.appendChild(up);
|
|
881
|
+
frow.appendChild(down);
|
|
882
|
+
frow.appendChild(name);
|
|
883
|
+
wrap.appendChild(frow);
|
|
884
|
+
});
|
|
885
|
+
wrap.appendChild(backRow());
|
|
886
|
+
|
|
887
|
+
// restore focus to the control that triggered the last change
|
|
888
|
+
var pref = null;
|
|
889
|
+
if (_feedFocus) {
|
|
890
|
+
var nodes = wrap.querySelectorAll('.feed-btn, .feed-name');
|
|
891
|
+
for (var i = 0; i < nodes.length; i++) {
|
|
892
|
+
if (nodes[i].getAttribute('data-fk') === _feedFocus.key && nodes[i].getAttribute('data-ctl') === _feedFocus.ctl) { pref = nodes[i]; break; }
|
|
893
|
+
}
|
|
894
|
+
_feedFocus = null;
|
|
895
|
+
}
|
|
896
|
+
Focus.setScope(scr('settings'), pref);
|
|
897
|
+
});
|
|
898
|
+
}
|
|
899
|
+
|
|
835
900
|
return {
|
|
836
901
|
renderHome: renderHome, renderDetail: renderDetail, renderSettings: renderSettings,
|
|
837
902
|
settingsRoot: settingsRoot, backInSettings: backInSettings,
|