stremiok 2.1.0 → 2.2.0

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/js/ytplay.js CHANGED
@@ -62,12 +62,16 @@ var YTPlay = (function () {
62
62
  }
63
63
  // A live HLS channel whose sound the TV's player stutters on (its server cuts the AAC sound
64
64
  // mid-frame): the service looks at it and, if so, gives a relay that repacks the sound:
65
- // { fix, sure, why, url }. force: the relay at once (the channel's already known to need it).
66
- // h: the channel's own User-Agent / Referer ({ ua, ref }).
67
- function liveOpen(url, h, force) {
65
+ // { fix, sure, why, url, cc: [{ ch, lang }] (its closed captions), ccSure }. force: the relay
66
+ // at once (the channel's already known to need it). h: the channel's own User-Agent /
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
+ function liveOpen(url, h, force, opts) {
68
70
  if (MODE === 'browser') { return Promise.reject(new Error('no service')); }
71
+ var cc = opts && opts.cc ? opts.cc.map(function (c) { return c.ch + (c.lang ? '-' + c.lang : ''); }).join(',') : '';
69
72
  return ensureService().then(entryAuth).then(function (a) {
70
- var q = '/live/open?u=' + encodeURIComponent(url) + (h && h.ua ? '&ua=' + encodeURIComponent(h.ua) : '') + (h && h.ref ? '&ref=' + encodeURIComponent(h.ref) : '') + (force ? '&force=1' : '');
73
+ 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
+ (force && opts && opts.fix === false ? '&fix=0' : '') + (force && cc ? '&cc=' + encodeURIComponent(cc) : '');
71
75
  return U.getJSON(PROXY + q + a.q, force ? 5000 : 30000, 65536, null, a.h);
72
76
  });
73
77
  }
@@ -91,6 +95,50 @@ var YTPlay = (function () {
91
95
  return U.getJSON(PROXY + '/aiom/addons?base=' + encodeURIComponent(base) + a.q, 40000, 1048576, null, h);
92
96
  });
93
97
  }
98
+ // A playlist's TV guide, read and kept by the service (see service/index.js, epgControl):
99
+ // epgLoad asks it to read it for these channels (k: their keys as a bitset, EPG.bitsFor) ->
100
+ // { state, at, channels, programmes, partial, error }; epgGet: their programs -> { <key>:
101
+ // [[start, stop, title, desc]] }. Both POSTs, what's asked in the body: a newer TV's service
102
+ // reads 8 KB of a request's address and headers, less than thousands of channels' keys.
103
+ // (a POST refused, a service from before it took them or one without the token: asked
104
+ // again as a GET, when it fits in the address)
105
+ // An app that can't read the service's token (its header instead): the guide ticket, asked
106
+ // for once, given with the POSTs (the TV adds an Origin to them, which the header alone doesn't pass).
107
+ var _ticket = null;
108
+ function epgTicket(a) {
109
+ if (a.q || MODE === 'tizenbrew') { return Promise.resolve(a.q); } // (the token; TizenBrew's origin passes as it is)
110
+ if (!_ticket) {
111
+ _ticket = U.getJSON(PROXY + '/epg/ticket', 8000, 4096, null, a.h).then(function (r) {
112
+ return r && /^[0-9a-f]{48}$/.test(r.ticket || '') ? '&ticket=' + r.ticket : '';
113
+ }, function () { _ticket = null; return ''; });
114
+ }
115
+ return _ticket;
116
+ }
117
+ function epgAsk(path, body, maxBytes) {
118
+ if (MODE === 'browser') { return Promise.reject(new Error('no service')); }
119
+ return ensureService().then(entryAuth).then(function (a) {
120
+ return epgTicket(a).then(function (cred) { return { a: a, cred: cred }; });
121
+ }).then(function (x) {
122
+ var a = x.a, q = x.cred ? '?' + x.cred.replace(/^&/, '') : '';
123
+ return U.postJSON(PROXY + path + q, body, 15000, maxBytes, a.h).then(null, function (err) {
124
+ if (err && /^HTTP 403\b/.test(err.message || '') && /ticket=/.test(q)) { _ticket = null; } // (the service started again since: a new ticket next time)
125
+ if (!(err && /^HTTP (403|405)\b/.test(err.message || '') && body.length < 6000)) { throw err; }
126
+ return U.getJSON(PROXY + path + (q ? q + '&' : '?') + body, 15000, maxBytes, null, a.h);
127
+ });
128
+ });
129
+ }
130
+ // Settings › Storage: the saved guides ({ count, bytes }), and deleting them all.
131
+ function epgFiles() {
132
+ if (MODE === 'browser') { return Promise.resolve(null); }
133
+ return ensureService().then(entryAuth).then(function (a) { return U.getJSON(PROXY + '/epg/files' + (a.q ? '?' + a.q.replace(/^&/, '') : ''), 8000, 4096, null, a.h); });
134
+ }
135
+ function epgClear() { return epgAsk('/epg/clear', '', 4096); }
136
+ function epgLoad(u, k, force) {
137
+ return epgAsk('/epg/load', 'u=' + encodeURIComponent(u) + '&k=' + k + (force ? '&force=1' : ''), 65536);
138
+ }
139
+ function epgGet(u, keys, from, to, max) {
140
+ return epgAsk('/epg/get', 'u=' + encodeURIComponent(u) + '&ids=' + encodeURIComponent(keys.join('|')) + '&from=' + from + '&to=' + to + (max ? '&max=' + max : ''), 4194304);
141
+ }
94
142
  // Whether YouTube gives the video out to the service (it refuses some uploads to the player
95
143
  // the service asks as): false when it says no; true when it does, or no answer came (the
96
144
  // player tries). The service keeps what it found, so playing it next asks YouTube nothing new.
@@ -181,6 +229,6 @@ var YTPlay = (function () {
181
229
  return MODE === 'tizenbrew' ? 'TizenBrew module' : MODE === 'wgt' ? 'Sideloaded app (.wgt)' : 'Browser (development)';
182
230
  }
183
231
 
184
- return { ensureService: ensureService, resolverUrl: resolverUrl, infoUrl: infoUrl, canPlay: canPlay, liveOpen: liveOpen, hlsMaster: hlsMaster, aiomAddons: aiomAddons, entryOpen: entryOpen, entryPoll: entryPoll, entryClose: entryClose, subsUrl: subsUrl, audioLang: audioLang, setAudioLang: setAudioLang, installMode: function () { return MODE; },
232
+ return { ensureService: ensureService, resolverUrl: resolverUrl, infoUrl: infoUrl, canPlay: canPlay, liveOpen: liveOpen, hlsMaster: hlsMaster, aiomAddons: aiomAddons, epgLoad: epgLoad, epgGet: epgGet, epgFiles: epgFiles, epgClear: epgClear, entryOpen: entryOpen, entryPoll: entryPoll, entryClose: entryClose, subsUrl: subsUrl, audioLang: audioLang, setAudioLang: setAudioLang, installMode: function () { return MODE; },
185
233
  installLabel: installLabel, unavailableMessage: unavailableMessage, isRunning: isRunning, port: PORT };
186
234
  })();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stremiok",
3
- "version": "2.1.0",
3
+ "version": "2.2.0",
4
4
  "description": "StremioK streaming client for Tizen 3.0+ Samsung TVs (TizenBrew app module).",
5
5
  "packageType": "app",
6
6
  "appName": "StremioK",
@@ -14,6 +14,7 @@
14
14
  "icon.png",
15
15
  "config.xml",
16
16
  "README.md",
17
+ "CHANGELOG.md",
17
18
  "LICENSE"
18
19
  ],
19
20
  "keys": [