Focus-friendly VMC shell for Tizen with live TV and playback against the master API. Co-authored-by: Cursor <cursoragent@cursor.com>
163 lines
5.8 KiB
JavaScript
163 lines
5.8 KiB
JavaScript
(function (global) {
|
|
var BASE = "https://master.vonas.nl";
|
|
var TOKEN_KEY = "mc_refresh_token";
|
|
var PROFILE_KEY = "mc_profile";
|
|
var FAV_KEY = "mc_iptv_favs";
|
|
|
|
function store() {
|
|
try {
|
|
return localStorage;
|
|
} catch (e) {
|
|
return {
|
|
_d: {},
|
|
getItem: function (k) { return this._d[k] || null; },
|
|
setItem: function (k, v) { this._d[k] = String(v); },
|
|
removeItem: function (k) { delete this._d[k]; },
|
|
};
|
|
}
|
|
}
|
|
var ls = store();
|
|
|
|
function getToken() { return ls.getItem(TOKEN_KEY); }
|
|
function setToken(token) {
|
|
if (token) ls.setItem(TOKEN_KEY, token);
|
|
else ls.removeItem(TOKEN_KEY);
|
|
}
|
|
function getProfileCache() {
|
|
try { return JSON.parse(ls.getItem(PROFILE_KEY) || "null"); } catch (e) { return null; }
|
|
}
|
|
function setProfileCache(profile) {
|
|
if (profile) ls.setItem(PROFILE_KEY, JSON.stringify(profile));
|
|
else ls.removeItem(PROFILE_KEY);
|
|
}
|
|
function getFavs() {
|
|
try { return JSON.parse(ls.getItem(FAV_KEY) || "[]"); } catch (e) { return []; }
|
|
}
|
|
function setFavs(ids) { ls.setItem(FAV_KEY, JSON.stringify(ids || [])); }
|
|
function toggleFav(streamId) {
|
|
var id = String(streamId);
|
|
var favs = getFavs();
|
|
var i = favs.indexOf(id);
|
|
if (i >= 0) favs.splice(i, 1);
|
|
else favs.push(id);
|
|
setFavs(favs);
|
|
return favs.indexOf(id) >= 0;
|
|
}
|
|
function isFav(streamId) { return getFavs().indexOf(String(streamId)) >= 0; }
|
|
|
|
function errMessage(body, status) {
|
|
if (body && body.error && body.error.message) return body.error.message;
|
|
if (body && body.error && body.error.code) return body.error.code;
|
|
return "HTTP " + status;
|
|
}
|
|
|
|
function request(path, opts) {
|
|
opts = opts || {};
|
|
var headers = opts.headers || {};
|
|
headers["Content-Type"] = "application/json";
|
|
var token = getToken();
|
|
if (token && !opts.noAuth) headers.Authorization = "Bearer " + token;
|
|
return fetch(BASE + path, {
|
|
method: opts.method || "GET",
|
|
headers: headers,
|
|
body: opts.body ? JSON.stringify(opts.body) : undefined,
|
|
}).then(function (res) {
|
|
return res.text().then(function (text) {
|
|
var body = null;
|
|
try { body = text ? JSON.parse(text) : null; } catch (e) { body = { raw: text }; }
|
|
if (!res.ok) {
|
|
var err = new Error(errMessage(body, res.status));
|
|
err.status = res.status;
|
|
err.code = body && body.error && body.error.code;
|
|
err.body = body;
|
|
throw err;
|
|
}
|
|
return body;
|
|
});
|
|
});
|
|
}
|
|
|
|
global.McApi = {
|
|
BASE: BASE,
|
|
getToken: getToken,
|
|
setToken: setToken,
|
|
getProfileCache: getProfileCache,
|
|
setProfileCache: setProfileCache,
|
|
getFavs: getFavs,
|
|
toggleFav: toggleFav,
|
|
isFav: isFav,
|
|
clearSession: function () { setToken(null); setProfileCache(null); },
|
|
deviceCode: function () {
|
|
return request("/api/v1/client/device/code", {
|
|
method: "POST", noAuth: true,
|
|
body: { deviceName: "Samsung Tizen", platform: "tizen" },
|
|
});
|
|
},
|
|
devicePoll: function (code) {
|
|
return request("/api/v1/client/device/poll?code=" + encodeURIComponent(code), { noAuth: true });
|
|
},
|
|
me: function () { return request("/api/v1/client/me"); },
|
|
listProfiles: function () { return request("/api/v1/client/profiles"); },
|
|
selectProfile: function (id, pin) {
|
|
var body = {};
|
|
if (pin) body.pin = pin;
|
|
return request("/api/v1/client/profiles/" + encodeURIComponent(id) + "/select", { method: "POST", body: body });
|
|
},
|
|
clearProfile: function () {
|
|
return request("/api/v1/client/profiles/clear", { method: "POST", body: {} });
|
|
},
|
|
home: function () { return request("/api/v1/client/home"); },
|
|
search: function (q) {
|
|
return request("/api/v1/client/search?q=" + encodeURIComponent(q) + "&take=60");
|
|
},
|
|
catalog: function (id, skip, take) {
|
|
skip = skip || 0; take = take || 60;
|
|
return request(
|
|
"/api/v1/client/catalog/" + encodeURIComponent(id) +
|
|
"?skip=" + skip + "&take=" + take
|
|
);
|
|
},
|
|
movie: function (id) { return request("/api/v1/client/movies/" + encodeURIComponent(id)); },
|
|
series: function (id) { return request("/api/v1/client/series/" + encodeURIComponent(id)); },
|
|
play: function (mediaFileId) {
|
|
return request("/api/v1/client/play", { method: "POST", body: { mediaFileId: mediaFileId } });
|
|
},
|
|
progress: function (payload) {
|
|
return request("/api/v1/client/progress", { method: "POST", body: payload });
|
|
},
|
|
dismissContinue: function (progressId) {
|
|
return request("/api/v1/client/progress/" + encodeURIComponent(progressId) + "/dismiss", {
|
|
method: "POST", body: {},
|
|
});
|
|
},
|
|
iptvCategories: function () { return request("/api/v1/client/iptv/categories"); },
|
|
iptvChannels: function (categoryId, includeEpg) {
|
|
var params = [];
|
|
if (categoryId) params.push("categoryId=" + encodeURIComponent(categoryId));
|
|
if (includeEpg) params.push("epg=1");
|
|
var q = params.length ? "?" + params.join("&") : "";
|
|
return request("/api/v1/client/iptv/channels" + q);
|
|
},
|
|
iptvPlay: function (streamId) {
|
|
return request("/api/v1/client/iptv/channels/" + streamId + "/play");
|
|
},
|
|
iptvEpg: function (streamId) {
|
|
return request("/api/v1/client/iptv/channels/" + streamId + "/epg");
|
|
},
|
|
searchSubtitles: function (mediaFileId, languages) {
|
|
languages = languages || "nl,en";
|
|
return request(
|
|
"/api/v1/client/subtitles/search?mediaFileId=" +
|
|
encodeURIComponent(mediaFileId) +
|
|
"&languages=" +
|
|
encodeURIComponent(languages)
|
|
);
|
|
},
|
|
fetchSubtitle: function (fileId, source) {
|
|
return request("/api/v1/client/subtitles/fetch", {
|
|
method: "POST",
|
|
body: { fileId: fileId, source: source || "org" },
|
|
});
|
|
},
|
|
};
|
|
})(window);
|