From 8db23ae0580de35793c735642ccbbe8b25393d6d Mon Sep 17 00:00:00 2001 From: Hermes Date: Sat, 8 Aug 2026 13:01:03 +0200 Subject: [PATCH] use Lampa.Reguest (TV-safe) instead of fetch; EN-only comments --- plugin.js | 87 ++++++++++++++++++++++++++++++++----------------------- 1 file changed, 50 insertions(+), 37 deletions(-) diff --git a/plugin.js b/plugin.js index 75e347a..128f455 100644 --- a/plugin.js +++ b/plugin.js @@ -1,28 +1,48 @@ (function () { 'use strict'; - var PLUGIN = { name: 'mymovies', title: 'Мои фильмы' }; + var PLUGIN = { name: 'mymovies', title: 'My Movies', menu_action: 'mymovies' }; var DEFAULT_BASE = 'https://movies-lmp-18.dynv6.net/'; function base() { var b = Lampa.Storage.get(PLUGIN.name + '_base', DEFAULT_BASE); return b.replace(/\/+$/, '') + '/'; } + function resolve(p) { if (!p) return ''; if (/^https?:\/\//.test(p)) return p; if (/^magnet:/.test(p)) return p; return base() + p.replace(/^\/+/, ''); } + function esc(s) { return String(s == null ? '' : s) .replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"'); } - // ---------- Компонент: список фильмов ---------- - // Регистрируется как функция-конструктор (как iptv), иначе Lampa падает: - // "component is not a constructor" + function loadCatalog(cb) { + var url = base() + 'movies/catalog.json'; + // Use Lampa native network layer (works on TV where fetch fails) + if (Lampa.Reguest && Lampa.Reguest.get) { + Lampa.Reguest.get(url, function (html) { + try { + cb(null, JSON.parse(html)); + } catch (e) { + cb(e, null); + } + }, function (err) { + cb(err || new Error('request failed'), null); + }); + } else { + fetch(url).then(function (r) { return r.json(); }) + .then(function (d) { cb(null, d); }) + .catch(function (e) { cb(e, null); }); + } + } + + // ---------- Component: movie list ---------- function MyMovies() { var comp = this; this.render = function () { @@ -34,26 +54,21 @@ if (comp.activity) comp.activity.loader(true); - fetch(base() + 'movies/catalog.json') - .then(function (r) { - if (!r.ok) throw new Error('HTTP ' + r.status); - return r.json(); - }) - .then(function (data) { - if (comp.activity) comp.activity.loader(false); - var movies = (data && data.movies) || []; - console.log('[mymovies] loaded', movies.length, 'films'); - renderMovies($(grid), movies); - Lampa.Layer.update(html); - Lampa.Layer.visible(html); - }) - .catch(function (err) { - if (comp.activity) comp.activity.loader(false); + loadCatalog(function (err, data) { + if (comp.activity) comp.activity.loader(false); + if (err) { console.error('[mymovies] catalog error', err); - grid.innerHTML = '
Ошибка загрузки каталога
'; + grid.innerHTML = '
Catalog load error
'; Lampa.Layer.update(html); Lampa.Layer.visible(html); - }); + return; + } + var movies = (data && data.movies) || []; + console.log('[mymovies] loaded', movies.length, 'films'); + renderMovies($(grid), movies); + Lampa.Layer.update(html); + Lampa.Layer.visible(html); + }); return html; }; @@ -63,7 +78,7 @@ function renderMovies(grid, movies) { grid.empty(); if (!movies.length) { - grid.append('
Каталог пуст
'); + grid.append('
Catalog is empty
'); if (Lampa.Selector) Lampa.Selector.update(); return; } @@ -78,13 +93,13 @@ if (Lampa.Selector) Lampa.Selector.update(); } - // ---------- Компонент: детали фильма ---------- + // ---------- Component: movie detail ---------- var selected = null; function MyMoviesDetail() { var comp = this; this.render = function () { var m = selected; - if (!m) { Lampa.Activity.back(); return $('
'); } + if (!m) { Lampa.Activity.back(); return document.createElement('div'); } var html = document.createElement('div'); html.className = 'mymovies-detail'; @@ -99,11 +114,11 @@ var h1 = document.createElement('h1'); h1.textContent = m.title; info.appendChild(h1); - if (m.original_title) { var d = document.createElement('div'); d.className='detail-orig'; d.textContent=m.original_title; info.appendChild(d); } - if (m.year) { var d = document.createElement('div'); d.className='detail-year'; d.textContent=m.year; info.appendChild(d); } - if (m.genre && m.genre.length) { var d = document.createElement('div'); d.className='detail-genre'; d.textContent=m.genre.join(', '); info.appendChild(d); } - if (m.rating) { var d = document.createElement('div'); d.className='detail-rating'; d.textContent='★ ' + m.rating; info.appendChild(d); } - if (m.description) { var d = document.createElement('div'); d.className='detail-desc'; d.textContent=m.description; info.appendChild(d); } + if (m.original_title) { var d = document.createElement('div'); d.className = 'detail-orig'; d.textContent = m.original_title; info.appendChild(d); } + if (m.year) { var d = document.createElement('div'); d.className = 'detail-year'; d.textContent = m.year; info.appendChild(d); } + if (m.genre && m.genre.length) { var d = document.createElement('div'); d.className = 'detail-genre'; d.textContent = m.genre.join(', '); info.appendChild(d); } + if (m.rating) { var d = document.createElement('div'); d.className = 'detail-rating'; d.textContent = '★ ' + m.rating; info.appendChild(d); } + if (m.description) { var d = document.createElement('div'); d.className = 'detail-desc'; d.textContent = m.description; info.appendChild(d); } head.appendChild(info); html.appendChild(head); var actions = document.createElement('div'); @@ -111,7 +126,7 @@ var btn = document.createElement('div'); btn.className = 'btn selector'; btn.setAttribute('data-act', 'play'); - btn.textContent = 'Смотреть'; + btn.textContent = 'Watch'; actions.appendChild(btn); html.appendChild(actions); @@ -144,13 +159,12 @@ }); } - // ---------- Пункт меню ---------- - // Официальный паттерн Lampa: меню собирается при событии 'menu:start', - // в e.body приходит jQuery-корень меню. Удаляем ВСЕ старые копии из DOM - // (на случай нескольких пересборок/подписок) и добавляем ровно одну. + // ---------- Menu item ---------- + // Lampa builds the main menu on the 'menu:start' event, e.body is the jQuery menu root. + // Remove ALL old copies from the DOM first, then add exactly one button. function makeButton() { var button = $( - '