;(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: "", 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 = $(( "
\n" + "
\n" + "
\n" + "
 
\n" + "
\n" + "
\n" + "
").replace(/PLUGIN/g, plugin.component) ).hide().fadeOut(0); var chHelper = $(( "
\n" + "
\n" + "
\n" + "
\n" + "
").replace(/PLUGIN/g, plugin.component) ).hide().fadeOut(0); var epgTemplate = $(('
\n' + '

\n' + '
\n' + '
Сейчас
\n' + '
' + '
\n' + '
XX:XX
\n' + '
\n' + '
\n' + '
\n' + '
\n' + '
' + '
\n' + '
'+ '
' + '
\n' + '
Потом
\n' + '
' + '
\n' + '
' + '
').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 = $(( '
\n' + '
XX:XX
\n' + '
\n' + '
\n' + '
\n' + '
').replace(/PLUGIN/g, plugin.component) ); var chHelpEl = chHelper.find('.tv-helper'); var chNumEl = chPanel.find('.player-info__name'); var encoder = $('
'); 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('
')); 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', ''.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 = $('
'); var body = $('
'); 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] ? ('

' + encoder.text(e[3]).html() + '

') : ''; epgNow.find('.js-epgDesc').html(desc.replace(/\n/g,'

')); 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, '$1'); 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('

' + fl + '
'); 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 = $('
'); 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('
'); if (tvgDay === 0) tvgDay = 1; } else { tvgDay = 0; } card.find('.card__age').html('
') 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', "
" + langGet('categories') + "\n
"); Lampa.Template.add(plugin.component + '_info_radio', '
'); 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: 'По умолчанию используется плейлист из проекта https://github.com/Free-TV/IPTV
Вы можете заменить его на свой.', uk: 'За замовчуванням використовується плейлист із проекту https://github.com/Free-TV/IPTV
Ви можете замінити його на свій.', be: 'Па змаўчанні выкарыстоўваецца плэйліст з праекта https://github.com/Free-TV/IPTV
Вы можаце замяніць яго на свой.', en: 'The default playlist is from the project https://github.com/Free-TV/IPTV
You can replace it with your own.', zh: '默认播放列表来自项目 https://github.com/Free-TV/IPTV
您可以将其替换为您自己的。' } ); langAdd('settings_list_url_desc1', { ru: 'Вы можете добавить еще один плейлист здесь. Ссылки на плейлисты обычно заканчиваются на .m3u или .m3u8', uk: 'Ви можете додати ще один плейлист суду. Посилання на плейлисти зазвичай закінчуються на .m3u або .m3u8', be: 'Вы можаце дадаць яшчэ адзін плэйліст суда. Спасылкі на плэйлісты звычайна заканчваюцца на .m3u або .m3u8', en: 'You can add another trial playlist. Playlist links usually end with .m3u or .m3u8', zh: '您可以添加另一个播放列表。 播放列表链接通常以 .m3u 或 .m3u8 结尾' } ); 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 = $('') .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()}); })();