Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Develop - v0.9.0-beta #13

Merged
merged 7 commits into from
Aug 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "stream-fusion"
version = "0.7.0"
version = "0.9.0"
description = "StreamFusion is an advanced plugin for Stremio that significantly enhances its streaming capabilities with debrid service."
authors = ["LimeDrive <[email protected]>"]
readme = "README.md"
Expand Down
12 changes: 6 additions & 6 deletions stream_fusion/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,14 +92,14 @@

FR_RELEASE_GROUPS = [
r"(?<=[.\s\-\[])(BlackAngel|Choco|Sicario|Tezcat74|TyrellCorp|Zapax)(?=[.\s\-$$]|$)",
r"(?<=[.\s\-\[])(FtLi|Goldenyann|MUSTANG|Obi|PEPiTE|QUEBEC63|QC63|ROMKENT)(?=[.\s\-$$]|$)",
r"(?<=[.\s\-\[])(FLOP|FRATERNiTY|QTZ|PopHD|toto70300|GHT|EXTREME)(?=[.\s\-$$]|$)",
r"(?<=[.\s\-\[])(DUSTiN|QUALiTY|Tsundere-Raws|LAZARUS|ALFA|SODAPOP)(?=[.\s\-$$]|$)",
r"(?<=[.\s\-\[])(BDHD|MAX|SowHD|SN2P|RG|BTT|KAF|AwA|MULTiViSiON|FERVEX)(?=[.\s\-$$]|$)",
r"(?<=[.\s\-\[])(FUJiSAN|HDForever|MARBLECAKE|MYSTERiON|ONLY|UTT|ZiT|JP48)(?=[.\s\-$$]|$)",
r"(?<=[.\s\-\[])(FtLi|Goldenyann|MUSTANG|Obi|PEPiTE|QUEBEC63|QC63|ROMKENT|R3MiX)(?=[.\s\-$$]|$)",
r"(?<=[.\s\-\[])(FLOP|FRATERNiTY|QTZ|PopHD|toto70300|GHT|EXTREME|AvALoN|KFL|mHDgz)(?=[.\s\-$$]|$)",
r"(?<=[.\s\-\[])(DUSTiN|QUALiTY|Tsundere-Raws|LAZARUS|ALFA|SODAPOP|Tetine|DREAM|Winks)(?=[.\s\-$$]|$)",
r"(?<=[.\s\-\[])(BDHD|MAX|SowHD|SN2P|RG|BTT|KAF|AwA|MULTiViSiON|FERVEX|Foxhound|K7|LiBERTAD)(?=[.\s\-$$]|$)",
r"(?<=[.\s\-\[])(FUJiSAN|HDForever|MARBLECAKE|MYSTERiON|ONLY|UTT|ZiT|JP48|SEL|PATOMiEL)(?=[.\s\-$$]|$)",
r"(?<=[.\s\-\[])(BONBON|FCK|FW|FoX|FrIeNdS|MOONLY|MTDK|PATOPESTO|Psaro|T3KASHi|TFA)(?=[.\s\-$$]|$)",
r"(?<=[.\s\-\[])(ALLDAYiN|ARK01|HANAMi|HeavyWeight|NEO|NoNe|ONLYMOViE|Slay3R|TkHD)(?=[.\s\-$$]|$)",
r"(?<=[.\s\-\[])(4FR|AiR3D|AiRDOCS|AiRFORCE|AiRLiNE|AiRTV|AKLHD|AMB3R)(?=[.\s\-$$]|$)",
r"(?<=[.\s\-\[])(4FR|AiR3D|AiRDOCS|AiRFORCE|AiRLiNE|AiRTV|AKLHD|AMB3R|SERQPH|Elcrackito)(?=[.\s\-$$]|$)",
r"(?<=[.\s\-\[])(ANMWR|AVON|AYMO|AZR|BANKAi|BAWLS|BiPOLAR|BLACKPANTERS|BODIE|BOOLZ|BRiNK|CARAPiLS|CiELOS)(?=[.\s\-$$]|$)",
r"(?<=[.\s\-\[])(CiNEMA|CMBHD|CoRa|COUAC|CRYPT0|D4KiD|DEAL|DiEBEX|DUPLI|DUSS|ENJOi|EUBDS|FHD|FiDELiO|FiDO|ForceBleue)(?=[.\s\-$$]|$)",
r"(?<=[.\s\-\[])(FREAMON|FRENCHDEADPOOL2|FRiES|FUTiL|FWDHD|GHOULS|GiMBAP|GLiMMER|Goatlove|HERC|HiggsBoson|HiRoSHiMa)(?=[.\s\-$$]|$)",
Expand Down
3 changes: 2 additions & 1 deletion stream_fusion/logging_config.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# logging_config.py
import os
from loguru import logger
from stream_fusion.settings import settings
import sys
Expand Down Expand Up @@ -98,7 +99,7 @@ def configure_logging():
)

logger.add(
settings.log_path,
f"/app/config/logs/api_worker_{os.getpid()}.log",
format=format,
level="DEBUG",
rotation="2 MB",
Expand Down
70 changes: 70 additions & 0 deletions stream_fusion/services/rd_conn/token_manager.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import aiohttp
import redis
import requests

from stream_fusion.settings import settings

class RealDebridService:
BASE_URL = "https://api.real-debrid.com/oauth/v2"
CLIENT_ID = "X245A4XAIBGVM" # Client ID for open source apps

async def get_device_code(self):
async with aiohttp.ClientSession() as session:
async with session.get(f"{self.BASE_URL}/device/code", params={"client_id": self.CLIENT_ID, "new_credentials": "yes"}) as response:
return await response.json()

async def get_credentials(self, device_code):
async with aiohttp.ClientSession() as session:
async with session.get(f"{self.BASE_URL}/device/credentials", params={"client_id": self.CLIENT_ID, "code": device_code}) as response:
if response.status == 200:
return await response.json()
return {"error": "Authorization pending"}

async def get_token(self, client_id, client_secret, device_code):
async with aiohttp.ClientSession() as session:
async with session.post(f"{self.BASE_URL}/token", data={
"client_id": client_id,
"client_secret": client_secret,
"code": device_code,
"grant_type": "http://oauth.net/grant_type/device/1.0"
}) as response:
return await response.json()

class RDTokenManager:
BASE_URL = "https://api.real-debrid.com/oauth/v2"

def __init__(self, config):
self.redis = redis.Redis(host=settings.redis_host, port=settings.redis_port)
self.config = config
self.rd_config = self.config.get('debridKey', {})
if not self.rd_config:
raise Exception("Real Debrid configuration not found")

self.client_id = self.rd_config.get('client_id')
self.client_secret = self.rd_config.get('client_secret')
self.refresh_token = self.rd_config.get('refresh_token')
self.apikey = self.config.get('apiKey')

if not all([self.client_id, self.client_secret, self.refresh_token, self.apikey]):
raise Exception("Missing required Real Debrid configuration")

def get_access_token(self):
token = self.redis.get(f"rd_access_token:{self.apikey}")
if token:
return token.decode('utf-8')
return self.new_access_token()

def new_access_token(self):
response = requests.post(f"{self.BASE_URL}/token", data={
"client_id": self.client_id,
"client_secret": self.client_secret,
"code": self.refresh_token,
"grant_type": "http://oauth.net/grant_type/device/1.0"
})

response.raise_for_status()

data = response.json()
self.redis.setex(f"rd_access_token:{self.apikey}", int(data['expires_in']), data['access_token'])

return data['access_token']
125 changes: 123 additions & 2 deletions stream_fusion/static/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,126 @@ function setElementDisplay(elementId, displayStatus) {
}
}

function startRealDebridAuth() {
document.getElementById('rd-auth-button').disabled = true;
document.getElementById('rd-auth-button').textContent = "Authentification en cours...";
console.log('Début de l\'authentification Real-Debrid');

fetch('/api/auth/realdebrid/device_code', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({})
})
.then(response => {
console.log('Réponse reçue', response);
if (!response.ok) {
throw new Error('Erreur de requête');
}
return response.json();
})
.then(data => {
console.log('Réponse reçue:', data);
document.getElementById('verification-url').href = data.direct_verification_url;
document.getElementById('verification-url').textContent = data.verification_url;
document.getElementById('user-code').textContent = data.user_code;
document.getElementById('auth-instructions').style.display = 'block';
pollForCredentials(data.device_code, data.expires_in);
})
.catch(error => {
console.error('Erreur détaillée:', error);
alert("Erreur lors de l'authentification. Veuillez réessayer.");
resetAuthButton();
});
}

function pollForCredentials(deviceCode, expiresIn) {
console.log('Début du polling avec device_code:', deviceCode);
const pollInterval = setInterval(() => {
fetch(`/api/auth/realdebrid/credentials?device_code=${encodeURIComponent(deviceCode)}`, {
method: 'POST',
headers: {
'accept': 'application/json'
}
})
.then(response => {
if (!response.ok) {
if (response.status === 400) {
console.log('Autorisation en attente...');
return null;
}
throw new Error('Erreur de requête');
}
return response.json();
})
.then(data => {
if (data && data.client_id && data.client_secret) {
clearInterval(pollInterval);
clearTimeout(timeoutId);
getToken(deviceCode, data.client_id, data.client_secret);
}
})
.catch(error => {
console.error('Erreur:', error);
console.log('Tentative suivante dans 5 secondes...');
});
}, 5000);

const timeoutId = setTimeout(() => {
clearInterval(pollInterval);
alert("Le délai d'authentification a expiré. Veuillez réessayer.");
resetAuthButton();
}, expiresIn * 1000);
}

function getToken(deviceCode, clientId, clientSecret) {
const url = `/api/auth/realdebrid/token?client_id=${encodeURIComponent(clientId)}&client_secret=${encodeURIComponent(clientSecret)}&device_code=${encodeURIComponent(deviceCode)}`;

fetch(url, {
method: 'POST',
headers: {
'accept': 'application/json'
}
})
.then(response => {
if (!response.ok) {
throw new Error('Erreur de requête');
}
return response.json();
})
.then(data => {
if (data.access_token && data.refresh_token) {
const rdCredentials = {
client_id: clientId,
client_secret: clientSecret,
access_token: data.access_token,
refresh_token: data.refresh_token
};
document.getElementById('debrid_api_key').value = JSON.stringify(rdCredentials, null, 2);
document.getElementById('auth-status').style.display = 'block';
document.getElementById('auth-instructions').style.display = 'none';
document.getElementById('rd-auth-button').disabled = true;
document.getElementById('rd-auth-button').classList.add('opacity-50', 'cursor-not-allowed');
document.getElementById('rd-auth-button').textContent = "Connexion réussie";
} else {
throw new Error('Tokens non reçus');
}
})
.catch(error => {
console.error('Erreur:', error);
// Ne pas afficher d'alerte ici, car cela pourrait être une erreur temporaire
console.log('Erreur lors de la récupération du token. Nouvelle tentative lors du prochain polling.');
});
}

function resetAuthButton() {
const button = document.getElementById('rd-auth-button');
button.disabled = false;
button.textContent = "S'authentifier avec Real-Debrid";
button.classList.remove('opacity-50', 'cursor-not-allowed');
}

function updateProviderFields() {
setElementDisplay('debrid-fields', document.getElementById('debrid').checked ? 'block' : 'none');
setElementDisplay('cache-fields', document.getElementById('cache')?.checked ? 'block' : 'none');
Expand Down Expand Up @@ -43,7 +163,7 @@ function loadData() {
document.getElementById('yggPasskey').value = data.yggPasskey;
document.getElementById('yggUsername').value = data.yggUsername;
document.getElementById('yggPassword').value = data.yggPassword;
document.getElementById('service').value = data.service;
// document.getElementById('service').value = data.service;
document.getElementById('exclusion-keywords').value = (data.exclusionKeywords || []).join(', ');
document.getElementById('maxSize').value = data.maxSize;
document.getElementById('resultsPerQuality').value = data.resultsPerQuality;
Expand Down Expand Up @@ -77,7 +197,8 @@ function getLink(method) {
const data = {
addonHost: new URL(window.location.href).origin,
apiKey: document.getElementById('ApiKey').value,
service: document.getElementById('service').value,
// service: document.getElementById('service').value,
service: 'Real-Debrid',
debridKey: document.getElementById('debrid_api_key').value,
sharewoodPasskey: document.getElementById('sharewoodPasskey').value,
maxSize: parseInt(document.getElementById('maxSize').value) || 16,
Expand Down
Loading
Loading