commit b1a83696e4097d086b5ef5d7263b47fbed72c7a3 Author: openclaw Date: Tue Mar 3 01:50:48 2026 +0300 init: lampa p365x plugin diff --git a/README.md b/README.md new file mode 100644 index 0000000..372ece9 --- /dev/null +++ b/README.md @@ -0,0 +1,6 @@ +# lampa-p365x-plugin + +MVP plugin for Lampa that parses and plays videos from m.porno365x.space. + +## Install +Add plugin URL in Lampa plugin manager pointing to `p365x-plugin.js`. diff --git a/p365x-plugin.js b/p365x-plugin.js new file mode 100644 index 0000000..4503c19 --- /dev/null +++ b/p365x-plugin.js @@ -0,0 +1,176 @@ +(function () { + 'use strict'; + + var FLAG = 'lampa_p365x_parser_started'; + if (window[FLAG]) return; + window[FLAG] = true; + + var BASE = 'https://m.porno365x.space'; + var STATE = { items: [], page: 1, loading: false }; + + function $(sel, root) { return (root || document).querySelector(sel); } + function el(tag, cls, txt) { + var n = document.createElement(tag); + if (cls) n.className = cls; + if (txt != null) n.textContent = txt; + return n; + } + + function extractCards(html) { + var out = []; + var re = /
  • ([^<]+)<\/p>[\s\S]*?([^<]*)<\/span>/g; + var m; + while ((m = re.exec(html))) { + out.push({ + id: m[1], + url: m[2].startsWith('http') ? m[2] : BASE + m[2], + poster: m[3], + title: m[4].trim(), + duration: (m[5] || '').trim() + }); + } + return out; + } + + function extractMp4(movieHtml) { + var all = []; + var re = /file\s*:\s*"([^"]+\.mp4[^"]*)"/g; + var m; + while ((m = re.exec(movieHtml))) all.push(m[1]); + if (!all.length) { + var v = movieHtml.match(/]+src="([^"]+\.mp4[^"]*)"/i); + if (v) all.push(v[1]); + } + // prefer highest quality by filename suffix _1080p/_720p ... + all.sort(function (a, b) { + function q(x) { + var mm = x.match(/_(\d{3,4})p\.mp4/i); + return mm ? Number(mm[1]) : 0; + } + return q(b) - q(a); + }); + return all[0] || ''; + } + + async function request(url) { + var r = await fetch(url, { credentials: 'omit' }); + if (!r.ok) throw new Error('HTTP ' + r.status); + return await r.text(); + } + + async function fetchList(page) { + var url = page > 1 ? (BASE + '/page/' + page + '/') : (BASE + '/'); + var html = await request(url); + return extractCards(html); + } + + async function fetchStream(movieUrl) { + var html = await request(movieUrl); + return extractMp4(html); + } + + function createUi() { + if ($('#p365x-root')) return; + + var css = el('style'); + css.textContent = '' + + '#p365x-fab{position:fixed;right:24px;bottom:24px;z-index:99999;background:#e91e63;color:#fff;border:none;border-radius:999px;padding:10px 14px;font-weight:700;}' + + '#p365x-root{position:fixed;inset:0;z-index:99998;background:#111;color:#fff;display:none;}' + + '#p365x-head{padding:12px 16px;display:flex;gap:10px;align-items:center;border-bottom:1px solid #333;}' + + '#p365x-list{padding:10px;display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:10px;overflow:auto;height:calc(100% - 64px);}' + + '.p365x-card{background:#1b1b1b;border:1px solid #333;border-radius:8px;overflow:hidden;cursor:pointer;}' + + '.p365x-card img{width:100%;height:130px;object-fit:cover;display:block;}' + + '.p365x-meta{padding:8px;font-size:13px;}' + + '#p365x-player{position:fixed;inset:0;z-index:100000;background:#000;display:none;}' + + '#p365x-player video{width:100%;height:100%;}' + + '#p365x-close-player{position:absolute;top:10px;right:10px;z-index:2;}'; + document.head.appendChild(css); + + var fab = el('button'); + fab.id = 'p365x-fab'; + fab.textContent = 'P365'; + + var root = el('div'); + root.id = 'p365x-root'; + root.innerHTML = '
    '; + + var player = el('div'); + player.id = 'p365x-player'; + player.innerHTML = ''; + + document.body.appendChild(fab); + document.body.appendChild(root); + document.body.appendChild(player); + + fab.addEventListener('click', function () { + root.style.display = 'block'; + if (!STATE.items.length) loadNextPage(); + }); + $('#p365x-close').addEventListener('click', function () { root.style.display = 'none'; }); + $('#p365x-more').addEventListener('click', loadNextPage); + $('#p365x-close-player').addEventListener('click', function () { + player.style.display = 'none'; + var v = $('#p365x-video'); + v.pause(); + v.removeAttribute('src'); + v.load(); + }); + } + + function setStatus(t) { var s = $('#p365x-status'); if (s) s.textContent = t || ''; } + + function renderItems() { + var list = $('#p365x-list'); + if (!list) return; + list.innerHTML = ''; + STATE.items.forEach(function (item) { + var c = el('div', 'p365x-card'); + c.innerHTML = '
    ' + item.title + '
    ' + item.duration + '
    '; + c.addEventListener('click', async function () { + try { + setStatus('Загрузка видео...'); + var src = await fetchStream(item.url); + if (!src) throw new Error('Поток не найден'); + var p = $('#p365x-player'); + var v = $('#p365x-video'); + v.src = src; + p.style.display = 'block'; + setStatus(''); + } catch (e) { + setStatus('Ошибка: ' + e.message); + } + }); + list.appendChild(c); + }); + } + + async function loadNextPage() { + if (STATE.loading) return; + STATE.loading = true; + try { + setStatus('Загрузка страницы ' + STATE.page + '...'); + var items = await fetchList(STATE.page); + STATE.items = STATE.items.concat(items); + STATE.page += 1; + renderItems(); + setStatus('Найдено: ' + STATE.items.length); + } catch (e) { + setStatus('Не удалось загрузить. Возможен CORS/блокировка: ' + e.message); + } finally { + STATE.loading = false; + } + } + + function start() { + createUi(); + } + + if (window.appready) start(); + else if (window.Lampa && Lampa.Listener) { + Lampa.Listener.follow('app', function (e) { + if (e.type === 'ready') start(); + }); + } else { + window.addEventListener('load', start); + } +})();