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 = $(
- '