api: Fix tipo raiplay

This commit is contained in:
Lovi 2025-05-25 15:37:53 +02:00
parent c01945fdbc
commit ef6c8c9cb3
9 changed files with 408 additions and 462 deletions

View File

@ -38,14 +38,11 @@ body {
flex-direction: column;
}
header {
background-color: var(--header-bg);
backdrop-filter: blur(10px);
position: fixed;
width: 100%;
padding: 15px 0;
z-index: 1000;
box-shadow: 0 2px 12px var(--shadow-color);
.container {
max-width: 1400px;
margin: 0 auto;
padding: 20px;
flex: 1;
}
.header-container {
@ -88,13 +85,6 @@ header {
font-size: 1.1rem;
}
.container {
max-width: 1400px;
margin: 0 auto;
padding: 20px;
flex: 1;
}
.site-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
@ -166,78 +156,6 @@ header {
color: var(--accent-color);
}
.site-content {
text-align: center;
width: 100%;
}
.domain {
color: var(--text-color);
opacity: 0.8;
font-size: 0.9rem;
margin-bottom: 1.5rem;
word-break: break-all;
}
.site-item a {
margin-top: 1rem;
background: linear-gradient(135deg, var(--primary-color), var(--secondary-color));
color: white;
text-decoration: none;
font-weight: 500;
padding: 12px 28px;
border-radius: 8px;
width: fit-content;
margin: 0 auto;
display: flex;
align-items: center;
gap: 8px;
}
.site-item a:hover {
opacity: 0.9;
transform: translateY(-2px);
}
.site-title {
opacity: 0;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: rgba(0, 0, 0, 0.8);
padding: 10px 20px;
border-radius: 8px;
transition: opacity 0.3s ease;
color: white;
font-size: 1.2rem;
text-align: center;
width: 80%;
pointer-events: none;
z-index: 2;
}
.site-item:hover .site-title {
opacity: 1;
}
.site-item::after {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
opacity: 0;
transition: opacity 0.3s ease;
pointer-events: none;
}
.site-item:hover::after {
opacity: 1;
}
.site-info {
display: flex;
flex-direction: column;
@ -264,6 +182,211 @@ header {
opacity: 1;
}
.site-status {
position: absolute;
top: 10px;
right: 10px;
width: 12px;
height: 12px;
border-radius: 50%;
background: #4CAF50;
}
.site-status.offline {
background: #f44336;
}
.status-indicator {
position: fixed;
top: 20px;
right: 20px;
background: var(--card-background);
border: 1px solid var(--border-color);
border-radius: 12px;
padding: 15px 20px;
box-shadow: 0 4px 20px var(--shadow-color);
z-index: 1001;
min-width: 280px;
max-width: 400px;
transition: all 0.3s ease;
}
.status-indicator.hidden {
opacity: 0;
transform: translateY(-20px);
pointer-events: none;
}
.status-header {
display: flex;
align-items: center;
gap: 10px;
margin-bottom: 15px;
font-weight: 600;
color: var(--primary-color);
}
.status-icon {
width: 20px;
height: 20px;
border: 2px solid var(--primary-color);
border-radius: 50%;
border-top-color: transparent;
animation: spin 1s linear infinite;
}
.status-icon.ready {
border: none;
background: #4CAF50;
animation: none;
position: relative;
}
.status-icon.ready::after {
content: '✓';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: white;
font-size: 12px;
font-weight: bold;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.status-text {
color: var(--text-color);
font-size: 0.9rem;
margin-bottom: 10px;
}
.checking-sites {
max-height: 200px;
overflow-y: auto;
background: var(--background-color);
border-radius: 8px;
padding: 10px;
border: 1px solid var(--border-color);
}
.checking-site {
display: flex;
align-items: center;
justify-content: between;
gap: 10px;
padding: 6px 8px;
margin-bottom: 4px;
border-radius: 6px;
background: var(--card-background);
font-size: 0.8rem;
color: var(--text-color);
transition: all 0.2s ease;
}
.checking-site.completed {
opacity: 0.6;
background: var(--card-hover);
}
.checking-site.online {
border-left: 3px solid #4CAF50;
}
.checking-site.offline {
border-left: 3px solid #f44336;
}
.checking-site .site-name {
flex: 1;
font-weight: 500;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.checking-site .site-status-icon {
width: 12px;
height: 12px;
border-radius: 50%;
flex-shrink: 0;
}
.checking-site .site-status-icon.checking {
background: var(--primary-color);
animation: pulse 1s infinite;
}
.checking-site .site-status-icon.online {
background: #4CAF50;
}
.checking-site .site-status-icon.offline {
background: #f44336;
}
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.5; }
}
.progress-bar {
width: 100%;
height: 6px;
background: var(--background-color);
border-radius: 3px;
overflow: hidden;
margin-top: 10px;
}
.progress-fill {
height: 100%;
background: linear-gradient(90deg, var(--primary-color), var(--accent-color));
width: 0%;
transition: width 0.3s ease;
border-radius: 3px;
}
.loader {
width: 48px;
height: 48px;
border: 3px solid var(--primary-color);
border-bottom-color: transparent;
border-radius: 50%;
display: inline-block;
position: relative;
box-sizing: border-box;
animation: rotation 1s linear infinite;
}
.loader::after {
content: '';
position: absolute;
box-sizing: border-box;
left: 0;
top: 0;
width: 48px;
height: 48px;
border-radius: 50%;
border: 3px solid transparent;
border-bottom-color: var(--accent-color);
animation: rotationBack 0.5s linear infinite;
transform: rotate(45deg);
}
@keyframes rotation {
0% { transform: rotate(0deg) }
100% { transform: rotate(360deg) }
}
@keyframes rotationBack {
0% { transform: rotate(0deg) }
100% { transform: rotate(-360deg) }
}
footer {
background: var(--card-background);
border-top: 1px solid var(--border-color);
@ -355,26 +478,6 @@ footer {
transform: scale(1.2);
}
.github-stats {
display: flex;
gap: 10px;
margin-top: 10px;
font-size: 0.8rem;
}
.github-badge {
background-color: var(--background-color);
padding: 4px 8px;
border-radius: 4px;
display: flex;
align-items: center;
gap: 4px;
}
.github-badge i {
color: var(--accent-color);
}
.footer-description {
margin-top: 15px;
font-size: 0.9rem;
@ -383,103 +486,13 @@ footer {
line-height: 1.5;
}
.update-info {
text-align: center;
margin-top: 30px;
padding-top: 30px;
border-top: 1px solid var(--border-color);
}
.update-note {
color: var(--accent-color);
font-size: 0.9rem;
opacity: 0.9;
}
.theme-toggle {
position: relative;
top: unset;
right: unset;
z-index: 1;
}
.theme-toggle input {
display: none;
}
.theme-toggle label {
cursor: pointer;
padding: 8px;
background: var(--background-color);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 0 10px var(--shadow-color);
border: 1px solid var(--border-color);
transition: all 0.3s ease;
}
.theme-toggle label:hover {
border-color: var(--primary-color);
transform: translateY(-2px);
}
.theme-toggle .fa-sun {
display: none;
color: #ffd700;
}
.theme-toggle .fa-moon {
color: #8c52ff;
}
.theme-toggle input:checked ~ label .fa-sun {
display: block;
}
.theme-toggle input:checked ~ label .fa-moon {
display: none;
}
.loader {
width: 48px;
height: 48px;
border: 3px solid var(--primary-color);
border-bottom-color: transparent;
border-radius: 50%;
display: inline-block;
position: relative;
box-sizing: border-box;
animation: rotation 1s linear infinite;
}
.loader::after {
content: '';
position: absolute;
box-sizing: border-box;
left: 0;
top: 0;
width: 48px;
height: 48px;
border-radius: 50%;
border: 3px solid transparent;
border-bottom-color: var(--accent-color);
animation: rotationBack 0.5s linear infinite;
transform: rotate(45deg);
}
@keyframes rotation {
0% { transform: rotate(0deg) }
100% { transform: rotate(360deg) }
}
@keyframes rotationBack {
0% { transform: rotate(0deg) }
100% { transform: rotate(-360deg) }
}
/* Improved Responsiveness */
/* Responsiveness */
@media (max-width: 768px) {
.site-grid {
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
@ -496,11 +509,7 @@ footer {
grid-template-columns: 1fr;
gap: 20px;
padding: 15px;
}
.theme-toggle {
top: 10px;
right: 10px;
text-align: center;
}
.header-container {
@ -517,27 +526,6 @@ footer {
width: 100%;
justify-content: center;
}
}
@media (max-width: 480px) {
.site-grid {
grid-template-columns: 1fr;
}
.site-item {
min-height: 220px;
}
.container {
padding: 10px;
}
}
@media (max-width: 768px) {
.footer-content {
grid-template-columns: 1fr;
text-align: center;
}
.footer-title::after {
left: 50%;
@ -557,83 +545,16 @@ footer {
}
}
.time-change {
color: var(--text-color);
opacity: 0.7;
font-size: 0.85rem;
margin-bottom: 0.5rem;
word-break: break-all;
}
@media (max-width: 480px) {
.site-grid {
grid-template-columns: 1fr;
}
.label {
color: var(--accent-color);
font-weight: 500;
}
.controls-container {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
padding: 15px 20px;
background: var(--card-background);
border-radius: 12px;
border: 1px solid var(--border-color);
}
.grid-controls {
display: flex;
align-items: center;
gap: 10px;
}
.grid-controls label {
color: var(--text-color);
font-weight: 500;
}
.grid-controls select {
padding: 8px 12px;
border-radius: 8px;
border: 1px solid var(--border-color);
background: var(--background-color);
color: var(--text-color);
cursor: pointer;
transition: all 0.3s ease;
}
.grid-controls select:hover {
border-color: var(--primary-color);
}
.sites-stats {
display: flex;
gap: 20px;
align-items: center;
}
.total-sites, .last-update-global {
display: flex;
align-items: center;
gap: 8px;
color: var(--text-color);
font-size: 0.9rem;
}
.total-sites i, .last-update-global i {
color: var(--primary-color);
}
.site-status {
position: absolute;
top: 10px;
right: 10px;
width: 12px;
height: 12px;
border-radius: 50%;
background: #4CAF50;
}
.site-status.offline {
background: #f44336;
.site-item {
min-height: 220px;
}
.container {
padding: 10px;
}
}

View File

@ -1,32 +1,82 @@
document.documentElement.setAttribute('data-theme', 'dark');
function initGridControls() {
const gridSize = document.getElementById('grid-size');
const siteGrid = document.querySelector('.site-grid');
gridSize.addEventListener('change', function() {
switch(this.value) {
case 'small':
siteGrid.style.gridTemplateColumns = 'repeat(auto-fill, minmax(200px, 1fr))';
break;
case 'medium':
siteGrid.style.gridTemplateColumns = 'repeat(auto-fill, minmax(300px, 1fr))';
break;
case 'large':
siteGrid.style.gridTemplateColumns = 'repeat(auto-fill, minmax(400px, 1fr))';
break;
}
localStorage.setItem('preferredGridSize', this.value);
});
let statusIndicator = null;
let checkingSites = new Map();
let totalSites = 0;
let completedSites = 0;
const savedSize = localStorage.getItem('preferredGridSize');
if (savedSize) {
gridSize.value = savedSize;
gridSize.dispatchEvent(new Event('change'));
function createStatusIndicator() {
statusIndicator = document.createElement('div');
statusIndicator.className = 'status-indicator';
statusIndicator.innerHTML = `
<div class="status-header">
<div class="status-icon"></div>
<span class="status-title">Loading Sites...</span>
</div>
<div class="status-text">Initializing site checks...</div>
<div class="progress-bar">
<div class="progress-fill"></div>
</div>
<div class="checking-sites"></div>
`;
document.body.appendChild(statusIndicator);
return statusIndicator;
}
function updateStatusIndicator(status, text, progress = 0) {
if (!statusIndicator) return;
const statusIcon = statusIndicator.querySelector('.status-icon');
const statusTitle = statusIndicator.querySelector('.status-title');
const statusText = statusIndicator.querySelector('.status-text');
const progressFill = statusIndicator.querySelector('.progress-fill');
statusTitle.textContent = status;
statusText.textContent = text;
progressFill.style.width = `${progress}%`;
if (status === 'Ready') {
statusIcon.classList.add('ready');
setTimeout(() => {
statusIndicator.classList.add('hidden');
setTimeout(() => statusIndicator.remove(), 300);
}, 2000);
}
}
async function checkSiteStatus(url) {
function addSiteToCheck(siteName, siteUrl) {
if (!statusIndicator) return;
const checkingSitesContainer = statusIndicator.querySelector('.checking-sites');
const siteElement = document.createElement('div');
siteElement.className = 'checking-site';
siteElement.innerHTML = `
<span class="site-name">${siteName}</span>
<div class="site-status-icon checking"></div>
`;
checkingSitesContainer.appendChild(siteElement);
checkingSites.set(siteName, siteElement);
}
function updateSiteStatus(siteName, isOnline) {
const siteElement = checkingSites.get(siteName);
if (!siteElement) return;
const statusIcon = siteElement.querySelector('.site-status-icon');
statusIcon.classList.remove('checking');
statusIcon.classList.add(isOnline ? 'online' : 'offline');
siteElement.classList.add('completed', isOnline ? 'online' : 'offline');
completedSites++;
const progress = (completedSites / totalSites) * 100;
updateStatusIndicator(
'Checking Sites...',
`Checked ${completedSites}/${totalSites} sites`,
progress
);
}
async function checkSiteStatus(url, siteName) {
try {
console.log(`Checking status for: ${url}`);
const controller = new AbortController();
@ -46,9 +96,19 @@ async function checkSiteStatus(url) {
const isOnline = response.type === 'opaque';
console.log(`Site ${url} is ${isOnline ? 'online' : 'offline'} (Type: ${response.type})`);
if (siteName) {
updateSiteStatus(siteName, isOnline);
}
return isOnline;
} catch (error) {
console.log(`Error checking ${url}:`, error.message);
if (siteName) {
updateSiteStatus(siteName, false);
}
return false;
}
}
@ -59,9 +119,12 @@ const supabaseKey = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS
async function loadSiteData() {
try {
console.log('Starting to load site data...');
createStatusIndicator();
updateStatusIndicator('Loading...', 'Fetching site data from database...', 0);
const siteList = document.getElementById('site-list');
siteList.innerHTML = '<div class="loader"></div>';
const headers = {
'accept': '*/*',
'accept-language': 'it-IT,it;q=0.9,en-US;q=0.8,en;q=0.7',
@ -83,29 +146,41 @@ async function loadSiteData() {
const data = await response.json();
siteList.innerHTML = ''; if (data && data.length > 0) {
console.log('Raw data from Supabase:', data);
siteList.innerHTML = '';
if (data && data.length > 0) {
const configSite = data[0].data;
console.log('Parsed config site:', configSite);
let totalSites = Object.keys(configSite).length;
totalSites = Object.keys(configSite).length;
completedSites = 0;
let latestUpdate = new Date(0);
document.getElementById('sites-count').textContent = totalSites;
updateStatusIndicator('Checking Sites...', `Starting checks for ${totalSites} sites...`, 0);
Object.entries(configSite).forEach(([siteName, site]) => {
addSiteToCheck(siteName, site.full_url);
});
for (const siteName in configSite) {
const site = configSite[siteName];
const statusChecks = Object.entries(configSite).map(async ([siteName, site]) => {
const isOnline = await checkSiteStatus(site.full_url, siteName);
return { siteName, site, isOnline };
});
const results = await Promise.all(statusChecks);
updateStatusIndicator('Ready', 'All sites checked successfully!', 100);
results.forEach(({ siteName, site, isOnline }) => {
const siteItem = document.createElement('div');
siteItem.className = 'site-item';
siteItem.style.cursor = 'pointer';
// Add status indicator
const statusDot = document.createElement('div');
statusDot.className = 'site-status';
const isOnline = await checkSiteStatus(site.full_url);
if (!isOnline) statusDot.classList.add('offline');
siteItem.appendChild(statusDot);
// Update latest update time
const updateTime = new Date(site.time_change);
if (updateTime > latestUpdate) {
latestUpdate = updateTime;
@ -133,7 +208,9 @@ async function loadSiteData() {
oldDomain.className = 'old-domain';
oldDomain.innerHTML = `<i class="fas fa-history"></i> ${site.old_domain}`;
siteInfo.appendChild(oldDomain);
} siteItem.addEventListener('click', function() {
}
siteItem.addEventListener('click', function() {
window.open(site.full_url, '_blank', 'noopener,noreferrer');
});
@ -150,7 +227,7 @@ async function loadSiteData() {
siteItem.appendChild(siteTitle);
siteItem.appendChild(siteInfo);
siteList.appendChild(siteItem);
}
});
const formattedDate = latestUpdate.toLocaleDateString('it-IT', {
year: 'numeric',
@ -162,6 +239,7 @@ async function loadSiteData() {
document.getElementById('last-update-time').textContent = formattedDate;
} else {
siteList.innerHTML = '<div class="no-sites">No sites available</div>';
updateStatusIndicator('Ready', 'No sites found in database', 100);
}
} catch (error) {
console.error('Errore:', error);
@ -171,6 +249,10 @@ async function loadSiteData() {
<button onclick="loadSiteData()" class="retry-button">Riprova</button>
</div>
`;
if (statusIndicator) {
updateStatusIndicator('Error', `Failed to load: ${error.message}`, 0);
statusIndicator.querySelector('.status-icon').style.background = '#f44336';
}
}
}

View File

@ -1,5 +1,5 @@
<p align="center">
<img src="https://i.ibb.co/v6RnT0wY/s2.jpg" alt="Project Logo" width="600"/>
<img src="https://i.ibb.co/v6RnT0wY/s2.jpg" alt="Project Logo" width="450"/>
</p>
<p align="center">

View File

@ -31,7 +31,8 @@ class ScrapSerie:
self.client = httpx.Client(
cookies={"sessionId": self.session_id},
headers={"User-Agent": get_userAgent(), "csrf-token": self.csrf_token},
base_url=full_url
base_url=full_url,
verify=False
)
try:

View File

@ -21,7 +21,7 @@ from .film import download_film
# Variable
indice = 5
_useFor = "Film_&_Serie"
_priority = 1 # NOTE: Site search need the use of tmbd obj
_priority = 0
_engineDownload = "hls"
_deprecate = False

View File

@ -1,9 +1,5 @@
# 21.05.24
import threading
import queue
# External libraries
import httpx
from rich.console import Console
@ -13,12 +9,9 @@ from rich.console import Console
from StreamingCommunity.Util.config_json import config_manager
from StreamingCommunity.Util.headers import get_userAgent
from StreamingCommunity.Util.table import TVShowManager
from StreamingCommunity.Lib.TMBD.tmdb import tmdb
# Logic class
from StreamingCommunity.Api.Template.config_loader import site_constant
from StreamingCommunity.Api.Template.Class.SearchType import MediaManager
from .util.ScrapeSerie import GetSerieInfo
# Variable
@ -26,76 +19,33 @@ console = Console()
media_search_manager = MediaManager()
table_show_manager = TVShowManager()
max_timeout = config_manager.get_int("REQUESTS", "timeout")
MAX_THREADS = 12
def determine_media_type(title):
def determine_media_type(item):
"""
Use TMDB to determine if a title is a movie or TV show.
Determine if the item is a film or TV series by checking actual seasons count
using GetSerieInfo.
"""
try:
# First search as a movie
movie_results = tmdb._make_request("search/movie", {"query": title})
movie_count = len(movie_results.get("results", []))
# Then search as a TV show
tv_results = tmdb._make_request("search/tv", {"query": title})
tv_count = len(tv_results.get("results", []))
# If results found in only one category, use that
if movie_count > 0 and tv_count == 0:
return "film"
elif tv_count > 0 and movie_count == 0:
return "tv"
# If both have results, compare popularity
if movie_count > 0 and tv_count > 0:
top_movie = movie_results["results"][0]
top_tv = tv_results["results"][0]
return "film" if top_movie.get("popularity", 0) > top_tv.get("popularity", 0) else "tv"
# Extract program name from path_id
program_name = None
if item.get('path_id'):
parts = item['path_id'].strip('/').split('/')
if len(parts) >= 2:
program_name = parts[-1].split('.')[0]
return "film"
if not program_name:
return "film"
scraper = GetSerieInfo(program_name)
scraper.collect_info_title()
return "tv" if scraper.getNumberSeason() > 0 else "film"
except Exception as e:
console.log(f"Error determining media type with TMDB: {e}")
console.print(f"[red]Error determining media type: {e}[/red]")
return "film"
def worker_determine_type(work_queue, result_dict, worker_id):
"""
Worker function to process items from queue and determine media types.
Parameters:
- work_queue: Queue containing items to process
- result_dict: Dictionary to store results
- worker_id: ID of the worker thread
"""
while not work_queue.empty():
try:
index, item = work_queue.get(block=False)
title = item.get('titolo', '')
media_type = determine_media_type(title)
result_dict[index] = {
'id': item.get('id', ''),
'name': title,
'type': media_type,
'path_id': item.get('path_id', ''),
'url': f"https://www.raiplay.it{item.get('url', '')}",
'image': f"https://www.raiplay.it{item.get('immagine', '')}",
}
work_queue.task_done()
except queue.Empty:
break
except Exception as e:
console.log(f"Worker {worker_id} error: {e}")
work_queue.task_done()
def title_search(query: str) -> int:
"""
Search for titles based on a search query.
@ -141,33 +91,15 @@ def title_search(query: str) -> int:
data = response.json().get('agg').get('titoli').get('cards')
data = data[:15] if len(data) > 15 else data
# Use multithreading to determine media types in parallel
work_queue = queue.Queue()
result_dict = {}
# Add items to the work queue
for i, item in enumerate(data):
work_queue.put((i, item))
# Create and start worker threads
threads = []
for i in range(min(MAX_THREADS, len(data))):
thread = threading.Thread(
target=worker_determine_type,
args=(work_queue, result_dict, i),
daemon=True
)
threads.append(thread)
thread.start()
# Wait for all threads to complete
for thread in threads:
thread.join()
# Add all results to media manager in correct order
for i in range(len(data)):
if i in result_dict:
media_search_manager.add_media(result_dict[i])
# Process each item and add to media manager
for item in data:
media_search_manager.add_media({
'id': item.get('id', ''),
'name': item.get('titolo', ''),
'type': determine_media_type(item),
'path_id': item.get('path_id', ''),
'url': f"https://www.raiplay.it{item.get('url', '')}",
'image': f"https://www.raiplay.it{item.get('immagine', '')}",
})
# Return the number of titles found
return media_search_manager.get_length()

View File

@ -30,28 +30,48 @@ class GetSerieInfo:
try:
program_url = f"{self.base_url}/programmi/{self.program_name}.json"
response = httpx.get(url=program_url, headers=get_headers(), timeout=max_timeout)
# If 404, content is not yet available
if response.status_code == 404:
logging.info(f"Content not yet available: {self.program_name}")
return
response.raise_for_status()
json_data = response.json()
# Look for seasons in the 'blocks' property
for block in json_data.get('blocks'):
if block.get('type') == 'RaiPlay Multimedia Block' and block.get('name', '').lower() == 'episodi':
self.publishing_block_id = block.get('id')
# Extract seasons from sets array
for season_set in block.get('sets', []):
if 'stagione' in season_set.get('name', '').lower():
self.seasons_manager.add_season({
'id': season_set.get('id', ''),
'number': len(self.seasons_manager.seasons) + 1,
'name': season_set.get('name', ''),
'path': season_set.get('path_id', ''),
'episodes_count': season_set.get('episode_size', {}).get('number', 0)
})
for block in json_data.get('blocks', []):
except Exception as e:
# Check if block is a season block or episodi block
if block.get('type') == 'RaiPlay Multimedia Block':
if block.get('name', '').lower() == 'episodi':
self.publishing_block_id = block.get('id')
# Extract seasons from sets array
for season_set in block.get('sets', []):
if 'stagione' in season_set.get('name', '').lower():
self._add_season(season_set, block.get('id'))
elif 'stagione' in block.get('name', '').lower():
self.publishing_block_id = block.get('id')
# Extract season directly from block's sets
for season_set in block.get('sets', []):
self._add_season(season_set, block.get('id'))
except httpx.HTTPError as e:
logging.error(f"Error collecting series info: {e}")
except Exception as e:
logging.error(f"Unexpected error collecting series info: {e}")
def _add_season(self, season_set: dict, block_id: str):
self.seasons_manager.add_season({
'id': season_set.get('id', ''),
'number': len(self.seasons_manager.seasons) + 1,
'name': season_set.get('name', ''),
'path': season_set.get('path_id', ''),
'episodes_count': season_set.get('episode_size', {}).get('number', 0)
})
def collect_info_season(self, number_season: int) -> None:
"""Get episodes for a specific season."""

View File

@ -39,9 +39,6 @@ class ConfigManager:
# Get the actual path of the module file
current_file_path = os.path.abspath(__file__)
# Navigate upwards to find the project root
# Assuming this file is in a package structure like StreamingCommunity/Util/config_json.py
# We need to go up 2 levels to reach the project root
base_path = os.path.dirname(os.path.dirname(os.path.dirname(current_file_path)))
# Initialize file paths
@ -562,7 +559,6 @@ class ConfigManager:
return section in config_source
# Helper function to check the platform
def get_use_large_bar():
"""
Determine if the large bar feature should be enabled.

View File

@ -296,12 +296,6 @@ class InternManager():
"Google": ["8.8.8.8", "8.8.4.4"],
"OpenDNS": ["208.67.222.222", "208.67.220.220"],
"Quad9": ["9.9.9.9", "149.112.112.112"],
"AdGuard": ["94.140.14.14", "94.140.15.15"],
"Comodo": ["8.26.56.26", "8.20.247.20"],
"Level3": ["209.244.0.3", "209.244.0.4"],
"Norton": ["199.85.126.10", "199.85.127.10"],
"CleanBrowsing": ["185.228.168.9", "185.228.169.9"],
"Yandex": ["77.88.8.8", "77.88.8.1"]
}
try: