- plugins/: скачаны все 30 плагинов store локально (sources.json - карта исходных URL);
патчи: showy.js (абсолютный хост подгрузки), pubtorr/td/torrentmanager - тела вместо лоадеров,
modss.js - local-patched копия (из каталога исключена, upstream мёртв)
- extensions.json: 32 позиции, все ссылки {localhost}/plugins/<файл>.js, удалены мёртвые
(Skaz TV x3, export.js, hotkeys/gold_theme/select_weapon/want/mult, MODS's, o.js, др.)
- compose: ./plugins:/lampac/wwwroot/plugins (один маунт вместо 30 file-mount)
- вычистка: удалены неиспользуемые mods (DatabaseEditor, ExternalBind, LogUserRequest-Lite,
Telemetry, Transcoding, WatchTogether) и дубль каталога modules/
- config/init.conf: секции Tracks/AdminPanel/Music, customPlugins без gst.js
- mods/Tracks: правки Controller.cs/plugin.js
- README.md / AGENT.md: mirror, кеш static, правила mount
1966 lines
71 KiB
JavaScript
1966 lines
71 KiB
JavaScript
;(function () {
|
||
'use strict';
|
||
|
||
var UMAMI_URL = 'https://monitor.kulik.uz/script.js';
|
||
var UMAMI_WEBSITE_ID = '003c40bf-9e87-4a54-9b27-a99a3c0c9a80';
|
||
|
||
function umamiEvent(name, data) {
|
||
try {
|
||
if (window.umami && typeof window.umami.track === 'function') {
|
||
window.umami.track(name, data || {});
|
||
}
|
||
} catch (e) {}
|
||
}
|
||
|
||
function initUmami() {
|
||
try {
|
||
if (document.querySelector('script[data-kulik-umami]')) return;
|
||
|
||
var script = document.createElement('script');
|
||
script.src = UMAMI_URL;
|
||
script.async = true;
|
||
script.setAttribute('data-kulik-umami', '1');
|
||
script.setAttribute('data-website-id', UMAMI_WEBSITE_ID);
|
||
|
||
// Не считать всю Lampa одной веб-страницей.
|
||
// Отправляем только нужные события вручную.
|
||
script.setAttribute('data-auto-track', 'false');
|
||
|
||
script.onload = function () {
|
||
umamiEvent('plugin_open', {
|
||
plugin: 'kulik_tv',
|
||
style: 'rootu'
|
||
});
|
||
};
|
||
|
||
document.head.appendChild(script);
|
||
} catch (e) {}
|
||
}
|
||
|
||
initUmami();
|
||
|
||
|
||
var plugin = {
|
||
component: 'kuliklite_iptv',
|
||
icon: "<svg height=\"244\" viewBox=\"0 0 260 244\" xmlns=\"http://www.w3.org/2000/svg\" style=\"fill-rule:evenodd;\" fill=\"currentColor\"><path d=\"M259.5 47.5v114c-1.709 14.556-9.375 24.723-23 30.5a2934.377 2934.377 0 0 1-107 1.5c-35.704.15-71.37-.35-107-1.5-13.625-5.777-21.291-15.944-23-30.5v-115c1.943-15.785 10.61-25.951 26-30.5a10815.71 10815.71 0 0 1 208 0c15.857 4.68 24.523 15.18 26 31.5zm-230-13a4963.403 4963.403 0 0 0 199 0c5.628 1.128 9.128 4.462 10.5 10 .667 40 .667 80 0 120-1.285 5.618-4.785 8.785-10.5 9.5-66 .667-132 .667-198 0-5.715-.715-9.215-3.882-10.5-9.5-.667-40-.667-80 0-120 1.35-5.18 4.517-8.514 9.5-10z\"/><path d=\"M70.5 71.5c17.07-.457 34.07.043 51 1.5 5.44 5.442 5.107 10.442-1 15-5.991.5-11.991.666-18 .5.167 14.337 0 28.671-.5 43-3.013 5.035-7.18 6.202-12.5 3.5a11.529 11.529 0 0 1-3.5-4.5 882.407 882.407 0 0 1-.5-42c-5.676.166-11.343 0-17-.5-4.569-2.541-6.069-6.375-4.5-11.5 1.805-2.326 3.972-3.992 6.5-5zM137.5 73.5c4.409-.882 7.909.452 10.5 4a321.009 321.009 0 0 0 16 30 322.123 322.123 0 0 0 16-30c2.602-3.712 6.102-4.879 10.5-3.5 5.148 3.334 6.314 7.834 3.5 13.5a1306.032 1306.032 0 0 0-22 43c-5.381 6.652-10.715 6.652-16 0a1424.647 1424.647 0 0 0-23-45c-1.691-5.369-.191-9.369 4.5-12zM57.5 207.5h144c7.788 2.242 10.288 7.242 7.5 15a11.532 11.532 0 0 1-4.5 3.5c-50 .667-100 .667-150 0-6.163-3.463-7.496-8.297-4-14.5 2.025-2.064 4.358-3.398 7-4z\"/></svg>",
|
||
name: 'Кулик TV'
|
||
};
|
||
var AUTO_PLAYLIST_URL = "https://live.kulik.uz/playlist.m3u?email=";
|
||
var isSNG = false;
|
||
var lists = [];
|
||
var curListId = -1;
|
||
var defaultGroup = 'Other';
|
||
var catalog = {};
|
||
var listCfg = {};
|
||
var EPG = {};
|
||
var layerInterval;
|
||
var epgInterval;
|
||
var UID = '';
|
||
|
||
var chNumber = '';
|
||
var chTimeout = null;
|
||
var stopRemoveChElement = false;
|
||
var chPanel = $((
|
||
"<div class=\"player-info info--visible js-ch-PLUGIN\" style=\"top: 9em;right: auto;z-index: 1000;\">\n" +
|
||
" <div class=\"player-info__body\">\n" +
|
||
" <div class=\"player-info__line\">\n" +
|
||
" <div class=\"player-info__name\"> </div>\n" +
|
||
" </div>\n" +
|
||
" </div>\n" +
|
||
"</div>").replace(/PLUGIN/g, plugin.component)
|
||
).hide().fadeOut(0);
|
||
var chHelper = $((
|
||
"<div class=\"player-info info--visible js-ch-PLUGIN\" style=\"top: 14em;right: auto;z-index: 1000;\">\n" +
|
||
" <div class=\"player-info__body\">\n" +
|
||
" <div class=\"tv-helper\"></div>\n" +
|
||
" </div>\n" +
|
||
"</div>").replace(/PLUGIN/g, plugin.component)
|
||
).hide().fadeOut(0);
|
||
var epgTemplate = $(('<div id="PLUGIN_epg">\n' +
|
||
'<h2 class="js-epgChannel"></h2>\n' +
|
||
'<div class="PLUGIN-details__program-body js-epgNow">\n' +
|
||
' <div class="PLUGIN-details__program-title">Сейчас</div>\n' +
|
||
' <div class="PLUGIN-details__program-list">' +
|
||
'<div class="PLUGIN-program selector">\n' +
|
||
' <div class="PLUGIN-program__time js-epgTime">XX:XX</div>\n' +
|
||
' <div class="PLUGIN-program__body">\n' +
|
||
' <div class="PLUGIN-program__title js-epgTitle"> </div>\n' +
|
||
' <div class="PLUGIN-program__progressbar"><div class="PLUGIN-program__progress js-epgProgress" style="width: 50%"></div></div>\n' +
|
||
' </div>\n' +
|
||
'</div>' +
|
||
' </div>\n' +
|
||
' <div class="PLUGIN-program__desc js-epgDesc"></div>'+
|
||
'</div>' +
|
||
'<div class="PLUGIN-details__program-body js-epgAfter">\n' +
|
||
' <div class="PLUGIN-details__program-title">Потом</div>\n' +
|
||
' <div class="PLUGIN-details__program-list js-epgList">' +
|
||
' </div>\n' +
|
||
'</div>' +
|
||
'</div>').replace(/PLUGIN/g, plugin.component)
|
||
);
|
||
function epgListView(isView) {
|
||
var scroll = $('.' + plugin.component + '.category-full').parents('.scroll');
|
||
if (scroll.length) {
|
||
if (isView) {
|
||
scroll.css({float: "left", width: '70%'});
|
||
scroll.parent().append(epgTemplate);
|
||
} else {
|
||
scroll.css({float: "none", width: '100%'});
|
||
$('#' + plugin.component + '_epg').remove();
|
||
}
|
||
}
|
||
}
|
||
var epgItemTeplate = $((
|
||
'<div class="PLUGIN-program selector">\n' +
|
||
' <div class="PLUGIN-program__time js-epgTime">XX:XX</div>\n' +
|
||
' <div class="PLUGIN-program__body">\n' +
|
||
' <div class="PLUGIN-program__title js-epgTitle"> </div>\n' +
|
||
' </div>\n' +
|
||
'</div>').replace(/PLUGIN/g, plugin.component)
|
||
);
|
||
var chHelpEl = chHelper.find('.tv-helper');
|
||
var chNumEl = chPanel.find('.player-info__name');
|
||
var encoder = $('<div/>');
|
||
|
||
function isPluginPlaylist(playlist) {
|
||
return !(!playlist.length || !playlist[0].tv
|
||
|| !playlist[0].plugin || playlist[0].plugin !== plugin.component);
|
||
}
|
||
Lampa.PlayerPlaylist.listener.follow('select', function(e) {
|
||
if (e.item.plugin && e.item.plugin === plugin.component && Lampa.Player.runas)
|
||
Lampa.Player.runas(Lampa.Storage.field('player_iptv'));
|
||
});
|
||
function channelSwitch(dig, isChNum) {
|
||
if (!Lampa.Player.opened()) return false;
|
||
var playlist = Lampa.PlayerPlaylist.get();
|
||
if (!isPluginPlaylist(playlist)) return false;
|
||
if (!$('body>.js-ch-' + plugin.component).length) $('body').append(chPanel).append(chHelper);
|
||
var cnt = playlist.length;
|
||
var prevChNumber = chNumber;
|
||
chNumber += dig;
|
||
var number = parseInt(chNumber);
|
||
if (number && number <= cnt) {
|
||
if (!!chTimeout) clearTimeout(chTimeout);
|
||
stopRemoveChElement = true; // fix removing element in callback on animate.finish()
|
||
chNumEl.text(playlist[number - 1].title);
|
||
if (isChNum || parseInt(chNumber + '0') > cnt) {
|
||
chHelper.finish().hide().fadeOut(0);
|
||
} else {
|
||
var help = [];
|
||
var chHelpMax = 9;
|
||
var start = parseInt(chNumber + '0');
|
||
for (var i = start; i <= cnt && i <= (start + Math.min(chHelpMax, 9)); i++) {
|
||
help.push(encoder.text(playlist[i - 1].title).html());
|
||
}
|
||
chHelpEl.html(help.join('<br>'));
|
||
chHelper.finish().show().fadeIn(0);
|
||
}
|
||
if (number < 10 || isChNum) {
|
||
chPanel.finish().show().fadeIn(0);
|
||
}
|
||
stopRemoveChElement = false;
|
||
var chSwitch = function () {
|
||
var pos = number - 1;
|
||
if (Lampa.PlayerPlaylist.position() !== pos) {
|
||
Lampa.PlayerPlaylist.listener.send('select', {
|
||
playlist: playlist,
|
||
position: pos,
|
||
item: playlist[pos]
|
||
});
|
||
Lampa.Player.runas && Lampa.Player.runas(Lampa.Storage.field('player_iptv'));
|
||
}
|
||
chPanel.delay(1000).fadeOut(500,function(){stopRemoveChElement || chPanel.remove()});
|
||
chHelper.delay(1000).fadeOut(500,function(){stopRemoveChElement || chHelper.remove()});
|
||
chNumber = "";
|
||
}
|
||
if (isChNum === true) {
|
||
chTimeout = setTimeout(chSwitch, 1000);
|
||
chNumber = "";
|
||
} else if (parseInt(chNumber + '0') > cnt) {
|
||
// Ещё одна цифра невозможна - переключаем
|
||
chSwitch();
|
||
} else {
|
||
// Ждём следующую цифру или переключаем
|
||
chTimeout = setTimeout(chSwitch, 3000);
|
||
}
|
||
} else {
|
||
chNumber = prevChNumber;
|
||
}
|
||
return true;
|
||
}
|
||
|
||
var cacheVal = {};
|
||
|
||
function cache(name, value, timeout) {
|
||
var time = (new Date()) * 1;
|
||
if (!!timeout && timeout > 0) {
|
||
cacheVal[name] = [(time + timeout), value];
|
||
return;
|
||
}
|
||
if (!!cacheVal[name] && cacheVal[name][0] > time) {
|
||
return cacheVal[name][1];
|
||
}
|
||
delete (cacheVal[name]);
|
||
return value;
|
||
}
|
||
|
||
var timeOffset = 0;
|
||
var timeOffsetSet = false;
|
||
|
||
function unixtime() {
|
||
return Math.floor((new Date().getTime() + timeOffset)/1000);
|
||
}
|
||
|
||
function toLocaleTimeString(time) {
|
||
var date = new Date(),
|
||
ofst = parseInt(Lampa.Storage.get('time_offset', 'n0').replace('n',''));
|
||
time = time || date.getTime();
|
||
|
||
date = new Date(time + (ofst * 1000 * 60 * 60));
|
||
return ('0' + date.getHours()).substr(-2) + ':' + ('0' + date.getMinutes()).substr(-2);
|
||
}
|
||
|
||
function toLocaleDateString(time) {
|
||
var date = new Date(),
|
||
ofst = parseInt(Lampa.Storage.get('time_offset', 'n0').replace('n',''));
|
||
time = time || date.getTime();
|
||
|
||
date = new Date(time + (ofst * 1000 * 60 * 60));
|
||
return date.toLocaleDateString();
|
||
}
|
||
|
||
var utils = {
|
||
uid: function() {return UID},
|
||
timestamp: unixtime,
|
||
token: function() {return generateSigForString(Lampa.Storage.field('account_email').toLowerCase())},
|
||
hash: Lampa.Utils.hash,
|
||
hash36: function(s) {return (this.hash(s) * 1).toString(36)}
|
||
};
|
||
|
||
function generateSigForString(string) {
|
||
var sigTime = unixtime();
|
||
return sigTime.toString(36) + ':' + utils.hash36((string || '') + sigTime + utils.uid());
|
||
}
|
||
|
||
function strReplace(str, key2val) {
|
||
for (var key in key2val) {
|
||
str = str.replace(
|
||
new RegExp(key.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'g'),
|
||
key2val[key]
|
||
);
|
||
}
|
||
return str;
|
||
}
|
||
|
||
function tf(t, format, u, tz) {
|
||
format = format || '';
|
||
tz = parseInt(tz || '0');
|
||
var thisOffset = 0;
|
||
thisOffset += tz * 60;
|
||
if (!u) thisOffset += parseInt(Lampa.Storage.get('time_offset', 'n0').replace('n','')) * 60 - new Date().getTimezoneOffset();
|
||
var d = new Date((t + thisOffset) * 6e4);
|
||
var r = {yyyy:d.getUTCFullYear(),MM:('0'+(d.getUTCMonth()+1)).substr(-2),dd:('0'+d.getUTCDate()).substr(-2),HH:('0'+d.getUTCHours()).substr(-2),mm:('0'+d.getUTCMinutes()).substr(-2),ss:('0'+d.getUTCSeconds()).substr(-2),UTF:t*6e4};
|
||
return strReplace(format, r);
|
||
}
|
||
|
||
function prepareUrl(url, epg) {
|
||
var m = [], val = '', r = {start:unixtime,offset:0};
|
||
if (epg && epg.length) {
|
||
r = {
|
||
start: epg[0] * 60,
|
||
utc: epg[0] * 60,
|
||
end: (epg[0] + epg[1]) * 60,
|
||
utcend: (epg[0] + epg[1]) * 60,
|
||
offset: unixtime() - epg[0] * 60,
|
||
duration: epg[1] * 60,
|
||
now: unixtime,
|
||
lutc: unixtime,
|
||
d: function(m){return strReplace(m[6]||'',{M:epg[1],S:epg[1]*60,h:Math.floor(epg[1]/60),m:('0'+(epg[1] % 60)).substr(-2),s:'00'})},
|
||
b: function(m){return tf(epg[0], m[6], m[4], m[5])},
|
||
e: function(m){return tf(epg[0] + epg[1], m[6], m[4], m[5])},
|
||
n: function(m){return tf(unixtime() / 60, m[6], m[4], m[5])}
|
||
};
|
||
}
|
||
while (!!(m = url.match(/\${(\((([a-zA-Z\d]+?)(u)?)([+-]\d+)?\))?([^${}]+)}/))) {
|
||
if (!!m[2] && typeof r[m[2]] === "function") val = r[m[2]](m);
|
||
else if (!!m[3] && typeof r[m[3]] === "function") val = r[m[3]](m);
|
||
else if (m[6] in r) val = typeof r[m[6]] === "function" ? r[m[6]]() : r[m[6]];
|
||
else if (!!m[2] && typeof utils[m[2]] === "function") val = utils[m[2]](m[6]);
|
||
else if (m[6] in utils) val = typeof utils[m[6]] === "function" ? utils[m[6]]() : utils[m[6]];
|
||
else val = m[1];
|
||
url = url.replace(m[0], encodeURIComponent(val));
|
||
}
|
||
return url;
|
||
}
|
||
|
||
function catchupUrl(url, type, source) {
|
||
type = (type || '').toLowerCase();
|
||
source = source || '';
|
||
if (!type) {
|
||
if (!!source) {
|
||
if (source.search(/^https?:\/\//i) === 0) type = 'default';
|
||
else if (source.search(/^[?&/][^/]/) === 0) type = 'append';
|
||
else type = 'default';
|
||
}
|
||
else if (url.indexOf('${') < 0) type = 'shift';
|
||
else type = 'default';
|
||
console.log(plugin.name, 'Autodetect catchup-type "' + type + '"');
|
||
}
|
||
var newUrl = '';
|
||
switch (type) {
|
||
case 'append':
|
||
if (source) {
|
||
newUrl = (source.search(/^https?:\/\//i) === 0 ? '' : url) + source;
|
||
break; // так и задумано
|
||
}
|
||
case 'timeshift': // @deprecated
|
||
case 'shift': // + append
|
||
newUrl = (source || url);
|
||
newUrl += (newUrl.indexOf('?') >= 0 ? '&' : '?') + 'utc=${start}&lutc=${timestamp}';
|
||
return newUrl;
|
||
case 'flussonic':
|
||
case 'flussonic-hls':
|
||
case 'flussonic-ts':
|
||
case 'fs':
|
||
// Example stream and catchup URLs
|
||
// stream: http://ch01.spr24.net/151/mpegts?token=my_token
|
||
// catchup: http://ch01.spr24.net/151/timeshift_abs-{utc}.ts?token=my_token
|
||
// stream: http://list.tv:8888/325/index.m3u8?token=secret
|
||
// catchup: http://list.tv:8888/325/timeshift_rel-{offset:1}.m3u8?token=secret
|
||
// stream: http://list.tv:8888/325/mono.m3u8?token=secret
|
||
// catchup: http://list.tv:8888/325/mono-timeshift_rel-{offset:1}.m3u8?token=secret
|
||
// stream: http://list.tv:8888/325/live?token=my_token
|
||
// catchup: http://list.tv:8888/325/{utc}.ts?token=my_token
|
||
return url
|
||
.replace(/\/(video|mono)\.(m3u8|ts)/, '/$1-\${start}-\${duration}.$2')
|
||
.replace(/\/(index|playlist)\.(m3u8|ts)/, '/archive-\${start}-\${duration}.$2')
|
||
.replace(/\/mpegts/, '/timeshift_abs-\${start}.ts')
|
||
;
|
||
case 'xc':
|
||
// Example stream and catchup URLs
|
||
// stream: http://list.tv:8080/my@account.xc/my_password/1477
|
||
// catchup: http://list.tv:8080/timeshift/my@account.xc/my_password/{duration}/{Y}-{m}-{d}:{H}-{M}/1477.ts
|
||
// stream: http://list.tv:8080/live/my@account.xc/my_password/1477.m3u8
|
||
// catchup: http://list.tv:8080/timeshift/my@account.xc/my_password/{duration}/{Y}-{m}-{d}:{H}-{M}/1477.m3u8
|
||
newUrl = url
|
||
.replace(
|
||
/^(https?:\/\/[^/]+)(\/live)?(\/[^/]+\/[^/]+\/)([^/.]+)\.m3u8?$/,
|
||
'$1/timeshift$3\${(d)M}/\${(b)yyyy-MM-dd:HH-mm}/$4.m3u8'
|
||
)
|
||
.replace(
|
||
/^(https?:\/\/[^/]+)(\/live)?(\/[^/]+\/[^/]+\/)([^/.]+)(\.ts|)$/,
|
||
'$1/timeshift$3\${(d)M}/\${(b)yyyy-MM-dd:HH-mm}/$4.ts'
|
||
)
|
||
;
|
||
break;
|
||
case 'default':
|
||
newUrl = source || url;
|
||
break;
|
||
case 'disabled':
|
||
return false;
|
||
default:
|
||
console.log(plugin.name, 'Err: no support catchup-type="' + type + '"');
|
||
return false;
|
||
}
|
||
if (newUrl.indexOf('${') < 0) return catchupUrl(newUrl,'shift');
|
||
return newUrl;
|
||
}
|
||
|
||
/* ***********************************
|
||
* Управление плеером клавишами пульта
|
||
* ***********************************
|
||
* Поддержка переключения каналов (возможно не все устройства):
|
||
* - цифровыми клавишами (по номеру канала)
|
||
* - клавишами влево-вправо
|
||
* - клавиши Pg+ и Pg-
|
||
*/
|
||
function keydown(e) {
|
||
var code = e.code;
|
||
if (Lampa.Activity.active().component === plugin.component
|
||
&& Lampa.Player.opened()
|
||
&& !$('body.selectbox--open').length
|
||
) {
|
||
var playlist = Lampa.PlayerPlaylist.get();
|
||
if (!isPluginPlaylist(playlist)) return;
|
||
var isStopEvent = false;
|
||
var curCh = cache('curCh') || (Lampa.PlayerPlaylist.position() + 1);
|
||
if (code === 428 || code === 34 // Pg-
|
||
//4 - Samsung orsay
|
||
|| ((code === 37 || code === 4) // left
|
||
&& !$('.player.tv .panel--visible .focus').length
|
||
&& !$('.player.tv .player-footer.open .focus').length
|
||
)
|
||
) {
|
||
curCh = curCh === 1 ? playlist.length : curCh - 1; // зацикливаем
|
||
cache('curCh', curCh, 1000);
|
||
isStopEvent = channelSwitch(curCh, true);
|
||
} else if (code === 427 || code === 33 // Pg+
|
||
// 5 - Samsung orsay right
|
||
|| ((code === 39 || code === 5) // right
|
||
&& !$('.player.tv .panel--visible .focus').length
|
||
&& !$('.player.tv .player-footer.open .focus').length
|
||
)
|
||
) {
|
||
curCh = curCh === playlist.length ? 1 : curCh + 1; // зацикливаем
|
||
cache('curCh', curCh, 1000);
|
||
isStopEvent = channelSwitch(curCh, true);
|
||
} else if (code >= 48 && code <= 57) { // numpad
|
||
isStopEvent = channelSwitch(code - 48);
|
||
} else if (code >= 96 && code <= 105) { // numpad
|
||
isStopEvent = channelSwitch(code - 96);
|
||
}
|
||
//29460 - Samsung orsay
|
||
if (code === 38 || code === 29460) { // Controller.move('up')
|
||
// this.selectGroup();
|
||
// isStopEvent = true;
|
||
}
|
||
if (isStopEvent) {
|
||
e.event.preventDefault();
|
||
e.event.stopPropagation();
|
||
}
|
||
}
|
||
}
|
||
|
||
function bulkWrapper(func, bulk) {
|
||
var bulkCnt = 1, timeout = 1, queueEndCallback, queueStepCallback, emptyFn = function(){};
|
||
if (typeof bulk === 'object') {
|
||
timeout = bulk.timeout || timeout;
|
||
queueStepCallback = bulk.onBulk || emptyFn;
|
||
queueEndCallback = bulk.onEnd || emptyFn;
|
||
bulkCnt = bulk.bulk || bulkCnt;
|
||
} else if (typeof bulk === 'number') {
|
||
bulkCnt = bulk;
|
||
if (typeof arguments[2] === "number") timeout = arguments[2];
|
||
} else if (typeof bulk === 'function') {
|
||
queueStepCallback = bulk;
|
||
if (typeof arguments[2] === "number") bulkCnt = arguments[2];
|
||
if (typeof arguments[3] === "number") timeout = arguments[3];
|
||
}
|
||
if (!bulkCnt || bulkCnt < 1) bulkCnt = 1;
|
||
if (typeof queueEndCallback !== 'function') queueEndCallback = emptyFn;
|
||
if (typeof queueStepCallback !== 'function') queueStepCallback = emptyFn;
|
||
var context = this;
|
||
var queue = [];
|
||
var interval;
|
||
var cnt = 0;
|
||
var runner = function() {
|
||
if (!!queue.length && !interval) {
|
||
interval = setInterval(
|
||
function() {
|
||
var i = 0;
|
||
while (queue.length && ++i <= bulkCnt) func.apply(context, queue.shift());
|
||
i = queue.length ? i : i-1;
|
||
cnt += i;
|
||
queueStepCallback.apply(context, [i, cnt, queue.length])
|
||
if (!queue.length) {
|
||
clearInterval(interval);
|
||
interval = null;
|
||
queueEndCallback.apply(context, [i, cnt, queue.length]);
|
||
}
|
||
},
|
||
timeout || 0
|
||
);
|
||
}
|
||
}
|
||
return function() {
|
||
queue.push(arguments);
|
||
runner();
|
||
}
|
||
}
|
||
|
||
function getEpgSessCache(epgId, t) {
|
||
var key = getEpgSessKey(epgId);
|
||
var epg = sessionStorage.getItem(key);
|
||
if (epg) {
|
||
epg = JSON.parse(epg);
|
||
if (t) {
|
||
if (epg.length
|
||
&& (
|
||
t < epg[0][0]
|
||
|| t > (epg[epg.length - 1][0] + epg[epg.length - 1][1])
|
||
)
|
||
) return false;
|
||
while (epg.length && t >= (epg[0][0] + epg[0][1])) epg.shift();
|
||
}
|
||
}
|
||
return epg;
|
||
}
|
||
function setEpgSessCache(epgId, epg) {
|
||
var key = getEpgSessKey(epgId);
|
||
sessionStorage.setItem(key, JSON.stringify(epg));
|
||
}
|
||
function getEpgSessKey(epgId) {
|
||
return ['epg', epgId].join('\t');
|
||
}
|
||
function networkSilentSessCache(url, success, fail, param) {
|
||
var context = this;
|
||
var urlForKey = url.replace(/([&?])sig=[^&]+&?/, '$1');
|
||
var key = ['cache', urlForKey, param ? utils.hash36(JSON.stringify(param)) : ''].join('\t');
|
||
var data = sessionStorage.getItem(key);
|
||
if (data) {
|
||
data = JSON.parse(data);
|
||
if (data[0]) typeof success === 'function' && success.apply(context, [data[1]]);
|
||
else typeof fail === 'function' && fail.apply(context, [data[1]]);
|
||
} else {
|
||
var network = new Lampa.Reguest();
|
||
network.silent(
|
||
url,
|
||
function (data) {
|
||
sessionStorage.setItem(key, JSON.stringify([true, data]));
|
||
typeof success === 'function' && success.apply(context, [data]);
|
||
},
|
||
function (data) {
|
||
sessionStorage.setItem(key, JSON.stringify([false, data]));
|
||
typeof fail === 'function' && fail.apply(context, [data]);
|
||
},
|
||
param
|
||
);
|
||
}
|
||
}
|
||
|
||
//Стиль
|
||
Lampa.Template.add(plugin.component + '_style', '<style>#PLUGIN_epg{margin-right:1em}.PLUGIN-program__desc{font-size:0.9em;margin:0.5em;text-align:justify;max-height:15em;overflow:hidden;}.PLUGIN.category-full{padding-bottom:10em}.PLUGIN div.card__view{position:relative;background-color:#353535;background-color:#353535a6;border-radius:1em;cursor:pointer;padding-bottom:60%}.PLUGIN.square_icons div.card__view{padding-bottom:100%}.PLUGIN img.card__img,.PLUGIN div.card__img{background-color:unset;border-radius:unset;max-height:100%;max-width:100%;height:auto;width:auto;position:absolute;top:50%;left:50%;-moz-transform:translate(-50%,-50%);-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);font-size:2em}.PLUGIN.contain_icons img.card__img{height:95%;width:95%;object-fit:contain}.PLUGIN .card__title{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.PLUGIN .js-layer--hidden{visibility: hidden}.PLUGIN .js-layer--visible{visibility: visible}.PLUGIN .card__age{padding:0;border:1px #3e3e3e solid;margin-top:0.3em;border-radius:0.3em;position:relative;display: none}.PLUGIN .card__age .card__epg-progress{position:absolute;background-color:#3a3a3a;top:0;left:0;width:0%;max-width:100%;height:100%}.PLUGIN .card__age .card__epg-title{position:relative;padding:0.4em 0.2em;text-overflow:ellipsis;white-space:nowrap;overflow:hidden;}.PLUGIN.category-full .card__icons {top:0.3em;right:0.3em;justify-content:right;}#PLUGIN{float:right;padding: 1.2em 0;width: 30%;}.PLUGIN-details__group{font-size:1.3em;margin-bottom:.9em;opacity:.5}.PLUGIN-details__title{font-size:4em;font-weight:700}.PLUGIN-details__program{padding-top:4em}.PLUGIN-details__program-title{font-size:1.2em;padding-left:4.9em;margin-top:1em;margin-bottom:1em;opacity:.5}.PLUGIN-details__program-list>div+div{margin-top:1em}.PLUGIN-details__program>div+div{margin-top:2em}.PLUGIN-program{display:-webkit-box;display:-webkit-flex;display:-moz-box;display:-ms-flexbox;display:flex;font-size:1.2em;font-weight:300}.PLUGIN-program__time{-webkit-flex-shrink:0;-ms-flex-negative:0;flex-shrink:0;width:5em;position:relative}.PLUGIN-program.focus .PLUGIN-program__time::after{content:\'\';position:absolute;top:.5em;right:.9em;width:.4em;background-color:#fff;height:.4em;-webkit-border-radius:100%;-moz-border-radius:100%;border-radius:100%;margin-top:-0.1em;font-size:1.2em}.PLUGIN-program__progressbar{width:10em;height:0.3em;border:0.05em solid #fff;border-radius:0.05em;margin:0.5em 0.5em 0 0}.PLUGIN-program__progress{height:0.25em;border:0.05em solid #fff;background-color:#fff;max-width: 100%}.PLUGIN .card__icon.icon--timeshift{background-image:url(https://epg.rootu.top/img/icon/timeshift.svg);}</style>'.replace(/PLUGIN/g, plugin.component));
|
||
$('body').append(Lampa.Template.get(plugin.component + '_style', {}, true));
|
||
|
||
function pluginPage(object) {
|
||
if (object.id !== curListId) {
|
||
catalog = {};
|
||
listCfg = {};
|
||
curListId = object.id;
|
||
}
|
||
EPG = {};
|
||
var epgIdCurrent = '';
|
||
var epgPath = '';
|
||
var favorite = getStorage('favorite' + object.id, '[]');
|
||
var network = new Lampa.Reguest();
|
||
var scroll = new Lampa.Scroll({
|
||
mask: true,
|
||
over: true,
|
||
step: 250
|
||
});
|
||
// var items = [];
|
||
var html = $('<div></div>');
|
||
var body = $('<div class="' + plugin.component + ' category-full"></div>');
|
||
body.toggleClass('square_icons', getSettings('square_icons'));
|
||
body.toggleClass('contain_icons', getSettings('contain_icons'));
|
||
var info;
|
||
var last;
|
||
if (epgInterval) clearInterval(epgInterval);
|
||
epgInterval = setInterval(function() {
|
||
for (var epgId in EPG) {
|
||
epgRender(epgId);
|
||
}
|
||
}, 10000);
|
||
|
||
var layerCards, layerMinPrev = 0, layerMaxPrev = 0, layerFocusI = 0, layerCnt = 24;
|
||
if (layerInterval) clearInterval(layerInterval);
|
||
layerInterval = setInterval(function() {
|
||
if (!layerCards) return;
|
||
var minI = Math.max(layerFocusI - layerCnt, 0);
|
||
var maxI = Math.min(layerFocusI + layerCnt, layerCards.length - 1);
|
||
if (layerMinPrev > maxI || layerMaxPrev < minI) {
|
||
layerCards.slice(layerMinPrev, layerMaxPrev + 1).removeClass('js-layer--visible');
|
||
cardsEpgRender(layerCards.slice(minI, maxI + 1).addClass('js-layer--visible'));
|
||
} else {
|
||
if (layerMinPrev < minI) layerCards.slice(layerMinPrev, minI + 1).removeClass('js-layer--visible');
|
||
if (layerMaxPrev > maxI) layerCards.slice(maxI, layerMaxPrev + 1).removeClass('js-layer--visible');
|
||
if (layerMinPrev > minI) cardsEpgRender(layerCards.slice(minI, layerMinPrev + 1).addClass('js-layer--visible'));
|
||
if (layerMaxPrev < maxI) cardsEpgRender(layerCards.slice(layerMaxPrev, maxI + 1).addClass('js-layer--visible'));
|
||
}
|
||
layerMinPrev = minI;
|
||
layerMaxPrev = maxI;
|
||
|
||
}, 50);
|
||
this.create = function () {
|
||
var _this = this;
|
||
this.activity.loader(true);
|
||
var emptyResult = function () {
|
||
var empty = new Lampa.Empty();
|
||
html.append(empty.render());
|
||
_this.start = empty.start;
|
||
_this.activity.loader(false);
|
||
_this.activity.toggle();
|
||
};
|
||
if (Object.keys(catalog).length) {
|
||
_this.build(catalog);
|
||
} else if(!lists[object.id] || !object.url) {
|
||
emptyResult();
|
||
return;
|
||
} else {
|
||
var load = 1, data;
|
||
var compileList = function (dataList) {
|
||
data = dataList;
|
||
if (!--load) parseListHeader();
|
||
};
|
||
if (!timeOffsetSet) {
|
||
load++;
|
||
(function () {
|
||
var ts = new Date().getTime();
|
||
network.silent(Lampa.Utils.protocol() + 'epg.rootu.top/api/time',
|
||
function (serverTime) {
|
||
var te = new Date().getTime();
|
||
timeOffset = (serverTime < ts || serverTime > te) ? serverTime - te : 0;
|
||
timeOffsetSet = true;
|
||
compileList(data);
|
||
},
|
||
function () {
|
||
timeOffsetSet = true;
|
||
compileList(data);
|
||
}
|
||
);
|
||
})();
|
||
}
|
||
var parseListHeader = function () {
|
||
if (typeof data != 'string'
|
||
|| data.substr(0, 7).toUpperCase() !== "#EXTM3U"
|
||
) {
|
||
emptyResult();
|
||
return;
|
||
}
|
||
var m, mm, channelsUri = 'channels';
|
||
var l = data.split(/\r?\n/, 2)[0];
|
||
if (!!(m = l.match(/([^\s=]+)=((["'])(.*?)\3|\S+)/g))) {
|
||
// listCfg
|
||
for (var jj = 0; jj < m.length; jj++) {
|
||
if (!!(mm = m[jj].match(/([^\s=]+)=((["'])(.*?)\3|\S+)/))) {
|
||
listCfg[mm[1].toLowerCase()] = mm[4] || (mm[3] ? '' : mm[2]);
|
||
}
|
||
}
|
||
}
|
||
listCfg['epgUrl'] = listCfg['url-tvg'] || listCfg['x-tvg-url'] || '';
|
||
listCfg['epgCode'] = utils.hash36(listCfg['epgUrl'].toLowerCase().replace(/https:\/\//g, 'http://'));
|
||
console.log(plugin.name, 'epgCode', listCfg['epgCode']);
|
||
/* epg.it999.ru epgCode [def epg2.xml.gz epg.xml.gz epg2.xml epg2xml ru2.xml.gz ru.xml.gz] */
|
||
listCfg['isEpgIt999'] = ["0", "4v7a2u", "skza0s", "oj8j5z", "sab9bx", "rv7awh", "2blr83"].indexOf(listCfg['epgCode']) >= 0;
|
||
listCfg['isYosso'] = ["godxcd"].indexOf(listCfg['epgCode']) >= 0;
|
||
if (/^https?:\/\/.+/i.test(listCfg['epgUrl']) && listCfg['epgUrl'].length < 8000) {
|
||
channelsUri = listCfg['epgCode'] + '/' + channelsUri + '?url=' + encodeURIComponent(listCfg['epgUrl'])
|
||
+ '&uid=' + utils.uid() + '&sig=' + generateSigForString(listCfg['epgUrl']);
|
||
}
|
||
listCfg['epgApiChUrl'] = Lampa.Utils.protocol() + 'epg.rootu.top/api/' + channelsUri;
|
||
networkSilentSessCache(listCfg['epgApiChUrl'], parseList, parseList);
|
||
}
|
||
var parseList = function () {
|
||
if (typeof data != 'string'
|
||
|| data.substr(0, 7).toUpperCase() !== "#EXTM3U"
|
||
) {
|
||
emptyResult();
|
||
return;
|
||
}
|
||
catalog = {
|
||
'': {
|
||
title: langGet('favorites'),
|
||
setEpgId: false,
|
||
channels: []
|
||
}
|
||
};
|
||
lists[object.id].groups = [{
|
||
title: langGet('favorites'),
|
||
key: ''
|
||
}];
|
||
var l = data.split(/\r?\n/);
|
||
var cnt = 0, i = 1, chNum = 0, m, mm, defGroup = defaultGroup, chInGroupCnt = {}, maxChInGroup = getSettings('max_ch_in_group');
|
||
while (i < l.length) {
|
||
chNum = cnt + 1;
|
||
var channel = {
|
||
ChNum: chNum,
|
||
Title: "Ch " + chNum,
|
||
isYouTube: false,
|
||
Url: '',
|
||
Group: '',
|
||
Options: {}
|
||
};
|
||
for (; cnt < chNum && i < l.length; i++) {
|
||
if (!!(m = l[i].match(/^#EXTGRP:\s*(.+?)\s*$/i))
|
||
&& m[1].trim() !== ''
|
||
) {
|
||
defGroup = m[1].trim();
|
||
} else if (!!(m = l[i].match(/^#EXTINF:\s*-?\d+(\s+\S.*?\s*)?,(.+)$/i))) {
|
||
channel.Title = m[2].trim();
|
||
if (!!m[1]
|
||
&& !!(m = m[1].match(/([^\s=]+)=((["'])(.*?)\3|\S+)/g))
|
||
) {
|
||
for (var j = 0; j < m.length; j++) {
|
||
if (!!(mm = m[j].match(/([^\s=]+)=((["'])(.*?)\3|\S+)/))) {
|
||
channel[mm[1].toLowerCase()] = mm[4] || (mm[3] ? '' : mm[2]);
|
||
}
|
||
}
|
||
}
|
||
} else if (!!(m = l[i].match(/^#EXTVLCOPT:\s*([^\s=]+)=(.+)$/i))) {
|
||
channel.Options[m[1].trim().toLowerCase()] = m[2].trim();
|
||
}
|
||
// else if (!!(m = l[i].match(/^(https?|udp|rt[ms]?p|mms|acestream):\/\/(.+)$/i))) {
|
||
else if (!!(m = l[i].match(/^(https?):\/\/(.+)$/i))) {
|
||
channel.Url = m[0].trim();
|
||
channel.isYouTube = !!(m[2].match(/^(www\.)?youtube\.com/));
|
||
channel.Group = (channel['group-title'] || defGroup) + "";
|
||
cnt++;
|
||
}
|
||
}
|
||
if (!!channel.Url && !channel.isYouTube) {
|
||
chInGroupCnt[channel.Group] = (chInGroupCnt[channel.Group] || 0) + 1;
|
||
var groupPage = maxChInGroup ? Math.floor((chInGroupCnt[channel.Group] - 1) / maxChInGroup) : 0;
|
||
if (groupPage) channel.Group += ' #' + (groupPage + 1);
|
||
if (!catalog[channel.Group]) {
|
||
catalog[channel.Group] = {
|
||
title: channel.Group,
|
||
setEpgId: false,
|
||
channels: []
|
||
};
|
||
lists[object.id].groups.push({
|
||
title: channel.Group,
|
||
key: channel.Group
|
||
});
|
||
}
|
||
channel['Title'] = channel['Title'].replace(/\s+(\s|ⓢ|ⓖ|ⓥ|ⓞ|Ⓢ|Ⓖ|Ⓥ|Ⓞ)/g, ' ').trim();
|
||
catalog[channel.Group].channels.push(channel);
|
||
var favI = favorite.indexOf(favID(channel.Title));
|
||
if (favI !== -1) {
|
||
catalog[''].channels[favI] = channel;
|
||
}
|
||
}
|
||
}
|
||
for (i = 0; i < lists[object.id].groups.length; i++) {
|
||
var group = lists[object.id].groups[i];
|
||
group.title += ' [' + catalog[group.key].channels.length + ']';
|
||
}
|
||
for (i = 0; i < favorite.length; i++) {
|
||
if (!catalog[''].channels[i]) {
|
||
catalog[''].channels[i] = {
|
||
ChNum: -1,
|
||
Title: "#" + favorite[i],
|
||
isYouTube: false,
|
||
Url: Lampa.Utils.protocol() + 'epg.rootu.top/empty/_.m3u8',
|
||
Group: '',
|
||
Options: {},
|
||
'tvg-logo': Lampa.Utils.protocol() + 'epg.rootu.top/empty/_.gif'
|
||
};
|
||
}
|
||
}
|
||
_this.build(catalog);
|
||
}
|
||
var listUrl = prepareUrl(object.url);
|
||
network.native(
|
||
listUrl,
|
||
compileList,
|
||
function () {
|
||
// Возможно ошибка из-за CORS пробуем silent запрос через CORS прокси
|
||
network.silent(
|
||
Lampa.Utils.protocol() + 'epg.rootu.top/cors.php?url=' + encodeURIComponent(listUrl)
|
||
+ '&uid=' + utils.uid() + '&sig=' + generateSigForString(listUrl),
|
||
compileList,
|
||
emptyResult,
|
||
false,
|
||
{dataType: 'text'}
|
||
);
|
||
},
|
||
false,
|
||
{dataType: 'text'}
|
||
)
|
||
}
|
||
return this.render();
|
||
};
|
||
function epgUpdateData(epgId) {
|
||
var lt = Math.floor(unixtime()/60);
|
||
var t = Math.floor(lt/60), ed, ede;
|
||
if (!!EPG[epgId] && t >= EPG[epgId][0] && t <= EPG[epgId][1]) {
|
||
ed = EPG[epgId][2];
|
||
if (!ed || !ed.length || ed.length >= 3) return;
|
||
ede = ed[ed.length - 1];
|
||
lt = (ede[0] + ede[1]);
|
||
var t2 = Math.floor(lt / 60);
|
||
if ((t2 - t) > 6 || t2 <= EPG[epgId][1]) return;
|
||
t = t2;
|
||
}
|
||
if (!!EPG[epgId]) {
|
||
ed = EPG[epgId][2];
|
||
if (typeof ed !== 'object') return;
|
||
if (ed.length) {
|
||
ede = ed[ed.length - 1];
|
||
lt = (ede[0] + ede[1]);
|
||
var t3 = Math.max(t, Math.floor(lt / 60));
|
||
if (t < t3 && ed.length >= 3) return;
|
||
t = t3;
|
||
}
|
||
EPG[epgId][1] = t;
|
||
} else {
|
||
EPG[epgId] = [t, t, false];
|
||
}
|
||
var success = function(epg) {
|
||
if (EPG[epgId][2] === false) EPG[epgId][2] = [];
|
||
for (var i = 0; i < epg.length; i++) {
|
||
if (lt < (epg[i][0] + epg[i][1])) {
|
||
EPG[epgId][2].push.apply(EPG[epgId][2], epg.slice(i));
|
||
break;
|
||
}
|
||
}
|
||
setEpgSessCache(epgId + epgPath, EPG[epgId][2]);
|
||
epgRender(epgId);
|
||
};
|
||
var fail = function () {
|
||
if (EPG[epgId][2] === false) EPG[epgId][2] = [];
|
||
setEpgSessCache(epgId + epgPath, EPG[epgId][2]);
|
||
epgRender(epgId);
|
||
};
|
||
if (EPG[epgId][2] === false) {
|
||
var epg = getEpgSessCache(epgId + epgPath, lt);
|
||
if (!!epg) return success(epg);
|
||
}
|
||
network.silent(
|
||
Lampa.Utils.protocol() + 'epg.rootu.top/api' + epgPath + '/epg/' + epgId + '/hour/' + t,
|
||
success,
|
||
fail
|
||
);
|
||
}
|
||
function cardsEpgRender(cards) {
|
||
cards.filter('.js-epgNoRender[data-epg-id]').each(function(){epgRender($(this).attr('data-epg-id'))});
|
||
}
|
||
function epgRender(epgId) {
|
||
var epg = (EPG[epgId] || [0, 0, []])[2];
|
||
var card = body.find('.js-layer--visible[data-epg-id="' + epgId + '"]').removeClass('js-epgNoRender');
|
||
if (epg === false || !card.length) return;
|
||
var epgEl = card.find('.card__age');
|
||
if (!epgEl.length) return;
|
||
var t = Math.floor(unixtime() / 60), enableCardEpg = false, i = 0, e, p, cId, cIdEl;
|
||
while (epg.length && t >= (epg[0][0] + epg[0][1])) epg.shift();
|
||
if (epg.length) {
|
||
e = epg[0];
|
||
if (t >= e[0] && t < (e[0] + e[1])) {
|
||
i++;
|
||
enableCardEpg = true;
|
||
p = Math.round((unixtime() - e[0] * 60) * 100 / (e[1] * 60 || 60));
|
||
cId = e[0] + '_' +epgEl.length;
|
||
cIdEl = epgEl.data('cId') || '';
|
||
if (cIdEl !== cId) {
|
||
epgEl.data('cId', cId);
|
||
epgEl.data('progress', p);
|
||
epgEl.find('.js-epgTitle').text(e[2]);
|
||
epgEl.find('.js-epgProgress').css('width', p + '%');
|
||
epgEl.show();
|
||
} else if (epgEl.data('progress') !== p) {
|
||
epgEl.data('progress', p);
|
||
epgEl.find('.js-epgProgress').css('width', p + '%');
|
||
}
|
||
}
|
||
}
|
||
if (epgIdCurrent === epgId) {
|
||
var ec = $('#' + plugin.component + '_epg');
|
||
var epgNow = ec.find('.js-epgNow');
|
||
cId = epgId + '_' + epg.length + (epg.length ? '_' + epg[0][0] : '');
|
||
cIdEl = ec.data('cId') || '';
|
||
if (cIdEl !== cId) {
|
||
ec.data('cId', cId);
|
||
var epgAfter = ec.find('.js-epgAfter');
|
||
if (i) {
|
||
var slt = toLocaleTimeString(e[0] * 60000);
|
||
var elt = toLocaleTimeString((e[0] + e[1]) * 60000);
|
||
epgNow.data('progress', p);
|
||
epgNow.find('.js-epgProgress').css('width', p + '%');
|
||
epgNow.find('.js-epgTime').text(slt);
|
||
epgNow.find('.js-epgTitle').text(e[2]);
|
||
var desc = e[3] ? ('<p>' + encoder.text(e[3]).html() + '</p>') : '';
|
||
epgNow.find('.js-epgDesc').html(desc.replace(/\n/g,'</p><p>'));
|
||
epgNow.show();
|
||
info.find('.info__create').html(slt + '-' + elt + ' • ' + encoder.text(e[2]).html());
|
||
} else {
|
||
info.find('.info__create').html('');
|
||
epgNow.hide();
|
||
}
|
||
if (epg.length > i) {
|
||
var list = epgAfter.find('.js-epgList');
|
||
list.empty();
|
||
var iEnd = Math.min(epg.length, 8);
|
||
for (; i < iEnd; i++) {
|
||
e = epg[i];
|
||
var item = epgItemTeplate.clone();
|
||
item.find('.js-epgTime').text(toLocaleTimeString(e[0] * 60000));
|
||
item.find('.js-epgTitle').text(e[2]);
|
||
list.append(item);
|
||
}
|
||
epgAfter.show();
|
||
} else {
|
||
epgAfter.hide();
|
||
}
|
||
} else if (i && epgNow.data('progress') !== p) {
|
||
epgNow.data('progress', p);
|
||
epgNow.find('.js-epgProgress').css('width', p + '%');
|
||
}
|
||
}
|
||
if (!enableCardEpg) epgEl.hide();
|
||
if (epg.length < 3) epgUpdateData(epgId);
|
||
}
|
||
this.append = function (data) {
|
||
var catEpg = [];
|
||
var chIndex = 0;
|
||
var _this2 = this;
|
||
var lazyLoadImg = ('loading' in HTMLImageElement.prototype);
|
||
layerCards = null;
|
||
var bulkFn = bulkWrapper(function (channel) {
|
||
var chI = chIndex++;
|
||
var card = Lampa.Template.get('card', {
|
||
title: channel.Title,
|
||
release_year: ''
|
||
});
|
||
card.addClass('card--collection')
|
||
.removeClass('layer--visible')
|
||
.removeClass('layer--render')
|
||
.addClass('js-layer--hidden')
|
||
;
|
||
if (chI < layerCnt) card.addClass('js-layer--visible');
|
||
var img = card.find('.card__img')[0];
|
||
if (lazyLoadImg) img.loading = (chI < 18 ? 'eager' : 'lazy');
|
||
img.onload = function () {
|
||
card.addClass('card--loaded');
|
||
};
|
||
img.onerror = function (e) {
|
||
var name = channel.Title
|
||
.replace(/\s+\(([+-]?\d+)\)/, ' $1').replace(/[-.()\s]+/g, ' ').replace(/(^|\s+)(TV|ТВ)(\s+|$)/i, '$3');
|
||
var fl = name.replace(/\s+/g, '').length > 5
|
||
? name.split(/\s+/).map(function(v) {return v.match(/^(\+?\d+|[UF]?HD|4K)$/i) ? v : v.substring(0,1).toUpperCase()}).join('').substring(0,6)
|
||
: name.replace(/\s+/g, '')
|
||
;
|
||
fl = fl.replace(/([UF]?HD|4k|\+\d+)$/i, '<sup>$1</sup>');
|
||
var hex = (Lampa.Utils.hash(channel.Title) * 1).toString(16);
|
||
while (hex.length < 6) hex+=hex;
|
||
hex = hex.substring(0,6);
|
||
var r = parseInt(hex.slice(0, 2), 16),
|
||
g = parseInt(hex.slice(2, 4), 16),
|
||
b = parseInt(hex.slice(4, 6), 16);
|
||
var hexText = (r * 0.299 + g * 0.587 + b * 0.114) > 186 ? '#000000' : '#FFFFFF';
|
||
card.find('.card__img').replaceWith('<div class="card__img">' + fl + '</div>');
|
||
card.find('.card__view').css({'background-color': '#' + hex, 'color': hexText});
|
||
channel['tvg-logo'] = '';
|
||
card.addClass('card--loaded');
|
||
};
|
||
if (channel['tvg-logo']) img.src = channel['tvg-logo'];else img.onerror();
|
||
var favIcon = $('<div class="card__icon icon--book hide"></div>');
|
||
card.find('.card__icons-inner').append(favIcon);
|
||
var tvgDay = parseInt(
|
||
channel['catchup-days'] || channel['tvg-rec'] || channel['timeshift']
|
||
|| listCfg['catchup-days'] || listCfg['tvg-rec'] || listCfg['timeshift']
|
||
|| '0' // todo вынести в настройки?
|
||
);
|
||
if (parseInt('catchup-enable' in channel ? channel['catchup-enable'] : tvgDay) > 0) {
|
||
card.find('.card__icons-inner').append('<div class="card__icon icon--timeshift"></div>');
|
||
if (tvgDay === 0) tvgDay = 1;
|
||
} else {
|
||
tvgDay = 0;
|
||
}
|
||
card.find('.card__age').html('<div class="card__epg-progress js-epgProgress"></div><div class="card__epg-title js-epgTitle"></div>')
|
||
if (object.currentGroup !== '' && favorite.indexOf(favID(channel.Title)) !== -1) {
|
||
favIcon.toggleClass('hide', false);
|
||
}
|
||
card.playThis = function(){
|
||
layerFocusI = chI;
|
||
var video = {
|
||
title: channel.Title,
|
||
url: prepareUrl(channel.Url),
|
||
thumbnail: channel['tvg-logo'],
|
||
plugin: plugin.component,
|
||
iptv: true,
|
||
tv: true
|
||
};
|
||
var playlist = [];
|
||
var playlistForExtrnalPlayer = [];
|
||
var i = 0;
|
||
data.forEach(function (elem) {
|
||
// Изменяем порядок для внешнего плейлиста (плейлист начинается с текущего элемента)
|
||
var j = i < chI ? data.length - chI + i : i - chI;
|
||
var videoUrl = i === chI ? video.url : prepareUrl(elem.Url);
|
||
playlistForExtrnalPlayer[j] = {
|
||
title: elem.Title,
|
||
url: videoUrl,
|
||
thumbnail: elem['tvg-logo'],
|
||
iptv: true,
|
||
tv: true
|
||
};
|
||
playlist.push({
|
||
title: ++i + '. ' + elem.Title,
|
||
url: videoUrl,
|
||
thumbnail: elem['tvg-logo'],
|
||
plugin: plugin.component,
|
||
iptv: true,
|
||
tv: true
|
||
});
|
||
});
|
||
video['playlist'] = playlistForExtrnalPlayer;
|
||
Lampa.Keypad.listener.destroy()
|
||
Lampa.Keypad.listener.follow('keydown', keydown.bind(_this2));
|
||
Lampa.Player.runas && Lampa.Player.runas(Lampa.Storage.field('player_iptv'));
|
||
Lampa.Player.play(video);
|
||
Lampa.Player.runas && Lampa.Player.runas(Lampa.Storage.field('player_iptv'));
|
||
Lampa.Player.playlist(playlist);
|
||
};
|
||
card.on('hover:focus hover:hover touchstart', function (event) {
|
||
layerFocusI = chI;
|
||
if (event.type && event.type !== 'touchstart' && event.type !== 'hover:hover') scroll.update(card, true);
|
||
last = card[0];
|
||
// info.find('.info__title-original').text(channel['Group']);
|
||
info.find('.info__title').text(channel.Title);
|
||
var ec = $('#' + plugin.component + '_epg');
|
||
ec.find('.js-epgChannel').text(channel.Title);
|
||
if (!channel['epgId']) {
|
||
info.find('.info__create').empty();
|
||
epgIdCurrent = '';
|
||
ec.find('.js-epgNow').hide();
|
||
ec.find('.js-epgAfter').hide();
|
||
}
|
||
else {
|
||
epgIdCurrent = channel['epgId'];
|
||
epgRender(channel['epgId']);
|
||
}
|
||
}).on('hover:enter', function() {
|
||
getStorage('launch_menu', 'false') ? card.trigger('hover:long') : card.playThis();
|
||
}).on('hover:long', function () {
|
||
layerFocusI = chI;
|
||
var favI = favorite.indexOf(favID(channel.Title));
|
||
var isFavoriteGroup = object.currentGroup === '';
|
||
var menu = [];
|
||
|
||
|
||
if (getStorage('launch_menu', 'false')) {
|
||
menu.push({
|
||
title: Lampa.Lang.translate('player_lauch'),
|
||
startPlay: true
|
||
});
|
||
}
|
||
if (tvgDay > 0) {
|
||
if (!!channel['epgId'] && !!EPG[channel['epgId']] && EPG[channel['epgId']][2].length) {
|
||
menu.push({
|
||
title: 'Смотреть сначала',
|
||
restartProgram: true
|
||
});
|
||
}
|
||
menu.push({
|
||
title: 'Архив',
|
||
archive: true
|
||
});
|
||
}
|
||
if (!!channel['epgId'] && !!EPG[channel['epgId']] && EPG[channel['epgId']][2].length) {
|
||
menu.push({
|
||
title: Lampa.Lang.translate('search_start'),
|
||
search: EPG[channel['epgId']][2][0][2]
|
||
});
|
||
}
|
||
menu.push({
|
||
title: favI === -1 ? langGet('favorites_add') : langGet('favorites_del'),
|
||
favToggle: true
|
||
});
|
||
if (isFavoriteGroup && favorite.length) {
|
||
if (favI !== 0) {
|
||
menu.push({
|
||
title: langGet('favorites_move_top'),
|
||
favMove: true,
|
||
i: 0
|
||
});
|
||
menu.push({
|
||
title: langGet('favorites_move_up'),
|
||
favMove: true,
|
||
i: favI - 1
|
||
});
|
||
}
|
||
if ((favI + 1) !== favorite.length) {
|
||
menu.push({
|
||
title: langGet('favorites_move_down'),
|
||
favMove: true,
|
||
i: favI + 1
|
||
});
|
||
menu.push({
|
||
title: langGet('favorites_move_end'),
|
||
favMove: true,
|
||
i: favorite.length - 1
|
||
});
|
||
}
|
||
menu.push({
|
||
title: langGet('favorites_clear'),
|
||
favClear: true
|
||
});
|
||
}
|
||
menu.push({
|
||
title: getStorage('epg', 'false') ? langGet('epg_off') : langGet('epg_on'),
|
||
epgToggle: true
|
||
});
|
||
Lampa.Select.show({
|
||
title: Lampa.Lang.translate('title_action'),
|
||
items: menu,
|
||
onSelect: function (sel) {
|
||
if (!!sel.startPlay) {
|
||
card.playThis();
|
||
} else if (!!sel.archive) {
|
||
var t = unixtime();
|
||
var m = Math.floor(t/60);
|
||
var d = Math.floor(t/86400);
|
||
var di = (tvgDay + 1), load = di;
|
||
var ms = m - tvgDay * 1440;
|
||
var tvgData = [];
|
||
var playlist = [];
|
||
var playlistMenu = [];
|
||
var archiveMenu = [];
|
||
var ps = 0;
|
||
var prevDate = '';
|
||
var d0 = toLocaleDateString(unixtime() * 1e3);
|
||
var d1 = toLocaleDateString((unixtime() - 86400) * 1e3);
|
||
var d2 = toLocaleDateString((unixtime() - 2 * 86400) * 1e3);
|
||
var txtD = {};
|
||
txtD[d0] = 'Сегодня - ' + d0;
|
||
txtD[d1] = 'Вчера - ' + d1;
|
||
txtD[d2] = 'Позавчера - ' + d2;
|
||
var onEpgLoad = function() {
|
||
if (--load) return;
|
||
for (var i=tvgData.length - 1; i >= 0; i--) {
|
||
if (tvgData[i].length === 0) {
|
||
var dt = (d - i) * 1440;
|
||
for (var dm = 0; dm < 1440; dm+=30)
|
||
tvgData[i].push([dt + dm, 30, toLocaleDateString((dt + dm) * 6e4), '']);
|
||
}
|
||
for (var j=0; j < tvgData[i].length; j++) {
|
||
var epg = tvgData[i][j];
|
||
if (epg[0] === ps || epg[0] > m || epg[0] + epg[1] < ms) continue;
|
||
ps = epg[0];
|
||
var url = catchupUrl(
|
||
channel.Url,
|
||
(channel['catchup'] || channel['catchup-type'] || listCfg['catchup'] || listCfg['catchup-type']),
|
||
(channel['catchup-source'] || listCfg['catchup-source'])
|
||
);
|
||
var item = {
|
||
title: toLocaleTimeString(epg[0] * 6e4) + ' - ' + epg[2],
|
||
url: prepareUrl(url, epg),
|
||
catchupUrl: url,
|
||
plugin: plugin.component,
|
||
epg: epg
|
||
};
|
||
var newDate = toLocaleDateString(epg[0] * 6e4);
|
||
newDate = txtD[newDate] || newDate;
|
||
if (newDate !== prevDate) {
|
||
if (prevDate) {
|
||
archiveMenu.unshift({
|
||
title: prevDate,
|
||
separator: true
|
||
});
|
||
}
|
||
playlistMenu.push({
|
||
title: newDate,
|
||
separator: true,
|
||
plugin: plugin.component,
|
||
url: item.url
|
||
});
|
||
prevDate = newDate;
|
||
}
|
||
archiveMenu.unshift(item);
|
||
playlistMenu.push(item);
|
||
playlist.push(item);
|
||
}
|
||
}
|
||
if (prevDate) {
|
||
archiveMenu.unshift({
|
||
title: prevDate,
|
||
separator: true
|
||
});
|
||
}
|
||
tvgData = [];
|
||
Lampa.Select.show({
|
||
title: 'Архив',
|
||
items: archiveMenu,
|
||
onSelect: function (sel) {
|
||
console.log(plugin.name, 'catchupUrl: ' + sel.catchupUrl, epg.slice(0,2));
|
||
var video = {
|
||
title: sel.title,
|
||
url: sel.url,
|
||
iptv: true,
|
||
playlist: playlist
|
||
}
|
||
Lampa.Controller.toggle('content');
|
||
Lampa.Player.runas && Lampa.Player.runas(Lampa.Storage.field('player_iptv'));
|
||
Lampa.Player.play(video);
|
||
Lampa.Player.runas && Lampa.Player.runas(Lampa.Storage.field('player_iptv'));
|
||
Lampa.Player.playlist(playlistMenu);
|
||
},
|
||
onBack: function () {
|
||
Lampa.Controller.toggle('content');
|
||
}
|
||
})
|
||
};
|
||
while (di--) {
|
||
tvgData[di] = [];
|
||
(function() {
|
||
var dd = di;
|
||
networkSilentSessCache(Lampa.Utils.protocol() + 'epg.rootu.top/api' + epgPath + '/epg/' + channel['epgId'] + '/day/' + (d - dd) ,
|
||
function (data) {
|
||
tvgData[dd] = data;
|
||
onEpgLoad()
|
||
},
|
||
onEpgLoad
|
||
);
|
||
})();
|
||
}
|
||
} else if (!!sel.search) {
|
||
var search = sel.search
|
||
.replace(/^«([^»]+)».*$/, '$1')
|
||
.replace(/^"([^"]+)".*$/, '$1')
|
||
.replace(/\s*\((19\d\d|20[01]\d|202[0-4])\)\s*(\*\s.+)?$/, '')
|
||
.replace(/[.,]\s*(\d+(-й)?\s+(с-н|сезон)|(с-н|сезон)\s+\d+|[s][-.\s]*\d+(-й)?)?[-.,\s]*(\d+(-\d+|-я)?\s*(сери.|эпизоды?|episode|[cс]|ep?)\.?|(сери.|эпизоды?|episode|[cс]|ep?)[-.]?\s*\d+).*$/i,'')
|
||
.replace(/\s*(\d+(-й)?\s+(с-н|сезон)|(с-н|сезон)\s+\d+|[s][-.\s]*\d+(-й)?)?[-.,\s]*(\d+(-\d+|-я)?\s*(сери.|эпизоды?|episode|[cс]|ep?)\.?|(сери.|эпизоды?|episode|[cс]|ep?)[-.]?\s*\d+)\.?/i,'')
|
||
|
||
.replace(/\.\s+Дайджест\s*$/i, '')
|
||
.replace(/\.?\s*\(([cCсСeE](ерия|pisode)?[-.]?\s*\d+|\d+(-[^)\s]+)?\s+[Сс]ерия)\)/,'')
|
||
|
||
.replace(/\.[^.:]+:\s*[Чч](асть|\.)\s+\d+\S*$/,'')
|
||
.replace(/\.\s*Сборник\s+\d+\S*\s*$/i,'')
|
||
.replace(/\s*[\[(]?(\d|1\d|2[0-5])\+[\])]?[.\s]*$/, '')
|
||
.replace(/\s*(\(\)|\[])/, '')
|
||
;
|
||
// Lampa.Controller.toContent();
|
||
Lampa.Search.open({input: search});
|
||
} else if (!!sel.restartProgram) {
|
||
var epg = EPG[channel['epgId']][2][0];
|
||
var type = (channel['catchup'] || channel['catchup-type'] || listCfg['catchup'] || listCfg['catchup-type'] || '');
|
||
var url = catchupUrl(
|
||
channel.Url,
|
||
type,
|
||
(channel['catchup-source'] || listCfg['catchup-source'])
|
||
);
|
||
var flussonic = type.search(/^flussonic/i) === 0;
|
||
if (flussonic) {
|
||
url = url.replace('${(d)S}', 'now');
|
||
}
|
||
console.log(plugin.name, 'catchupUrl: ' + url, epg.slice(0,2));
|
||
var video = {
|
||
title: channel.Title,
|
||
url: prepareUrl(url, epg),
|
||
plugin: plugin.component,
|
||
catchupUrl: url,
|
||
iptv: true,
|
||
epg: epg
|
||
}
|
||
if (flussonic) video['timeline'] = {
|
||
time: 11,
|
||
percent: 0,
|
||
handler: function(){},
|
||
//hash: '',
|
||
duration: (epg[1] * 60)
|
||
};
|
||
Lampa.Controller.toggle('content');
|
||
Lampa.Player.runas && Lampa.Player.runas(Lampa.Storage.field('player_iptv'));
|
||
Lampa.Player.play(video);//Lampa.PlayerVideo.to(0)
|
||
Lampa.Player.runas && Lampa.Player.runas(Lampa.Storage.field('player_iptv'));
|
||
} else if (!!sel.epgToggle) {
|
||
var isView = !getStorage('epg', false);
|
||
setStorage('epg', isView);
|
||
epgListView(isView);
|
||
Lampa.Controller.toggle('content');
|
||
} else {
|
||
var favGroup = lists[object.id].groups[0];
|
||
if (!!sel.favToggle) {
|
||
if (favI === -1) {
|
||
favI = favorite.length
|
||
favorite[favI] = favID(channel.Title);
|
||
catalog[favGroup.key].channels[favI] = channel;
|
||
} else {
|
||
favorite.splice(favI, 1);
|
||
catalog[favGroup.key].channels.splice(favI, 1);
|
||
}
|
||
} else if (!!sel.favClear) {
|
||
favorite = [];
|
||
catalog[favGroup.key].channels = [];
|
||
} else if (!!sel.favMove) {
|
||
favorite.splice(favI, 1);
|
||
favorite.splice(sel.i, 0, favID(channel.Title));
|
||
catalog[favGroup.key].channels.splice(favI, 1);
|
||
catalog[favGroup.key].channels.splice(sel.i, 0, channel);
|
||
}
|
||
setStorage('favorite' + object.id, favorite);
|
||
favGroup.title = catalog[favGroup.key].title
|
||
+ ' [' + catalog[favGroup.key].channels.length + ']';
|
||
if (isFavoriteGroup) {
|
||
Lampa.Activity.replace(Lampa.Arrays.clone(lists[object.id].activity));
|
||
} else {
|
||
favIcon.toggleClass('hide', favorite.indexOf(favID(channel.Title)) === -1);
|
||
Lampa.Controller.toggle('content');
|
||
}
|
||
}
|
||
},
|
||
onBack: function () {
|
||
Lampa.Controller.toggle('content');
|
||
}
|
||
});
|
||
});
|
||
body.append(card);
|
||
if (!!channel['epgId']) {
|
||
card.attr('data-epg-id', channel['epgId']).addClass('js-epgNoRender');
|
||
epgRender(channel['epgId']);
|
||
}
|
||
},
|
||
{
|
||
bulk: 18,
|
||
onEnd: function (last, total, left) {
|
||
// body.find('.layer--render').removeClass('layer--render');
|
||
_this2.activity.loader(false);
|
||
_this2.activity.toggle();
|
||
if (chIndex > layerCnt) {
|
||
layerFocusI = 0;
|
||
layerCards = body.find('.js-layer--hidden');
|
||
}
|
||
// Lampa.Layer.visible(scroll.render(true));
|
||
}
|
||
});
|
||
data.forEach(function (channel) {
|
||
bulkFn(channel);
|
||
if (!!channel['epgId'] && catEpg.indexOf(channel['epgId']) === -1) catEpg.push(channel['epgId']);
|
||
});
|
||
// var catEpgString = catEpg.sort(function(a,b){return a-b}).join('-');
|
||
// var catEpgHash = utils.hash36(catEpgString);
|
||
// console.log('Epg', catEpgHash, catEpgString, data);
|
||
};
|
||
function setEpgId(channelGroup) {
|
||
if (channelGroup.setEpgId || !channelGroup.channels || !listCfg['epgApiChUrl']) return;
|
||
var chIDs = {id2epg: {}, piconUrl: '', id2picon: []}, i=0, channel;
|
||
networkSilentSessCache(listCfg['epgApiChUrl'], function(d){
|
||
chIDs = d;
|
||
if (!chIDs['id2epg']) chIDs['id2epg'] = {};
|
||
epgPath = !chIDs['epgPath'] ? '' : ('/' + chIDs['epgPath']);
|
||
});
|
||
var chShortName = function(chName){
|
||
return chName
|
||
.toLowerCase()
|
||
.replace(/\s+\(архив\)$/, '')
|
||
.replace(/\s+\((\+\d+)\)/g, ' $1')
|
||
.replace(/^телеканал\s+/, '')
|
||
.replace(/([!\s.,()–-]+|ⓢ|ⓖ|ⓥ|ⓞ|Ⓢ|Ⓖ|Ⓥ|Ⓞ)/g, ' ').trim()
|
||
.replace(/\s(канал|тв)(\s.+|\s*)$/, '$2')
|
||
.replace(/\s(50|orig|original)$/, '')
|
||
.replace(/\s(\d+)/g, '$1')
|
||
;
|
||
};
|
||
var trW = {"ё":"e","у":"y","к":"k","е":"e","н":"h","ш":"w","з":"3","х":"x","ы":"bl","в":"b","а":"a","р":"p","о":"o","ч":"4","с":"c","м":"m","т":"t","ь":"b","б":"6"};
|
||
var trName = function(word) {
|
||
return word.split('').map(function (char) {
|
||
return trW[char] || char;
|
||
}).join("");
|
||
};
|
||
var epgIdByName = function(v, find, epgId) {
|
||
var n = chShortName(v), fw, key;
|
||
if (n === '' || (!chIDs[n[0]] && !find)) return 0;
|
||
fw = n[0];
|
||
if (!!chIDs[fw]) {
|
||
if (!!chIDs[fw][n]) return chIDs[fw][n];
|
||
n = trName(n);
|
||
if (!!chIDs[fw][n]) return chIDs[fw][n];
|
||
if (find) {
|
||
for (key in chIDs[fw]) {
|
||
if (chIDs[fw][key] == epgId) {
|
||
return epgId;
|
||
} else if (n === trName(key)) {
|
||
return chIDs[fw][key];
|
||
}
|
||
}
|
||
}
|
||
}
|
||
if (n[0] !== fw && !!chIDs[n[0]]) {
|
||
fw = n[0];
|
||
if (!!chIDs[fw][n]) return chIDs[fw][n];
|
||
if (find) {
|
||
for (key in chIDs[fw]) {
|
||
if (chIDs[fw][key] == epgId) {
|
||
return epgId;
|
||
} else if (n === trName(key)) {
|
||
return chIDs[fw][key];
|
||
}
|
||
}
|
||
}
|
||
} else if (find) {
|
||
for(var keyW in trW) {
|
||
if (trW[keyW] === fw && !!chIDs[keyW]) {
|
||
for (key in chIDs[keyW]) {
|
||
if (chIDs[keyW][key] == epgId) {
|
||
return epgId;
|
||
} else if (n === trName(key)){
|
||
return chIDs[keyW][key];
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return 0;
|
||
};
|
||
for (;i < channelGroup.channels.length;i++) {
|
||
channel = channelGroup.channels[i];
|
||
channel['epgId'] = (listCfg['isEpgIt999'] || listCfg['isYosso'])
|
||
? (channel['tvg-id'] && /^\d{1,4}$/.test(channel['tvg-id']) ? channel['tvg-id'] : epgIdByName(channel['Title'], true, channel['tvg-id']))
|
||
: (chIDs.id2epg[channel['tvg-id'] || ''] || epgIdByName(channel['Title'], isSNG, channel['tvg-id']) || channel['tvg-id']);
|
||
/*if (isSNG && !/^\d+$/.test(channel['epgId'])) {
|
||
channel['epgId'] = epgIdByName(channel['Title'], isSNG) || channel['epgId'];
|
||
}*/
|
||
if (!channel['tvg-logo'] && channel['epgId'] && !!chIDs.piconUrl) {
|
||
channel['tvg-logo'] = Lampa.Utils.protocol() + chIDs.piconUrl.replace('{picon}', (chIDs.id2picon && chIDs.id2picon[channel['epgId']]) ? chIDs.id2picon[channel['epgId']] : channel['epgId']);
|
||
}
|
||
if (!channel['tvg-logo']) {
|
||
if (channel['epgId'] && (listCfg['isEpgIt999'] || isSNG) && /^\d{1,4}$/.test(channel['epgId'])) {
|
||
channel['tvg-logo'] = Lampa.Utils.protocol() + 'epg.one/img2/' + channel['epgId'] + '.png'
|
||
} else if (isSNG && !/^Ch \d+$/.test(channel['Title'])) {
|
||
channel['tvg-logo'] = Lampa.Utils.protocol() + 'epg.rootu.top/picon/'
|
||
+ encodeURIComponent(channel['Title']) + '.png';
|
||
}
|
||
}
|
||
}
|
||
}
|
||
this.build = function (catalog) {
|
||
var channelGroup = !catalog[object.currentGroup]
|
||
? (lists[object.id].groups.length > 1 && !!catalog[lists[object.id].groups[1].key]
|
||
? catalog[lists[object.id].groups[1].key]
|
||
: {'channels': []}
|
||
)
|
||
: catalog[object.currentGroup];
|
||
var _this2 = this;
|
||
Lampa.Background.change();
|
||
Lampa.Template.add(plugin.component + '_button_category', "<style>@media screen and (max-width: 2560px) {." + plugin.component + " .card--collection {width: 16.6%!important;}}@media screen and (max-width: 800px) {." + plugin.component + " .card--collection {width: 24.6%!important;}}@media screen and (max-width: 500px) {." + plugin.component + " .card--collection {width: 33.3%!important;}}</style><div class=\"full-start__button selector view--category\"><svg style=\"enable-background:new 0 0 512 512;\" version=\"1.1\" viewBox=\"0 0 24 24\" xml:space=\"preserve\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\"><g id=\"info\"/><g id=\"icons\"><g id=\"menu\"><path d=\"M20,10H4c-1.1,0-2,0.9-2,2c0,1.1,0.9,2,2,2h16c1.1,0,2-0.9,2-2C22,10.9,21.1,10,20,10z\" fill=\"currentColor\"/><path d=\"M4,8h12c1.1,0,2-0.9,2-2c0-1.1-0.9-2-2-2H4C2.9,4,2,4.9,2,6C2,7.1,2.9,8,4,8z\" fill=\"currentColor\"/><path d=\"M16,16H4c-1.1,0-2,0.9-2,2c0,1.1,0.9,2,2,2h12c1.1,0,2-0.9,2-2C18,16.9,17.1,16,16,16z\" fill=\"currentColor\"/></g></g></svg><span>" + langGet('categories') + "</span>\n </div>");
|
||
Lampa.Template.add(plugin.component + '_info_radio', '<div class="info layer--width"><div class="info__left"><div class="info__title"></div><div class="info__title-original"></div><div class="info__create"></div></div><div class="info__right" style="display: flex !important;"> <div id="stantion_filtr"></div></div></div>');
|
||
var btn = Lampa.Template.get(plugin.component + '_button_category');
|
||
info = Lampa.Template.get(plugin.component + '_info_radio');
|
||
info.find('#stantion_filtr').append(btn);
|
||
info.find('.view--category').on('hover:enter hover:click', function () {
|
||
_this2.selectGroup();
|
||
});
|
||
info.find('.info__title-original').text(!catalog[object.currentGroup] ? '' : catalog[object.currentGroup].title);
|
||
info.find('.info__title').text('');
|
||
html.append(info.append());
|
||
if (channelGroup.channels.length) {
|
||
setEpgId(channelGroup);
|
||
scroll.render().addClass('layer--wheight').data('mheight', info);
|
||
html.append(scroll.render());
|
||
this.append(channelGroup.channels);
|
||
if (getStorage('epg', false)) {
|
||
scroll.render().css({float: "left", width: '70%'});
|
||
scroll.render().parent().append(epgTemplate);
|
||
}
|
||
scroll.append(body);
|
||
setStorage('last_catalog' + object.id, object.currentGroup ? object.currentGroup : '!!');
|
||
lists[object.id].activity.currentGroup = object.currentGroup;
|
||
} else {
|
||
var empty = new Lampa.Empty();
|
||
html.append(empty.render());
|
||
this.activity.loader(false);
|
||
Lampa.Controller.collectionSet(info);
|
||
Navigator.move('right');
|
||
}
|
||
};
|
||
this.selectGroup = function () {
|
||
var activity = Lampa.Arrays.clone(lists[object.id].activity);
|
||
var groups = Lampa.Arrays.clone(lists[object.id].groups).map(function(group){
|
||
group.selected = object.currentGroup === group.key;
|
||
return group;
|
||
});
|
||
Lampa.Select.show({
|
||
title: langGet('categories'),
|
||
items: groups,
|
||
onSelect: function(group) {
|
||
if (object.currentGroup !== group.key) {
|
||
activity.currentGroup = group.key;
|
||
Lampa.Activity.replace(activity);
|
||
} else {
|
||
Lampa.Player.opened() || Lampa.Controller.toggle('content');
|
||
}
|
||
},
|
||
onBack: function() {
|
||
Lampa.Player.opened() || Lampa.Controller.toggle('content');
|
||
}
|
||
});
|
||
};
|
||
this.start = function () {
|
||
if (Lampa.Activity.active().activity !== this.activity) return; //обязательно, иначе наблюдается баг, активность создается но не стартует, в то время как компонент загружается и стартует самого себя.
|
||
var _this = this;
|
||
Lampa.Controller.add('content', {
|
||
toggle: function toggle() {
|
||
Lampa.Controller.collectionSet(scroll.render());
|
||
Lampa.Controller.collectionFocus(last || false, scroll.render());
|
||
},
|
||
left: function left() {
|
||
if (Navigator.canmove('left')) Navigator.move('left');
|
||
else Lampa.Controller.toggle('menu');
|
||
},
|
||
right: function right() {
|
||
if (Navigator.canmove('right')) Navigator.move('right');
|
||
else _this.selectGroup();
|
||
},
|
||
up: function up() {
|
||
if (Navigator.canmove('up')) {
|
||
Navigator.move('up');
|
||
} else {
|
||
if (!info.find('.view--category').hasClass('focus')) {
|
||
Lampa.Controller.collectionSet(info);
|
||
Navigator.move('right')
|
||
} else Lampa.Controller.toggle('head');
|
||
}
|
||
},
|
||
down: function down() {
|
||
if (Navigator.canmove('down')) Navigator.move('down');
|
||
else if (info.find('.view--category').hasClass('focus')) {
|
||
Lampa.Controller.toggle('content');
|
||
}
|
||
},
|
||
back: function back() {
|
||
Lampa.Activity.backward();
|
||
}
|
||
});
|
||
Lampa.Controller.toggle('content');
|
||
};
|
||
this.pause = function () {
|
||
Lampa.Player.runas && Lampa.Player.runas('');
|
||
};
|
||
this.stop = function () {
|
||
Lampa.Player.runas && Lampa.Player.runas('');
|
||
};
|
||
this.render = function () {
|
||
return html;
|
||
};
|
||
this.destroy = function () {
|
||
Lampa.Player.runas && Lampa.Player.runas('');
|
||
network.clear();
|
||
scroll.destroy();
|
||
if (info) info.remove();
|
||
layerCards = null;
|
||
if (layerInterval) clearInterval(layerInterval);
|
||
if (epgInterval) clearInterval(epgInterval);
|
||
html.remove();
|
||
body.remove();
|
||
favorite = null;
|
||
network = null;
|
||
html = null;
|
||
body = null;
|
||
info = null;
|
||
};
|
||
}
|
||
|
||
if (!Lampa.Lang) {
|
||
var lang_data = {};
|
||
Lampa.Lang = {
|
||
add: function add(data) {
|
||
lang_data = data;
|
||
},
|
||
translate: function translate(key) {
|
||
return lang_data[key] ? lang_data[key].ru : key;
|
||
}
|
||
};
|
||
}
|
||
var langData = {};
|
||
function langAdd(name, values) {
|
||
langData[plugin.component + '_' + name] = values;
|
||
}
|
||
function langGet(name) {
|
||
return Lampa.Lang.translate(plugin.component + '_' + name);
|
||
}
|
||
|
||
langAdd('max_ch_in_group',
|
||
{
|
||
ru: 'Количество каналов в категории',
|
||
uk: 'Кількість каналів у категорії',
|
||
be: 'Колькасць каналаў у катэгорыі',
|
||
en: 'Number of channels in category',
|
||
zh: '分类中的频道数量'
|
||
}
|
||
);
|
||
langAdd('max_ch_in_group_desc',
|
||
{
|
||
ru: 'Если количество превышено, категория разбивается на несколько. Уменьшите количество на слабых устройствах',
|
||
uk: 'Якщо кількість перевищена, категорія розбивається на кілька. Зменшіть кількість на слабких пристроях',
|
||
be: 'Калі колькасць перавышана, катэгорыя разбіваецца на некалькі. Паменшыце колькасць на слабых прыладах',
|
||
en: 'If the quantity is exceeded, it splits the category into several. Reduce the number on weak devices',
|
||
zh: '如果超出数量,则将分类拆分为多个。在弱设备上减少数量。'
|
||
}
|
||
);
|
||
langAdd('default_playlist',
|
||
{
|
||
ru: 'https://tsynik.github.io/tv.m3u',
|
||
uk: 'https://raw.githubusercontent.com/Free-TV/IPTV/master/playlist.m3u8',
|
||
be: 'https://raw.githubusercontent.com/Free-TV/IPTV/master/playlist.m3u8',
|
||
en: 'https://raw.githubusercontent.com/Free-TV/IPTV/master/playlist.m3u8',
|
||
zh: 'https://raw.iqiq.io/Free-TV/IPTV/master/playlist.m3u8'
|
||
}
|
||
);
|
||
langAdd('default_playlist_cat',
|
||
{
|
||
ru: 'Russia',
|
||
uk: 'Ukraine',
|
||
be: 'Belarus',
|
||
en: 'VOD Movies (EN)',
|
||
zh: 'China'
|
||
}
|
||
);
|
||
langAdd('settings_playlist_num_group',
|
||
{
|
||
ru: 'Плейлист ',
|
||
uk: 'Плейлист ',
|
||
be: 'Плэйліст ',
|
||
en: 'Playlist ',
|
||
zh: '播放列表 '
|
||
}
|
||
);
|
||
langAdd('settings_list_name',
|
||
{
|
||
ru: 'Название',
|
||
uk: 'Назва',
|
||
be: 'Назва',
|
||
en: 'Name',
|
||
zh: '名称'
|
||
}
|
||
);
|
||
langAdd('settings_list_name_desc',
|
||
{
|
||
ru: 'Название плейлиста в левом меню',
|
||
uk: 'Назва плейлиста у лівому меню',
|
||
be: 'Назва плэйліста ў левым меню',
|
||
en: 'Playlist name in the left menu',
|
||
zh: '左侧菜单中的播放列表名称'
|
||
}
|
||
);
|
||
langAdd('settings_list_url',
|
||
{
|
||
ru: 'URL-адрес',
|
||
uk: 'URL-адреса',
|
||
be: 'URL-адрас',
|
||
en: 'URL',
|
||
zh: '网址'
|
||
}
|
||
);
|
||
langAdd('settings_list_url_desc0',
|
||
{
|
||
ru: 'По умолчанию используется плейлист из проекта <i>https://github.com/Free-TV/IPTV</i><br>Вы можете заменить его на свой.',
|
||
uk: 'За замовчуванням використовується плейлист із проекту <i>https://github.com/Free-TV/IPTV</i><br>Ви можете замінити його на свій.',
|
||
be: 'Па змаўчанні выкарыстоўваецца плэйліст з праекта <i>https://github.com/Free-TV/IPTV</i><br> Вы можаце замяніць яго на свой.',
|
||
en: 'The default playlist is from the project <i>https://github.com/Free-TV/IPTV</i><br>You can replace it with your own.',
|
||
zh: '默认播放列表来自项目 <i>https://github.com/Free-TV/IPTV</i><br>您可以将其替换为您自己的。'
|
||
}
|
||
);
|
||
langAdd('settings_list_url_desc1',
|
||
{
|
||
ru: 'Вы можете добавить еще один плейлист здесь. Ссылки на плейлисты обычно заканчиваются на <i>.m3u</i> или <i>.m3u8</i>',
|
||
uk: 'Ви можете додати ще один плейлист суду. Посилання на плейлисти зазвичай закінчуються на <i>.m3u</i> або <i>.m3u8</i>',
|
||
be: 'Вы можаце дадаць яшчэ адзін плэйліст суда. Спасылкі на плэйлісты звычайна заканчваюцца на <i>.m3u</i> або <i>.m3u8</i>',
|
||
en: 'You can add another trial playlist. Playlist links usually end with <i>.m3u</i> or <i>.m3u8</i>',
|
||
zh: '您可以添加另一个播放列表。 播放列表链接通常以 <i>.m3u</i> 或 <i>.m3u8</i> 结尾'
|
||
}
|
||
);
|
||
langAdd('categories',
|
||
{
|
||
ru: 'Категории',
|
||
uk: 'Категорія',
|
||
be: 'Катэгорыя',
|
||
en: 'Categories',
|
||
zh: '分类'
|
||
}
|
||
);
|
||
langAdd('uid',
|
||
{
|
||
ru: 'UID',
|
||
uk: 'UID',
|
||
be: 'UID',
|
||
en: 'UID',
|
||
zh: 'UID'
|
||
}
|
||
);
|
||
langAdd('unique_id',
|
||
{
|
||
ru: 'уникальный идентификатор (нужен для некоторых ссылок на плейлисты)',
|
||
uk: 'унікальний ідентифікатор (необхідний для деяких посилань на списки відтворення)',
|
||
be: 'унікальны ідэнтыфікатар (неабходны для некаторых спасылак на спіс прайгравання)',
|
||
en: 'unique identifier (needed for some playlist links)',
|
||
zh: '唯一 ID(某些播放列表链接需要)'
|
||
}
|
||
);
|
||
langAdd('launch_menu',
|
||
{
|
||
ru: 'Запуск через меню',
|
||
uk: 'Запуск через меню',
|
||
be: 'Запуск праз меню',
|
||
en: 'Launch via menu',
|
||
zh: '通过菜单启动'
|
||
}
|
||
);
|
||
langAdd('favorites',
|
||
{
|
||
ru: 'Избранное',
|
||
uk: 'Вибране',
|
||
be: 'Выбранае',
|
||
en: 'Favorites',
|
||
zh: '收藏夹'
|
||
}
|
||
);
|
||
langAdd('favorites_add',
|
||
{
|
||
ru: 'Добавить в избранное',
|
||
uk: 'Додати в обране',
|
||
be: 'Дадаць у абранае',
|
||
en: 'Add to favorites',
|
||
zh: '添加到收藏夹'
|
||
}
|
||
);
|
||
langAdd('favorites_del',
|
||
{
|
||
ru: 'Удалить из избранного',
|
||
uk: 'Видалити з вибраного',
|
||
be: 'Выдаліць з абранага',
|
||
en: 'Remove from favorites',
|
||
zh: '从收藏夹中删除'
|
||
}
|
||
);
|
||
langAdd('favorites_clear',
|
||
{
|
||
ru: 'Очистить избранное',
|
||
uk: 'Очистити вибране',
|
||
be: 'Ачысціць выбранае',
|
||
en: 'Clear favorites',
|
||
zh: '清除收藏夹'
|
||
}
|
||
);
|
||
langAdd('favorites_move_top',
|
||
{
|
||
ru: 'В начало списка',
|
||
uk: 'На початок списку',
|
||
be: 'Да пачатку спісу',
|
||
en: 'To the top of the list',
|
||
zh: '到列表顶部'
|
||
}
|
||
);
|
||
langAdd('favorites_move_up',
|
||
{
|
||
ru: 'Сдвинуть вверх',
|
||
uk: 'Зрушити вгору',
|
||
be: 'Ссунуць уверх',
|
||
en: 'Move up',
|
||
zh: '上移'
|
||
}
|
||
);
|
||
langAdd('favorites_move_down',
|
||
{
|
||
ru: 'Сдвинуть вниз',
|
||
uk: 'Зрушити вниз',
|
||
be: 'Ссунуць уніз',
|
||
en: 'Move down',
|
||
zh: '下移'
|
||
}
|
||
);
|
||
langAdd('favorites_move_end',
|
||
{
|
||
ru: 'В конец списка',
|
||
uk: 'В кінець списку',
|
||
be: 'У канец спісу',
|
||
en: 'To the end of the list',
|
||
zh: '到列表末尾'
|
||
}
|
||
);
|
||
langAdd('epg_on',
|
||
{
|
||
ru: 'Включить телепрограмму',
|
||
uk: 'Увімкнути телепрограму',
|
||
be: 'Уключыць тэлепраграму',
|
||
en: 'TV Guide: On',
|
||
zh: '電視指南:開'
|
||
}
|
||
);
|
||
langAdd('epg_off',
|
||
{
|
||
ru: 'Отключить телепрограмму',
|
||
uk: 'Вимкнути телепрограму',
|
||
be: 'Адключыць тэлепраграму',
|
||
en: 'TV Guide: Off',
|
||
zh: '電視指南:關閉'
|
||
}
|
||
);
|
||
langAdd('epg_title',
|
||
{
|
||
ru: 'Телепрограмма',
|
||
uk: 'Телепрограма',
|
||
be: 'Тэлепраграма',
|
||
en: 'TV Guide',
|
||
zh: '電視指南'
|
||
}
|
||
);
|
||
langAdd('square_icons', {
|
||
ru: 'Квадратные лого каналов',
|
||
uk: 'Квадратні лого каналів',
|
||
be: 'Квадратныя лога каналаў',
|
||
en: 'Square channel logos',
|
||
zh: '方形通道標誌'
|
||
});
|
||
langAdd('contain_icons', {
|
||
ru: 'Коррекция размера логотипа телеканала',
|
||
uk: 'Виправлення розміру логотипу телеканалу',
|
||
be: 'Карэкцыя памеру лагатыпа тэлеканала',
|
||
en: 'TV channel logo size correction',
|
||
zh: '電視頻道標誌尺寸校正'
|
||
});
|
||
langAdd('contain_icons_desc', {
|
||
ru: 'Может некорректно работать на старых устройствах',
|
||
uk: 'Може некоректно працювати на старих пристроях',
|
||
be: 'Можа некарэктна працаваць на старых прыладах',
|
||
en: 'May not work correctly on older devices.',
|
||
zh: '可能无法在较旧的设备上正常工作。'
|
||
});
|
||
|
||
Lampa.Lang.add(langData);
|
||
|
||
function favID(title) {
|
||
return title.toLowerCase().replace(/[\s!-\/:-@\[-`{-~]+/g, '')
|
||
}
|
||
function getStorage(name, defaultValue) {
|
||
return Lampa.Storage.get(plugin.component + '_' + name, defaultValue);
|
||
}
|
||
function setStorage(name, val, noListen) {
|
||
return Lampa.Storage.set(plugin.component + '_' + name, val, noListen);
|
||
}
|
||
function getSettings(name) {
|
||
return Lampa.Storage.field(plugin.component + '_' + name);
|
||
}
|
||
function addSettings(type, param) {
|
||
var data = {
|
||
component: plugin.component,
|
||
param: {
|
||
name: plugin.component + '_' + param.name,
|
||
type: type, // select|trigger|input|title|static
|
||
values: !param.values ? '' : param.values,
|
||
placeholder: !param.placeholder ? '' : param.placeholder,
|
||
default: (typeof param.default === 'undefined') ? '' : param.default
|
||
},
|
||
field: {
|
||
name: !param.title ? (!param.name ? '' : param.name) : param.title
|
||
}
|
||
}
|
||
if (!!param.name) data.param.name = plugin.component + '_' + param.name;
|
||
if (!!param.description) data.field.description = param.description;
|
||
if (!!param.onChange) data.onChange = param.onChange;
|
||
if (!!param.onRender) data.onRender = param.onRender;
|
||
Lampa.SettingsApi.addParam(data);
|
||
}
|
||
|
||
function configurePlaylist(i) {
|
||
if (i > 0) return i;
|
||
|
||
var title = plugin.name;
|
||
var url = (typeof AUTO_PLAYLIST_URL === 'string') ? AUTO_PLAYLIST_URL : '';
|
||
|
||
var activity = {
|
||
id: 0,
|
||
url: '',
|
||
title: title,
|
||
groups: [],
|
||
currentGroup: getStorage('last_catalog0', langGet('default_playlist_cat')),
|
||
component: plugin.component,
|
||
page: 1
|
||
};
|
||
|
||
if (activity.currentGroup === '!!') activity.currentGroup = '';
|
||
|
||
var menuEl = $('<li class="menu__item selector js-' + plugin.component + '-menu0">'
|
||
+ '<div class="menu__ico">' + plugin.icon + '</div>'
|
||
+ '<div class="menu__text js-' + plugin.component + '-menu0-title">'
|
||
+ encoder.text(title).html()
|
||
+ '</div>'
|
||
+ '</li>')
|
||
.hide()
|
||
.on('hover:enter', function(){
|
||
if (Lampa.Activity.active().component === plugin.component) {
|
||
Lampa.Activity.replace(Lampa.Arrays.clone(activity));
|
||
} else {
|
||
Lampa.Activity.push(Lampa.Arrays.clone(activity));
|
||
}
|
||
});
|
||
|
||
if (/^https?:\/\/./i.test(url)) {
|
||
activity.url = url;
|
||
menuEl.show();
|
||
}
|
||
|
||
lists.push({activity: activity, menuEl: menuEl, groups: []});
|
||
return 0;
|
||
}
|
||
|
||
Lampa.Component.add(plugin.component, pluginPage);
|
||
// Готовим настройки
|
||
Lampa.SettingsApi.addComponent(plugin);
|
||
addSettings(
|
||
'trigger',
|
||
{
|
||
title: langGet('square_icons'),
|
||
name: 'square_icons',
|
||
default: false,
|
||
onChange: function(v){
|
||
$('.' + plugin.component + '.category-full').toggleClass('square_icons', v === 'true');
|
||
}
|
||
}
|
||
);
|
||
addSettings(
|
||
'trigger',
|
||
{
|
||
title: langGet('contain_icons'),
|
||
description: langGet('contain_icons_desc'),
|
||
name: 'contain_icons',
|
||
default: true,
|
||
onChange: function(v){
|
||
$('.' + plugin.component + '.category-full').toggleClass('contain_icons', v === 'true');
|
||
}
|
||
}
|
||
);
|
||
addSettings(
|
||
'trigger',
|
||
{
|
||
title: langGet('epg_on'),
|
||
name: 'epg',
|
||
default: false,
|
||
onChange: function(v){
|
||
epgListView(v === 'true');
|
||
}
|
||
}
|
||
);
|
||
addSettings(
|
||
'trigger',
|
||
{
|
||
title: langGet('launch_menu'),
|
||
name: 'launch_menu',
|
||
default: false
|
||
}
|
||
);
|
||
addSettings(
|
||
'select',
|
||
{
|
||
title: langGet('max_ch_in_group'),
|
||
description: langGet('max_ch_in_group_desc'),
|
||
name: 'max_ch_in_group',
|
||
values: {
|
||
0: '#{settings_param_card_view_all}',
|
||
60: '60',
|
||
120: '120',
|
||
180: '180',
|
||
240: '240',
|
||
300: '300'
|
||
},
|
||
default: 300
|
||
}
|
||
);
|
||
configurePlaylist(0);
|
||
UID = getStorage('uid', '');
|
||
if (!UID) {
|
||
UID = Lampa.Utils.uid(10).toUpperCase().replace(/(.{4})/g, '$1-');
|
||
setStorage('uid', UID);
|
||
} else if (UID.length > 12) {
|
||
UID = UID.substring(0, 12);
|
||
setStorage('uid', UID);
|
||
}
|
||
addSettings('title', {title: langGet('uid')});
|
||
addSettings('static', {title: UID, description: langGet('unique_id')});
|
||
//~ Готовим настройки
|
||
|
||
function pluginStart() {
|
||
if (!!window['plugin_' + plugin.component + '_ready']) {
|
||
console.log(plugin.name, 'plugin already start');
|
||
return;
|
||
}
|
||
window['plugin_' + plugin.component + '_ready'] = true;
|
||
var menu = $('.menu .menu__list').eq(0);
|
||
for (var i=0; i < lists.length; i++) menu.append(lists[i].menuEl);
|
||
isSNG = ['uk', 'ru', 'be'].indexOf(Lampa.Storage.field('language')) >= 0;
|
||
console.log(plugin.name, 'plugin start', menu.length, lists.length, isSNG);
|
||
}
|
||
|
||
console.log(plugin.name, 'plugin ready start', !!window.appready ? 'now' : 'waiting event ready');
|
||
if (!!window.appready) pluginStart();
|
||
else Lampa.Listener.follow('app', function(e){if (e.type === 'ready') pluginStart()});
|
||
})(); |