ServiceFork Tizen: различия между версиями

Материал из Браузер Fork - Wiki
Перейти к навигации Перейти к поиску
FXML all_*: channel overrides global
 
FXML all_*: channel overrides global
Строка 1: Строка 1:
{{DISPLAYTITLE:ServiceFork — плагины Tizen}}
{{DISPLAYTITLE:ServiceFork — локальные парсеры (Tizen)}}


<div class="toccolours" style="width:100%; max-width:920px; padding:12px 16px; line-height:1.55;">
<div class="toccolours" style="width:100%; max-width:920px; padding:12px 16px; line-height:1.55;">
'''ServiceFork''' — фоновый HTTP-сервис в приложении Fork browser на <b>Samsung Tizen</b>. Отдаёт страницы в формате '''FXML (JSON)''' с локального адреса <code>http://127.0.0.1:8092/</code>, без отдельного PHP-сервера.
На <b>Samsung Tizen</b> Fork browser запускает фоновый HTTP-сервис '''ServiceFork''' (порт '''8092'''): в нём '''Node.js''' парсит сайты и отдаёт страницы в формате '''FXML (JSON)''' с <code>http://127.0.0.1:8092/</code> — без PHP на хостинге.
 
Каждый файл-плагин в <code>service/plugins/</code> — отдельный локальный парсер. Если задана функция <code>home()</code>, плитка парсера появляется на домашней странице Fork browser в секции '''Локально'''.


См. также: [[FXML|Спецификация FXML]] · [https://appfxml.com/ Репозиторий Fork browser]
См. также: [[FXML|Спецификация FXML]] · [https://appfxml.com/ Репозиторий Fork browser]
Строка 9: Строка 11:
== Назначение ==
== Назначение ==


* Парсеры сайтов, каталоги и утилиты, работающие '''на TV''' (Node.js в Tizen service).
* '''Локальные парсеры''' — каталоги, поиск, просмотр: логика выполняется на TV в Tizen background service (Node.js).
* Тот же контракт, что у веб-портала: объект с <code>title</code>, массив <code>channels[]</code>, глобальные поля (<code>css</code>, <code>typeList</code>, <code>icon</code> и др.) — см. [[FXML#3. Термины и модель данных|модель FXML]].
* Ответ — тот же JSON, что у веб-портала: <code>title</code>, <code>channels[]</code>, глобальные поля (<code>css</code>, <code>typeList</code>, <code>icon</code> …) — см. [[FXML#3. Термины и модель данных|модель FXML]].
* Плагины подключаются файлами в каталоге <code>service/plugins/</code> проекта Tizen (в пакете приложения).
* Один файл <code>service/plugins/&lt;id&gt;.js</code> = один парсер с URL <code>http://127.0.0.1:8092/&lt;id&gt;</code>.
 
== Домашняя страница: секция «Локально» ==
 
При старте Fork browser (Tizen) запрашивает <code>http://127.0.0.1:8092/status</code>. ServiceFork собирает массив <code>services</code> из функций <code>home()</code> всех загруженных плагинов (<code>homeServices</code> в <code>service/index.js</code>) и отдаёт плитки в формате FXML-channel (<code>source: service</code>, <code>playlist_url</code>, иконка, меню).
 
Клиент добавляет эти плитки в блок <code>ch.service</code> стартовой страницы — в интерфейсе это секция '''Локально''' (рядом с USB, играми и другими локальными пунктами).
 
'''Важно:''' без <code>home()</code> парсер доступен только по прямому URL (<code>/&lt;id&gt;</code> или ссылка <code>playlist_url</code> в другом портале), на домашний экран он не попадёт.


== Архитектура ==
== Архитектура ==
Строка 18: Строка 28:
! Компонент !! Описание
! Компонент !! Описание
|-
|-
| <code>service/index.js</code> || Ядро ServiceFork: HTTP на порту '''8092''', загрузка плагинов, общий API (<code>api.page</code>, <code>api.htmlChannel</code>, HTTP-запросы, кеш).
| <code>service/index.js</code> || Ядро ServiceFork: HTTP '''8092''', загрузка плагинов, <code>createApi</code>, маршрутизация, <code>/status</code> → <code>services</code>.
|-
|-
| <code>service/plugins/&lt;id&gt;.js</code> || Один плагин = один модуль. Имя файла (без <code>.js</code>) = URL-путь: <code>/&lt;id&gt;</code>.
| <code>service/plugins/&lt;id&gt;.js</code> || Модуль парсера: <code>routes</code> (страницы FXML), опционально <code>home()</code> (плитка «Локально»), <code>matchUrl</code> / <code>handleUrl</code> для перехвата внешних ссылок.
|-
|-
| Fork browser (UI) || Запрашивает <code>playlist_url</code> вида <code>http://127.0.0.1:8092/rezka/...</code> и отображает JSON как обычную FXML-страницу.
| Fork browser (UI) || Открывает <code>playlist_url</code> плитки или любой <code>http://127.0.0.1:8092/…</code> и рисует JSON как обычную FXML-страницу.
|}
|}


'''Запуск сервиса (Tizen):''' background service приложения, операция <code>service</code>, пакет вида <code>&lt;packageId&gt;.servicefork</code> (см. <code>config.xml</code> виджета). При старте вызываются <code>onStart</code> / <code>onRequest</code> из <code>service/index.js</code>.
'''Tizen:''' background service приложения (<code>config.xml</code>, пакет <code>&lt;packageId&gt;.servicefork</code>), точки входа <code>onStart</code> / <code>onRequest</code> в <code>service/index.js</code>.


'''Служебные URL:'''
'''Служебные URL:'''
Строка 32: Строка 42:
! Путь !! Ответ
! Путь !! Ответ
|-
|-
| <code>/</code> || Список загруженных плагинов
| <code>/status</code> || JSON: <code>ok</code>, версия, список плагинов, '''<code>services</code>''' — плитки для секции «Локально»
|-
| <code>/status</code> || JSON: версия, список плагинов, плитки для стартового меню
|-
|-
| <code>/plugins</code> || FXML-страница со списком плагинов
| <code>/</code>, <code>/plugins</code> || Список парсеров (FXML или JSON)
|-
|-
| <code>/logs</code> || Просмотр логов service (FXML-страница)
| <code>/logs</code> || Логи service (FXML-страница)
|}
|}


Зарезервированные id: <code>status</code>, <code>plugins</code>, <code>logs</code> — нельзя использовать как имя плагина.
Зарезервированные id: <code>status</code>, <code>plugins</code>, <code>logs</code>.


== Быстрый старт: свой плагин ==
== Быстрый старт: свой парсер ==


# В проекте Tizen Studio (например <code>workspace/Forkbrowser/service/plugins/</code>) скопируйте шаблон <code>_template.js</code> → <code>myparser.js</code> (файлы с префиксом <code>_</code> '''не''' загружаются).
# В Tizen Studio (<code>workspace/Forkbrowser/service/plugins/</code>) скопируйте <code>_template.js</code> → <code>myparser.js</code> (файлы с <code>_</code> в начале имени не загружаются).
# Задайте в начале файла объект <code>PLUGIN</code>: <code>id</code>, <code>name</code>, <code>version</code>, навигацию <code>nav[]</code>.
# Опишите парсер: <code>name</code>, <code>version</code>, маршруты в <code>routes</code> (<code>''</code> — главная, <code>search</code>, <code>list</code> …).
# Экспортируйте функцию <code>module.exports = function (api) { return { ... }; }</code> с полями:
# Реализуйте '''<code>home(base)</code>''' и верните <code>api.homeTile({…})</code> — так парсер появится в '''Локально''' после установки .wgt.
#* <code>name</code>, <code>version</code>
# Соберите виджет и установите на TV. Парсер: <code>http://127.0.0.1:8092/myparser</code>
#* <code>home(base)</code> — плитка на стартовом экране (через <code>api.homeTile</code>)
# Иконка: положите <code>service/plugins/myparser.png</code> рядом с .js — подставится в плитку.
#* <code>routes</code> — обработчики путей: <code>''</code> (главная), <code>search</code>, <code>list</code> и т.д.
# Соберите и установите .wgt на TV. Плагин будет доступен: <code>http://127.0.0.1:8092/myparser</code>
# В FXML укажите, например: <code>"playlist_url": "http://127.0.0.1:8092/myparser"</code> или добавьте плитку через <code>/status</code> → <code>services</code>.


'''Минимальный каркас (упрощённо):'''
'''Минимальный каркас:'''


<pre>module.exports = function (api) {
<pre>module.exports = function (api) {
Строка 83: Строка 88:
   };
   };
};</pre>
};</pre>
При необходимости парсер можно вызывать и с удалённого портала — укажите в JSON <code>"playlist_url": "http://127.0.0.1:8092/myparser"</code> (актуально только на устройстве, где запущен ServiceFork).


== API ядра (кратко) ==
== API ядра (кратко) ==


Плагин получает объект <code>api</code> из <code>createApi</code> в <code>service/index.js</code>.
Плагин получает объект <code>api</code> из <code>createApi</code> (<code>service/index.js</code>).


{| class="wikitable"
{| class="wikitable"
! Метод !! Назначение
! Метод !! Назначение
|-
|-
| <code>api.page(title, channels, extra)</code> || Готовая FXML-страница (<code>extra</code>: <code>css</code>, <code>typeList</code>, <code>icon</code>)
| <code>api.page(title, channels, extra)</code> || FXML-страница (<code>css</code>, <code>typeList</code>, <code>icon</code> в <code>extra</code>)
|-
|-
| <code>api.folder(title, url, opts)</code> || Элемент с <code>playlist_url</code>
| <code>api.folder(title, url, opts)</code> || Элемент с <code>playlist_url</code>
Строка 97: Строка 104:
| <code>api.stream(title, url, opts)</code> || Элемент с <code>stream_url</code>, опционально <code>parser</code>
| <code>api.stream(title, url, opts)</code> || Элемент с <code>stream_url</code>, опционально <code>parser</code>
|-
|-
| <code>api.htmlChannel(cfg)</code> || Channel с <code>position: html</code>, <code>template</code>, <code>menu</code>, <code>search_on</code>
| <code>api.htmlChannel(cfg)</code> || Channel с <code>position: html</code>, шаблон, меню, поиск
|-
| <code>api.homeTile(cfg)</code> || Плитка для стартового меню Tizen
|-
|-
| <code>api.cardChannels(items, base, opts)</code> || Сетка карточек с шаблоном
| <code>api.homeTile(cfg)</code> || Плитка для секции «Локально» (<code>source: service</code>)
|-
|-
| <code>api.getText / api.getTextCached</code> || HTTP GET HTML (User-Agent, редиректы, таймаут)
| <code>api.cardChannels(items, base, opts)</code> || Сетка карточек
|-
|-
| <code>api.pluginUrl(base, id, route, params)</code> || Ссылка на свой или чужой маршрут плагина
| <code>api.getText / api.getTextCached</code> || HTTP GET HTML
|-
|-
| <code>api.linkTo(base, path, params)</code> || Query-string для внутренних URL
| <code>api.pluginUrl(base, id, route, params)</code> || URL маршрута парсера
|-
|-
| <code>api.log.info / warn / error</code> || Логи → консоль, буфер, <code>/logs</code>
| <code>api.log.info / warn / error</code> || Логи → <code>/logs</code> и UI Fork
|}
|}


'''Маршруты (<code>routes</code>):''' ключ — путь после <code>/&lt;pluginId&gt;/</code> (пустая строка = корень). Обработчик <code>function (ctx, cb)</code>: <code>ctx.q</code> — GET-параметры, <code>ctx.base</code> — <code>http://127.0.0.1:8092</code>, <code>cb(err, fxmlObject)</code>.
'''Маршруты:''' ключ — путь после <code>/&lt;pluginId&gt;/</code>; обработчик <code>(ctx, cb)</code>, <code>cb(err, fxmlObject)</code>.


'''Прямые URL в адресной строке Fork:''' если <code>playlist_url</code> — полный <code>http(s)://...</code>, ServiceFork может перехватить запрос через <code>matchUrl</code> + <code>handleUrl</code> (см. плагины rezka, kinogo).
'''Внешние ссылки:''' <code>matchUrl</code> + <code>handleUrl</code> — перехват полного <code>http(s)://…</code> в адресной строке Fork (см. <code>rezka.js</code>, <code>kinogo.js</code>).


== Иконки и оформление ==
== Иконки и оформление ==


* Положите <code>service/plugins/&lt;id&gt;.png</code> (или .jpg) — ядро отдаст <code>http://127.0.0.1:8092/&lt;id&gt;.png</code> и подставит в плитку.
* <code>service/plugins/&lt;id&gt;.png</code> (или .jpg) → <code>http://127.0.0.1:8092/&lt;id&gt;.png</code>
* CSS страницы: передайте в <code>api.page(..., { css: '...' })</code> — попадает в глобальный тег FXML <code>css</code>.
* CSS страницы: <code>api.page(..., { css: '...' })</code>
* Шаблоны кнопок/карточек — через <code>api.htmlChannel({ template: '...', before: '...' })</code>, плейсхолдеры <code>$title</code>, <code>$logo_30x30</code> (как в [[FXML#6. Оформление и вёрстка элементов|§6 FXML]]).
* Шаблоны карточек: <code>api.htmlChannel({ template: '...' })</code> — плейсхолдеры как в [[FXML#6. Оформление и вёрстка элементов|§6 FXML]]


== Отладка ==
== Отладка ==


# На TV откройте в Fork: <code>http://127.0.0.1:8092/status</code> — список плагинов и версия ServiceFork.
# <code>http://127.0.0.1:8092/status</code> — версия, список плагинов, массив <code>services</code> (то, что уходит в «Локально»).
# <code>http://127.0.0.1:8092/logs</code> — логи (уровни error/warn/info/debug).
# <code>http://127.0.0.1:8092/logs</code> — логи; ошибки плагина с префиксом <code>[pluginId]</code>.
# Ошибки загрузки плагина пишутся в log с префиксом <code>[pluginId]</code>.
# В Fork логи service также приходят через MessagePort (<code>servicefork-log</code>).
# Логи также уходят в UI Fork через MessagePort (<code>servicefork-log</code>).


== Связь с FXML ==
== Связь с FXML ==


{| class="wikitable"
{| class="wikitable"
! На сервере (PHP) !! ServiceFork (Tizen)
! PHP-портал !! ServiceFork (Tizen)
|-
|-
| <code>$_PL</code> / <code>$_CH</code> || <code>api.page()</code> / объекты channel
| <code>$_PL</code> / <code>$_CH</code> || <code>api.page()</code>
|-
|-
| <code>json_encode($_PL)</code> || <code>sendJson(res, body)</code> в HTTP-ответе
| <code>json_encode</code> || <code>sendJson</code> в HTTP-ответе
|-
|-
| <code>playlist_url</code> на свой домен || <code>api.pluginUrl(...)</code> → localhost:8092
| Ссылки на свой домен || <code>api.pluginUrl</code> → <code>127.0.0.1:8092</code>
|}
|}


Пользователь не видит разницы: Fork парсит JSON одинаково. Для гибридных сценариев портал может отдавать ссылки на <code>http://127.0.0.1:8092/...</code> только на Tizen (по <code>box_client</code> в GET — см. [[FXML#7.1. Параметры GET от клиента|§7.1 FXML]]).
Для пользователя JSON выглядит одинаково; разница только в том, что парсер крутится локально на TV.


== Примеры в проекте ==
== Примеры в проекте ==


* <code>service/plugins/_template.js</code> — шаблон нового плагина
* <code>service/plugins/_template.js</code> — шаблон парсера с <code>home()</code> и <code>routes</code>
* <code>service/plugins/rezka.js</code>, <code>kinogo.js</code> — полноценные парсеры с маршрутами, меню, поиском
* <code>service/plugins/rezka.js</code>, <code>kinogo.js</code> — полные парсеры (меню, поиск, <code>matchUrl</code>)


== Установка приложения с ServiceFork ==
== Установка приложения с ServiceFork ==


Сборка виджета и установка на Samsung Tizen — [[Браузер Fork - Wiki:Установить браузер Fork#Samsung Smart TV|инструкции по установке]] ([https://appfxml.com/ Apps2Tizen], ForkTizenInstall, .wgt).
Сборка .wgt и установка на Samsung Tizen — [[Браузер Fork - Wiki:Установить браузер Fork#Samsung Smart TV|инструкции по установке]] ([https://appfxml.com/ Apps2Tizen], ForkTizenInstall).


[[Category:FXML]]
[[Category:FXML]]



Версия от 14:02, 28 октября 2026


На Samsung Tizen Fork browser запускает фоновый HTTP-сервис ServiceFork (порт 8092): в нём Node.js парсит сайты и отдаёт страницы в формате FXML (JSON) с http://127.0.0.1:8092/ — без PHP на хостинге.

Каждый файл-плагин в service/plugins/ — отдельный локальный парсер. Если задана функция home(), плитка парсера появляется на домашней странице Fork browser в секции Локально.

См. также: Спецификация FXML · Репозиторий Fork browser

Назначение

  • Локальные парсеры — каталоги, поиск, просмотр: логика выполняется на TV в Tizen background service (Node.js).
  • Ответ — тот же JSON, что у веб-портала: title, channels[], глобальные поля (css, typeList, icon …) — см. модель FXML.
  • Один файл service/plugins/<id>.js = один парсер с URL http://127.0.0.1:8092/<id>.

Домашняя страница: секция «Локально»

При старте Fork browser (Tizen) запрашивает http://127.0.0.1:8092/status. ServiceFork собирает массив services из функций home() всех загруженных плагинов (homeServices в service/index.js) и отдаёт плитки в формате FXML-channel (source: service, playlist_url, иконка, меню).

Клиент добавляет эти плитки в блок ch.service стартовой страницы — в интерфейсе это секция Локально (рядом с USB, играми и другими локальными пунктами).

Важно: без home() парсер доступен только по прямому URL (/<id> или ссылка playlist_url в другом портале), на домашний экран он не попадёт.

Архитектура

Компонент Описание
service/index.js Ядро ServiceFork: HTTP 8092, загрузка плагинов, createApi, маршрутизация, /status → services.
service/plugins/<id>.js Модуль парсера: routes (страницы FXML), опционально home() (плитка «Локально»), matchUrl / handleUrl для перехвата внешних ссылок.
Fork browser (UI) Открывает playlist_url плитки или любой http://127.0.0.1:8092/… и рисует JSON как обычную FXML-страницу.

Tizen: background service приложения (config.xml, пакет <packageId>.servicefork), точки входа onStart / onRequest в service/index.js.

Служебные URL:

Путь Ответ
/status JSON: ok, версия, список плагинов, services — плитки для секции «Локально»
/, /plugins Список парсеров (FXML или JSON)
/logs Логи service (FXML-страница)

Зарезервированные id: status, plugins, logs.

Быстрый старт: свой парсер

  1. В Tizen Studio (workspace/Forkbrowser/service/plugins/) скопируйте _template.js → myparser.js (файлы с _ в начале имени не загружаются).
  2. Опишите парсер: name, version, маршруты в routes ( — главная, search, list …).
  3. Реализуйте home(base) и верните api.homeTile({…}) — так парсер появится в Локально после установки .wgt.
  4. Соберите виджет и установите на TV. Парсер: http://127.0.0.1:8092/myparser
  5. Иконка: положите service/plugins/myparser.png рядом с .js — подставится в плитку.

Минимальный каркас:

module.exports = function (api) {
  var id = 'myparser';
  return {
    name: 'My Parser',
    version: '1.0.0',
    home: function (base) {
      return api.homeTile({
        id: id,
        base: base,
        title: 'My Parser',
        playlist_url: api.pluginUrl(base, id)
      });
    },
    routes: {
      '': function (ctx, cb) {
        cb(null, api.page('My Parser', [
          api.folder('Раздел', api.pluginUrl(ctx.base, id, 'list'))
        ]));
      },
      list: function (ctx, cb) {
        cb(null, api.page('Список', [
          api.stream('Пример', 'http://example.com/video.m3u8')
        ]));
      }
    }
  };
};

При необходимости парсер можно вызывать и с удалённого портала — укажите в JSON "playlist_url": "http://127.0.0.1:8092/myparser" (актуально только на устройстве, где запущен ServiceFork).

API ядра (кратко)

Плагин получает объект api из createApi (service/index.js).

Метод Назначение
api.page(title, channels, extra) FXML-страница (css, typeList, icon в extra)
api.folder(title, url, opts) Элемент с playlist_url
api.stream(title, url, opts) Элемент с stream_url, опционально parser
api.htmlChannel(cfg) Channel с position: html, шаблон, меню, поиск
api.homeTile(cfg) Плитка для секции «Локально» (source: service)
api.cardChannels(items, base, opts) Сетка карточек
api.getText / api.getTextCached HTTP GET HTML
api.pluginUrl(base, id, route, params) URL маршрута парсера
api.log.info / warn / error Логи → /logs и UI Fork

Маршруты: ключ — путь после /<pluginId>/; обработчик (ctx, cb), cb(err, fxmlObject).

Внешние ссылки: matchUrl + handleUrl — перехват полного http(s)://… в адресной строке Fork (см. rezka.js, kinogo.js).

Иконки и оформление

  • service/plugins/<id>.png (или .jpg) → http://127.0.0.1:8092/<id>.png
  • CSS страницы: api.page(..., { css: '...' })
  • Шаблоны карточек: api.htmlChannel({ template: '...' }) — плейсхолдеры как в §6 FXML

Отладка

  1. http://127.0.0.1:8092/status — версия, список плагинов, массив services (то, что уходит в «Локально»).
  2. http://127.0.0.1:8092/logs — логи; ошибки плагина с префиксом [pluginId].
  3. В Fork логи service также приходят через MessagePort (servicefork-log).

Связь с FXML

PHP-портал ServiceFork (Tizen)
$_PL / $_CH api.page()
json_encode sendJson в HTTP-ответе
Ссылки на свой домен api.pluginUrl → 127.0.0.1:8092

Для пользователя JSON выглядит одинаково; разница только в том, что парсер крутится локально на TV.

Примеры в проекте

  • service/plugins/_template.js — шаблон парсера с home() и routes
  • service/plugins/rezka.js, kinogo.js — полные парсеры (меню, поиск, matchUrl)

Установка приложения с ServiceFork

Сборка .wgt и установка на Samsung Tizen — инструкции по установке (Apps2Tizen, ForkTizenInstall).