From c5373b9fd561e809130259d443dda71f1825b30f Mon Sep 17 00:00:00 2001 From: LimeDrive Date: Mon, 30 Sep 2024 15:38:23 +0000 Subject: [PATCH 1/8] =?UTF-8?q?Update=20version=20to=202.1.0:=20add=20d?= =?UTF-8?q?=C3=A9brid=20order=20and=20dll=20debrid=20config=20-=20[Feature?= =?UTF-8?q?]=20Add=20priority=20and=20download=20selection=20on=20debrid?= =?UTF-8?q?=20services=20#50?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pyproject.toml | 2 +- stream_fusion/static/config.js | 348 +++++++++++++----- stream_fusion/static/index.html | 59 ++- .../utils/debrid/get_debrid_service.py | 16 +- .../utils/torrent/torrent_smart_container.py | 2 +- stream_fusion/web/playback/stream/views.py | 14 +- 6 files changed, 329 insertions(+), 112 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 4ad2108..62717a1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "stream-fusion" -version = "2.0.5" +version = "2.1.0" description = "StreamFusion is an advanced plugin for Stremio that significantly enhances its streaming capabilities with debrid service." authors = ["LimeDrive "] readme = "README.md" diff --git a/stream_fusion/static/config.js b/stream_fusion/static/config.js index 1dc529c..27b9728 100644 --- a/stream_fusion/static/config.js +++ b/stream_fusion/static/config.js @@ -6,6 +6,7 @@ document.addEventListener('DOMContentLoaded', function () { handleUniqueAccounts(); updateProviderFields(); loadData(); + updateDebridOrderList(); }); function setElementDisplay(elementId, displayStatus) { @@ -245,91 +246,265 @@ function handleUniqueAccounts() { setUniqueAccountState(yggCheckbox); } +function updateDebridOrderList() { + const debridOrderList = document.getElementById('debridOrderList'); + if (!debridOrderList) return; + + debridOrderList.innerHTML = ''; + + let debridOrder = []; + try { + const currentUrl = window.location.href; + let data = currentUrl.match(/\/([^\/]+)\/configure$/); + if (data && data[1]) { + const decodedData = JSON.parse(atob(data[1])); + debridOrder = decodedData.service || []; + } + } catch (error) { + console.error("Error getting debrid order:", error); + } + + const rdEnabled = document.getElementById('debrid_rd').checked || document.getElementById('debrid_rd').disabled; + const adEnabled = document.getElementById('debrid_ad').checked || document.getElementById('debrid_ad').disabled; + + if (debridOrder.length === 0 || + !debridOrder.every(service => + (service === 'Real-Debrid' && rdEnabled) || + (service === 'AllDebrid' && adEnabled) + )) { + debridOrder = []; + if (rdEnabled) debridOrder.push('Real-Debrid'); + if (adEnabled) debridOrder.push('AllDebrid'); + } + + debridOrder.forEach(serviceName => { + if ((serviceName === 'Real-Debrid' && rdEnabled) || + (serviceName === 'AllDebrid' && adEnabled)) { + addDebridToList(serviceName); + } + }); + + if (rdEnabled && !debridOrder.includes('Real-Debrid')) { + addDebridToList('Real-Debrid'); + } + if (adEnabled && !debridOrder.includes('AllDebrid')) { + addDebridToList('AllDebrid'); + } + + Sortable.create(debridOrderList, { + animation: 150, + ghostClass: 'bg-gray-100', + onEnd: function() { + const newOrder = Array.from(debridOrderList.children).map(li => li.dataset.serviceName); + console.log("Nouvel ordre des débrideurs:", newOrder); + } + }); +} + +function addDebridToList(serviceName) { + const debridOrderList = document.getElementById('debridOrderList'); + const li = document.createElement('li'); + li.className = 'bg-gray-700 text-white text-sm p-1.5 rounded shadow cursor-move flex items-center justify-between w-64 mb-2'; + + const text = document.createElement('span'); + text.textContent = serviceName; + text.className = 'flex-grow truncate'; + + const icon = document.createElement('span'); + icon.innerHTML = '⋮'; + icon.className = 'text-gray-400 ml-2 flex-shrink-0'; + + li.appendChild(text); + li.appendChild(icon); + li.dataset.serviceName = serviceName; + debridOrderList.appendChild(li); +} + +function toggleDebridOrderList() { + const orderList = document.getElementById('debridOrderList'); + const isChecked = document.getElementById('debrid_order').checked; + orderList.classList.toggle('hidden', !isChecked); + + if (isChecked) { + updateDebridOrderList(); + } +} + +function updateDebridDownloaderOptions() { + const debridDownloaderOptions = document.getElementById('debridDownloaderOptions'); + if (!debridDownloaderOptions) return; + + debridDownloaderOptions.innerHTML = ''; + + const rdEnabled = document.getElementById('debrid_rd').checked || document.getElementById('debrid_rd').disabled; + const adEnabled = document.getElementById('debrid_ad').checked || document.getElementById('debrid_ad').disabled; + + let firstOption = null; + + if (rdEnabled) { + firstOption = addDebridDownloaderOption('Real-Debrid'); + } + if (adEnabled) { + if (!firstOption) { + firstOption = addDebridDownloaderOption('AllDebrid'); + } else { + addDebridDownloaderOption('AllDebrid'); + } + } + + if (firstOption && !document.querySelector('input[name="debrid_downloader"]:checked')) { + firstOption.checked = true; + } +} + +function addDebridDownloaderOption(serviceName) { + const debridDownloaderOptions = document.getElementById('debridDownloaderOptions'); + const id = `debrid_downloader_${serviceName.toLowerCase().replace('-', '_')}`; + + const div = document.createElement('div'); + div.className = 'flex items-center'; + + const input = document.createElement('input'); + input.type = 'radio'; + input.id = id; + input.name = 'debrid_downloader'; + input.value = serviceName; + input.className = 'h-4 w-4 border-gray-300 text-indigo-600 focus:ring-indigo-600'; + + const label = document.createElement('label'); + label.htmlFor = id; + label.className = 'ml-3 block text-sm font-medium text-white'; + label.textContent = serviceName; + + div.appendChild(input); + div.appendChild(label); + debridDownloaderOptions.appendChild(div); + + return input; +} + + function updateProviderFields() { - const RDdebridChecked = document.getElementById('debrid_rd').checked || - document.getElementById('debrid_rd').disabled; - const ADdebridChecked = document.getElementById('debrid_ad').checked || - document.getElementById('debrid_ad').disabled; - const cacheChecked = document.getElementById('cache')?.checked; - const yggflixChecked = document.getElementById('yggflix')?.checked || - document.getElementById('yggflix')?.disabled; - const sharewoodChecked = document.getElementById('sharewood')?.checked || - document.getElementById('sharewood')?.disabled; - - const RDdebridFields = document.getElementById('rd_debrid-fields'); - const ADdebridFields = document.getElementById('ad_debrid-fields'); - const cacheFields = document.getElementById('cache-fields'); - const yggFields = document.getElementById('ygg-fields'); - const sharewoodFields = document.getElementById('sharewood-fields'); - - if (RDdebridFields) RDdebridFields.style.display = RDdebridChecked ? 'block' : 'none'; - if (ADdebridFields) ADdebridFields.style.display = ADdebridChecked ? 'block' : 'none'; - if (cacheFields) cacheFields.style.display = cacheChecked ? 'block' : 'none'; - if (yggFields) yggFields.style.display = yggflixChecked ? 'block' : 'none'; - if (sharewoodFields) sharewoodFields.style.display = sharewoodChecked ? 'block' : 'none'; + const RDdebridChecked = document.getElementById('debrid_rd').checked || + document.getElementById('debrid_rd').disabled; + const ADdebridChecked = document.getElementById('debrid_ad').checked || + document.getElementById('debrid_ad').disabled; + const cacheChecked = document.getElementById('cache')?.checked; + const yggflixChecked = document.getElementById('yggflix')?.checked || + document.getElementById('yggflix')?.disabled; + const sharewoodChecked = document.getElementById('sharewood')?.checked || + document.getElementById('sharewood')?.disabled; + + const RDdebridFields = document.getElementById('rd_debrid-fields'); + const ADdebridFields = document.getElementById('ad_debrid-fields'); + const cacheFields = document.getElementById('cache-fields'); + const yggFields = document.getElementById('ygg-fields'); + const sharewoodFields = document.getElementById('sharewood-fields'); + + if (RDdebridFields) RDdebridFields.style.display = RDdebridChecked ? 'block' : 'none'; + if (ADdebridFields) ADdebridFields.style.display = ADdebridChecked ? 'block' : 'none'; + if (cacheFields) cacheFields.style.display = cacheChecked ? 'block' : 'none'; + if (yggFields) yggFields.style.display = yggflixChecked ? 'block' : 'none'; + if (sharewoodFields) sharewoodFields.style.display = sharewoodChecked ? 'block' : 'none'; + + const debridOrderCheckbox = document.getElementById('debrid_order'); + const debridOrderList = document.getElementById('debridOrderList'); + + if (debridOrderCheckbox && debridOrderList) { + const anyDebridEnabled = RDdebridChecked || ADdebridChecked; + + debridOrderCheckbox.disabled = !anyDebridEnabled; + debridOrderCheckbox.checked = anyDebridEnabled && debridOrderCheckbox.checked; + + if (anyDebridEnabled && debridOrderCheckbox.checked) { + debridOrderList.classList.remove('hidden'); + updateDebridOrderList(); + } else { + debridOrderList.classList.add('hidden'); + } + } + + updateDebridOrderList(); + updateDebridDownloaderOptions(); } function loadData() { - const currentUrl = window.location.href; - let data = currentUrl.match(/\/([^\/]+)\/configure$/); - if (data && data[1]) { + const currentUrl = window.location.href; + let data = currentUrl.match(/\/([^\/]+)\/configure$/); + let decodedData = {}; + + if (data && data[1]) { try { - const decodedData = JSON.parse(atob(data[1])); - - function setElementValue(id, value) { - const element = document.getElementById(id); - if (element) { - if (typeof value === 'boolean') { + decodedData = JSON.parse(atob(data[1])); + } catch (error) { + console.error("Error decoding data:", error); + } + } + + function setElementValue(id, value) { + const element = document.getElementById(id); + if (element) { + if (typeof value === 'boolean') { element.checked = value; - } else { + } else { element.value = value; - } } - } - - setElementValue('jackett', decodedData.jackett ?? false); - setElementValue('cache', decodedData.cache ?? false); - setElementValue('cacheUrl', decodedData.cacheUrl || ''); - setElementValue('zilean', decodedData.zilean ?? false); - setElementValue('yggflix', decodedData.yggflix ?? false); - setElementValue('sharewood', decodedData.sharewood ?? false); - setElementValue('rd_token_info', decodedData.RDToken || ''); - setElementValue('ad_token_info', decodedData.ADToken || ''); - setElementValue('sharewoodPasskey', decodedData.sharewoodPasskey || ''); - setElementValue('yggPasskey', decodedData.yggPasskey || ''); - setElementValue('ApiKey', decodedData.apiKey || ''); - setElementValue('exclusion-keywords', (decodedData.exclusionKeywords || []).join(', ')); - setElementValue('maxSize', decodedData.maxSize || ''); - setElementValue('resultsPerQuality', decodedData.resultsPerQuality || ''); - setElementValue('maxResults', decodedData.maxResults || ''); - setElementValue('minCachedResults', decodedData.minCachedResults || ''); - setElementValue('torrenting', decodedData.torrenting ?? false); - setElementValue('ctg_yggtorrent', decodedData.yggtorrentCtg ?? false); - setElementValue('ctg_yggflix', decodedData.yggflixCtg ?? false); - setElementValue('tmdb', decodedData.metadataProvider === 'tmdb'); - setElementValue('cinemeta', decodedData.metadataProvider === 'cinemeta'); - setElementValue('debrid_rd', decodedData.service?.includes('Real-Debrid') ?? false); - setElementValue('debrid_ad', decodedData.service?.includes('AllDebrid') ?? false); - - sorts.forEach(sort => { - setElementValue(sort, decodedData.sort === sort); - }); - - qualityExclusions.forEach(quality => { - setElementValue(quality, decodedData.exclusion?.includes(quality) ?? false); - }); - - languages.forEach(language => { - setElementValue(language, decodedData.languages?.includes(language) ?? false); - }); - - updateProviderFields(); - } catch (error) { - console.error("Error decoding data:", error); } - } } + setElementValue('jackett', decodedData.jackett ?? false); + setElementValue('cache', decodedData.cache ?? false); + setElementValue('cacheUrl', decodedData.cacheUrl || ''); + setElementValue('zilean', decodedData.zilean ?? false); + setElementValue('yggflix', decodedData.yggflix ?? false); + setElementValue('sharewood', decodedData.sharewood ?? false); + setElementValue('rd_token_info', decodedData.RDToken || ''); + setElementValue('ad_token_info', decodedData.ADToken || ''); + setElementValue('sharewoodPasskey', decodedData.sharewoodPasskey || ''); + setElementValue('yggPasskey', decodedData.yggPasskey || ''); + setElementValue('ApiKey', decodedData.apiKey || ''); + setElementValue('exclusion-keywords', (decodedData.exclusionKeywords || []).join(', ')); + setElementValue('maxSize', decodedData.maxSize || ''); + setElementValue('resultsPerQuality', decodedData.resultsPerQuality || ''); + setElementValue('maxResults', decodedData.maxResults || ''); + setElementValue('minCachedResults', decodedData.minCachedResults || ''); + setElementValue('torrenting', decodedData.torrenting ?? false); + setElementValue('ctg_yggtorrent', decodedData.yggtorrentCtg ?? false); + setElementValue('ctg_yggflix', decodedData.yggflixCtg ?? false); + setElementValue('tmdb', decodedData.metadataProvider === 'tmdb'); + setElementValue('cinemeta', decodedData.metadataProvider === 'cinemeta'); + setElementValue('debrid_rd', decodedData.service?.includes('Real-Debrid') ?? false); + setElementValue('debrid_ad', decodedData.service?.includes('AllDebrid') ?? false); + setElementValue('debrid_order', decodedData.service && decodedData.service.length > 0); + + sorts.forEach(sort => { + setElementValue(sort, decodedData.sort === sort); + }); + + qualityExclusions.forEach(quality => { + setElementValue(quality, decodedData.exclusion?.includes(quality) ?? false); + }); + + languages.forEach(language => { + setElementValue(language, decodedData.languages?.includes(language) ?? false); + }); + + updateProviderFields(); + + const debridDownloader = decodedData.debridDownloader; + if (debridDownloader) { + const radioButton = document.querySelector(`input[name="debrid_downloader"][value="${debridDownloader}"]`); + if (radioButton) { + radioButton.checked = true; + } + } + + updateDebridDownloaderOptions(); + + updateDebridOrderList(); +} + + function getLink(method) { const data = { addonHost: new URL(window.location.href).origin, @@ -357,32 +532,23 @@ function getLink(method) { yggPasskey: document.getElementById('yggPasskey')?.value, torrenting: document.getElementById('torrenting').checked, debrid: false, - metadataProvider: document.getElementById('tmdb').checked ? 'tmdb' : 'cinemeta' + metadataProvider: document.getElementById('tmdb').checked ? 'tmdb' : 'cinemeta', + debridDownloader: document.querySelector('input[name="debrid_downloader"]:checked')?.value }; - const rdEnabled = document.getElementById('debrid_rd').checked; - const adEnabled = document.getElementById('debrid_ad').checked; + data.service = Array.from(document.getElementById('debridOrderList').children).map(li => li.dataset.serviceName); + data.debrid = data.service.length > 0; - if (rdEnabled) { - data.service.push('Real-Debrid'); - data.debrid = true; - } - if (adEnabled) { - data.service.push('AllDebrid'); - data.debrid = true; - } - - // Check if all required fields are filled const missingRequiredFields = []; if (data.cache && !data.cacheUrl) missingRequiredFields.push("Cache URL"); - if (rdEnabled && document.getElementById('rd_token_info') && !data.RDToken) missingRequiredFields.push("Real-Debrid Account Connection"); - if (adEnabled && document.getElementById('ad_token_info') && !data.ADToken) missingRequiredFields.push("AllDebrid Account Connection"); + if (data.service.includes('Real-Debrid') && document.getElementById('rd_token_info') && !data.RDToken) missingRequiredFields.push("Real-Debrid Account Connection"); + if (data.service.includes('AllDebrid') && document.getElementById('ad_token_info') && !data.ADToken) missingRequiredFields.push("AllDebrid Account Connection"); if (data.languages.length === 0) missingRequiredFields.push("Languages"); if (!data.apiKey) missingRequiredFields.push("API Key"); if (data.yggflix && document.getElementById('yggPasskey') && !data.yggPasskey) missingRequiredFields.push("Ygg Passkey"); if (data.sharewood && document.getElementById('sharewoodPasskey') && !data.sharewoodPasskey) missingRequiredFields.push("Sharewood Passkey"); - + if (missingRequiredFields.length > 0) { alert(`Please fill all required fields: ${missingRequiredFields.join(", ")}`); return false; @@ -413,6 +579,8 @@ function getLink(method) { return false; } + console.log("Données avant encodage :", JSON.parse(JSON.stringify(data))); + const encodedData = btoa(JSON.stringify(data)); const stremio_link = `${window.location.host}/${encodedData}/manifest.json`; diff --git a/stream_fusion/static/index.html b/stream_fusion/static/index.html index 7a73a56..44ed561 100644 --- a/stream_fusion/static/index.html +++ b/stream_fusion/static/index.html @@ -6,6 +6,7 @@ + @@ -72,8 +73,8 @@

Streaming Settings

-

Activate Real-Débrid service for - streaming.

+

Activate Real-Débrid service for streaming. +

@@ -86,8 +87,8 @@

Streaming Settings

-

Activate AllDebrid service for - streaming.

+

Activate AllDebrid service for streaming. +

@@ -189,6 +190,42 @@

Torrent Providers

+
+

Debrid Custom Config

+

Customize your debrid service + settings here.

+
+
+
+ +
+
+ +

+ Set the priority order for streaming services. The cache of each debrid service will + be checked in this order. +

+ +
+
+ +
+
+ +

+ Select which debrid service to use for downloading torrents. +

+
+
+
+
+
+
+

Catalogs Providers

Configure your catalogs @@ -213,7 +250,8 @@

Catalogs Providers

class="h-4 w-4 rounded border-gray-300 text-indigo-600 focus:ring-indigo-600">
- +

Activate yggtorrent catalogs for discovers contents.

@@ -264,8 +302,10 @@

AllDebrid Configuration

-