Minor fix

This commit is contained in:
Lovi 2024-12-01 14:13:53 +01:00
parent 6d06a3421f
commit eeb60d989a
16 changed files with 74 additions and 385 deletions

View File

@ -11,5 +11,5 @@ SITE_NAME = os.path.basename(os.path.dirname(os.path.abspath(__file__)))
ROOT_PATH = config_manager.get('DEFAULT', 'root_path')
DOMAIN_NOW = config_manager.get_dict('SITE', SITE_NAME)['domain']
SERIES_FOLDER = "Serie"
MOVIE_FOLDER = "Film"
SERIES_FOLDER = config_manager.get('DEFAULT', 'serie_folder_name')
MOVIE_FOLDER = config_manager.get('DEFAULT', 'movie_folder_name')

View File

@ -11,5 +11,5 @@ SITE_NAME = os.path.basename(os.path.dirname(os.path.abspath(__file__)))
ROOT_PATH = config_manager.get('DEFAULT', 'root_path')
DOMAIN_NOW = config_manager.get_dict('SITE', SITE_NAME)['domain']
MOVIE_FOLDER = "Movie"
SERIES_FOLDER= "Serie"
SERIES_FOLDER = config_manager.get('DEFAULT', 'serie_folder_name')
MOVIE_FOLDER = config_manager.get('DEFAULT', 'movie_folder_name')

View File

@ -1,126 +0,0 @@
# 11.03.24
import os
import sys
import logging
# Internal utilities
from StreamingCommunity.Util.console import console, msg
from StreamingCommunity.Util.os import os_manager
from StreamingCommunity.Util.message import start_message
from StreamingCommunity.Lib.Downloader import MP4_downloader
# Logic class
from StreamingCommunity.Api.Template.Util import manage_selection
from StreamingCommunity.Api.Template.Class.SearchType import MediaItem
# Player
from StreamingCommunity.Api.Player.vixcloud import AnimeVideoSource as VideoSource
# Variable
from .costant import ROOT_PATH, SITE_NAME, SERIES_FOLDER, MOVIE_FOLDER
video_source = VideoSource(site_name=SITE_NAME)
def download_episode(index_select: int):
"""
Downloads the selected episode.
Parameters:
- index_select (int): Index of the episode to download.
"""
# Get information about the selected episode
obj_episode = video_source.get_info_episode(index_select)
if obj_episode is not None:
start_message()
console.print(f"[yellow]Download: [red]EP_{obj_episode.number} \n")
# Get the js script from the episode
js_script = video_source.get_embed(obj_episode.id)
# Parse parameter in embed text
video_source.parse_script(js_script)
# Create output path
title_name = f"{obj_episode.number}.mp4"
if video_source.is_series:
mp4_path = os_manager.get_sanitize_path(
os.path.join(ROOT_PATH, SITE_NAME, SERIES_FOLDER, video_source.series_name)
)
else:
mp4_path = os_manager.get_sanitize_path(
os.path.join(ROOT_PATH, SITE_NAME, MOVIE_FOLDER, video_source.series_name)
)
# Create output folder
os_manager.create_path(mp4_path)
# Start downloading
r_proc = MP4_downloader(
url = str(video_source.src_mp4).strip(),
path = os.path.join(mp4_path, title_name)
)
if r_proc != None:
console.print("[green]Result: ")
console.print(r_proc)
else:
logging.error(f"Skip index: {index_select} cant find info with api.")
def download_series(select_title: MediaItem):
"""
Function to download episodes of a TV series.
Parameters:
- tv_id (int): The ID of the TV series.
- tv_name (str): The name of the TV series.
"""
# Set up video source
video_source.setup(select_title.id, select_title.slug)
# Get the count of episodes for the TV series
episoded_count = video_source.get_count_episodes()
console.log(f"[cyan]Episodes find: [red]{episoded_count}")
# Prompt user to select an episode index
last_command = msg.ask("\n[cyan]Insert media [red]index [yellow]or [red](*) [cyan]to download all media [yellow]or [red][1-2] [cyan]or [red][3-*] [cyan]for a range of media")
# Manage user selection
list_episode_select = manage_selection(last_command, episoded_count)
# Download selected episodes
if len(list_episode_select) == 1 and last_command != "*":
download_episode(list_episode_select[0]-1)
# Download all other episodes selecter
else:
for i_episode in list_episode_select:
download_episode(i_episode-1)
def download_film(select_title: MediaItem):
"""
Function to download a film.
Parameters:
- id_film (int): The ID of the film.
- title_name (str): The title of the film.
"""
# Set up video source
video_source.setup(select_title.id, select_title.slug)
video_source.is_series = False
# Start download
download_episode(0)

View File

@ -11,5 +11,5 @@ SITE_NAME = os.path.basename(os.path.dirname(os.path.abspath(__file__)))
ROOT_PATH = config_manager.get('DEFAULT', 'root_path')
DOMAIN_NOW = config_manager.get_dict('SITE', SITE_NAME)['domain']
SERIES_FOLDER= "Serie"
MOVIE_FOLDER = "Movie"
SERIES_FOLDER = config_manager.get('DEFAULT', 'serie_folder_name')
MOVIE_FOLDER = config_manager.get('DEFAULT', 'movie_folder_name')

View File

@ -11,5 +11,5 @@ SITE_NAME = os.path.basename(os.path.dirname(os.path.abspath(__file__)))
ROOT_PATH = config_manager.get('DEFAULT', 'root_path')
DOMAIN_NOW = config_manager.get_dict('SITE', SITE_NAME)['domain']
SERIES_FOLDER = "Serie"
MOVIE_FOLDER = "Film"
SERIES_FOLDER = config_manager.get('DEFAULT', 'serie_folder_name')
MOVIE_FOLDER = config_manager.get('DEFAULT', 'movie_folder_name')

View File

@ -11,5 +11,5 @@ SITE_NAME = os.path.basename(os.path.dirname(os.path.abspath(__file__)))
ROOT_PATH = config_manager.get('DEFAULT', 'root_path')
DOMAIN_NOW = config_manager.get_dict('SITE', SITE_NAME)['domain']
MOVIE_FOLDER = "Movie"
SERIES_FOLDER = "Serie"
SERIES_FOLDER = config_manager.get('DEFAULT', 'serie_folder_name')
MOVIE_FOLDER = config_manager.get('DEFAULT', 'movie_folder_name')

View File

@ -1,85 +0,0 @@
# 13.06.24
import sys
import logging
from typing import List, Dict
# External libraries
import httpx
from bs4 import BeautifulSoup
# Internal utilities
from StreamingCommunity.Util._jsonConfig import config_manager
from StreamingCommunity.Util.headers import get_headers
# Logic class
from StreamingCommunity.Api.Template.Class.SearchType import MediaItem
# Variable
from ..costant import COOKIE
max_timeout = config_manager.get_int("REQUESTS", "timeout")
class GetSerieInfo:
def __init__(self, dict_serie: MediaItem) -> None:
"""
Initializes the GetSerieInfo object with default values.
Parameters:
- dict_serie (MediaItem): Dictionary containing series information (optional).
"""
self.headers = {'user-agent': get_headers()}
self.cookies = COOKIE
self.url = dict_serie.url
self.tv_name = None
self.list_episodes = None
def get_episode_number(self) -> List[Dict[str, str]]:
"""
Retrieves the number of episodes for a specific season.
Parameters:
n_season (int): The season number.
Returns:
List[Dict[str, str]]: List of dictionaries containing episode information.
"""
try:
response = httpx.get(self.url + "?area=online", cookies=self.cookies, headers=self.headers, timeout=max_timeout)
response.raise_for_status()
except:
logging.error(f"Insert value for [ips4_device_key, ips4_member_id, ips4_login_key] in config.json file SITE \\ ddlstreamitaly \\ cookie. Use browser debug and cookie request with a valid account, filter by DOC.")
sys.exit(0)
# Parse HTML content of the page
soup = BeautifulSoup(response.text, "html.parser")
# Get tv name
self.tv_name = soup.find("span", class_= "ipsType_break").get_text(strip=True)
# Find the container of episodes for the specified season
table_content = soup.find('div', class_='ipsMargin_bottom:half')
list_dict_episode = []
for episode_div in table_content.find_all('a', href=True):
# Get text of episode
part_name = episode_div.get_text(strip=True)
if part_name:
obj_episode = {
'name': part_name,
'url': episode_div['href']
}
list_dict_episode.append(obj_episode)
self.list_episodes = list_dict_episode
return list_dict_episode

View File

@ -12,5 +12,5 @@ ROOT_PATH = config_manager.get('DEFAULT', 'root_path')
DOMAIN_NOW = config_manager.get_dict('SITE', SITE_NAME)['domain']
COOKIE = config_manager.get_dict('SITE', SITE_NAME)['cookie']
MOVIE_FOLDER = "Movie"
SERIES_FOLDER = "Serie"
SERIES_FOLDER = config_manager.get('DEFAULT', 'serie_folder_name')
MOVIE_FOLDER = config_manager.get('DEFAULT', 'movie_folder_name')

View File

@ -1,115 +0,0 @@
# 13.06.24
import logging
from typing import List, Dict
# External libraries
import httpx
from bs4 import BeautifulSoup
# Internal utilities
from StreamingCommunity.Util._jsonConfig import config_manager
from StreamingCommunity.Util.headers import get_headers
# Logic class
from StreamingCommunity.Api.Template .Class.SearchType import MediaItem
# Variable
max_timeout = config_manager.get_int("REQUESTS", "timeout")
class GetSerieInfo:
def __init__(self, dict_serie: MediaItem) -> None:
"""
Initializes the GetSerieInfo object with default values.
Parameters:
dict_serie (MediaItem): Dictionary containing series information (optional).
"""
self.headers = {'user-agent': get_headers()}
self.url = dict_serie.url
self.tv_name = None
self.list_episodes = None
def get_seasons_number(self) -> int:
"""
Retrieves the number of seasons of a TV series.
Returns:
int: Number of seasons of the TV series.
"""
try:
# Make an HTTP request to the series URL
response = httpx.get(self.url, headers=self.headers, timeout=max_timeout)
response.raise_for_status()
# Parse HTML content of the page
soup = BeautifulSoup(response.text, "html.parser")
# Find the container of seasons
table_content = soup.find('div', class_="tt_season")
# Count the number of seasons
seasons_number = len(table_content.find_all("li"))
# Extract the name of the series
self.tv_name = soup.find("h1", class_="front_title").get_text(strip=True)
return seasons_number
except Exception as e:
logging.error(f"Error parsing HTML page: {e}")
return -999
def get_episode_number(self, n_season: int) -> List[Dict[str, str]]:
"""
Retrieves the number of episodes for a specific season.
Parameters:
n_season (int): The season number.
Returns:
List[Dict[str, str]]: List of dictionaries containing episode information.
"""
try:
# Make an HTTP request to the series URL
response = httpx.get(self.url, headers=self.headers, timeout=max_timeout)
response.raise_for_status()
# Parse HTML content of the page
soup = BeautifulSoup(response.text, "html.parser")
# Find the container of episodes for the specified season
table_content = soup.find('div', class_="tab-pane", id=f"season-{n_season}")
# Extract episode information
episode_content = table_content.find_all("li")
list_dict_episode = []
for episode_div in episode_content:
index = episode_div.find("a").get("data-num")
link = episode_div.find("a").get("data-link")
name = episode_div.find("a").get("data-title")
obj_episode = {
'number': index,
'name': name,
'url': link
}
list_dict_episode.append(obj_episode)
self.list_episodes = list_dict_episode
return list_dict_episode
except Exception as e:
logging.error(f"Error parsing HTML page: {e}")
return []

View File

@ -11,5 +11,5 @@ SITE_NAME = os.path.basename(os.path.dirname(os.path.abspath(__file__)))
ROOT_PATH = config_manager.get('DEFAULT', 'root_path')
DOMAIN_NOW = config_manager.get_dict('SITE', SITE_NAME)['domain']
SERIES_FOLDER = "Serie"
MOVIE_FOLDER = "Film"
SERIES_FOLDER = config_manager.get('DEFAULT', 'serie_folder_name')
MOVIE_FOLDER = config_manager.get('DEFAULT', 'movie_folder_name')

View File

@ -11,5 +11,5 @@ SITE_NAME = os.path.basename(os.path.dirname(os.path.abspath(__file__)))
ROOT_PATH = config_manager.get('DEFAULT', 'root_path')
DOMAIN_NOW = config_manager.get_dict('SITE', SITE_NAME)['domain']
MOVIE_FOLDER = "Movie"
SERIES_FOLDER= "Serie"
SERIES_FOLDER = config_manager.get('DEFAULT', 'serie_folder_name')
MOVIE_FOLDER = config_manager.get('DEFAULT', 'movie_folder_name')

View File

@ -11,5 +11,5 @@ SITE_NAME = os.path.basename(os.path.dirname(os.path.abspath(__file__)))
ROOT_PATH = config_manager.get('DEFAULT', 'root_path')
DOMAIN_NOW = config_manager.get_dict('SITE', SITE_NAME)['domain']
SERIES_FOLDER = "Serie"
MOVIE_FOLDER = "Film"
SERIES_FOLDER = config_manager.get('DEFAULT', 'serie_folder_name')
MOVIE_FOLDER = config_manager.get('DEFAULT', 'movie_folder_name')

View File

@ -11,5 +11,5 @@ SITE_NAME = os.path.basename(os.path.dirname(os.path.abspath(__file__)))
ROOT_PATH = config_manager.get('DEFAULT', 'root_path')
DOMAIN_NOW = config_manager.get('SITE', SITE_NAME)
MOVIE_FOLDER = "Movie"
SERIES_FOLDER = "Serie"
SERIES_FOLDER = config_manager.get('DEFAULT', 'serie_folder_name')
MOVIE_FOLDER = config_manager.get('DEFAULT', 'movie_folder_name')

View File

@ -11,6 +11,7 @@ import shutil
import glob
from typing import Optional, Tuple
# External library
from rich.console import Console
from rich.progress import Progress, SpinnerColumn, BarColumn, TextColumn, TimeRemainingColumn
@ -18,7 +19,6 @@ from rich.progress import Progress, SpinnerColumn, BarColumn, TextColumn, TimeRe
# Variable
console = Console()
FFMPEG_CONFIGURATION = {
'windows': {
'base_dir': lambda home: os.path.join(os.path.splitdrive(home)[0] + os.path.sep, 'binary'),
@ -208,7 +208,7 @@ class FFMPEGDownloader:
Returns paths of ffmpeg and ffprobe
"""
# First, check if binaries already exist in base directory
existing_ffmpeg, existing_ffprobe = self._check_existing_binaries()
existing_ffmpeg, existing_ffprobe, existing_ffplay = self._check_existing_binaries()
if existing_ffmpeg and existing_ffprobe:
return existing_ffmpeg, existing_ffprobe

View File

@ -13,7 +13,7 @@ import subprocess
import contextlib
import pathvalidate
import urllib.request
import pkg_resources
import importlib.metadata
# External library
@ -318,7 +318,6 @@ class OsSummary():
Returns:
str: The version string of the executable.
"""
try:
version_output = subprocess.check_output(command, stderr=subprocess.STDOUT).decode().split('\n')[0]
return version_output.split(" ")[2]
@ -327,6 +326,21 @@ class OsSummary():
console.print(f"{command[0]} not found", style="bold red")
sys.exit(0)
def check_ffmpeg_location(self, command: list):
"""
Run 'where ffmpeg' command to check FFmpeg's location.
Returns:
str: Location of FFmpeg executable or None if not found
"""
try:
result = subprocess.check_output(command, stderr=subprocess.STDOUT, text=True).strip()
return result
except subprocess.CalledProcessError:
console.print("FFmpeg not found in system PATH", style="bold red")
sys.exit(0)
def get_library_version(self, lib_name: str):
"""
Retrieve the version of a Python library.
@ -338,40 +352,35 @@ class OsSummary():
str: The library name followed by its version, or `-not installed` if not found.
"""
try:
version = pkg_resources.get_distribution(lib_name).version
version = importlib.metadata.version(lib_name)
return f"{lib_name}-{version}"
except pkg_resources.DistributionNotFound as e:
logging.error(f"Error with get_library_version (1): {e}")
return f"{lib_name}-not installed"
except Exception as e:
logging.error(f"Error with get_library_version (2): {e}")
except importlib.metadata.PackageNotFoundError:
return f"{lib_name}-not installed"
async def download_requirements(self, url: str, filename: str):
def download_requirements(self, url: str, filename: str):
"""
Download the requirements.txt file from the specified URL if not found locally using httpx.
Download the requirements.txt file from the specified URL if not found locally using requests.
Args:
url (str): The URL to download the requirements file from.
filename (str): The local filename to save the requirements file as.
"""
try:
async with httpx.AsyncClient() as client:
console.print(f"{filename} not found locally. Downloading from {url}...", style="bold yellow")
response = await client.get(url)
if response.status_code == 200:
with open(filename, 'wb') as f:
f.write(response.content)
console.print(f"{filename} successfully downloaded.", style="bold green")
else:
console.print(f"Failed to download {filename}. HTTP Status code: {response.status_code}", style="bold red")
sys.exit(1)
import requests
console.print(f"{filename} not found locally. Downloading from {url}...", style="bold yellow")
response = requests.get(url)
if response.status_code == 200:
with open(filename, 'wb') as f:
f.write(response.content)
console.print(f"{filename} successfully downloaded.", style="bold green")
else:
console.print(f"Failed to download {filename}. HTTP Status code: {response.status_code}", style="bold red")
sys.exit(1)
except Exception as e:
console.print(f"Failed to download {filename}: {e}", style="bold red")
sys.exit(1)
@ -435,8 +444,14 @@ class OsSummary():
# ffmpeg and ffprobe versions
ffmpeg_path, ffprobe_path = check_ffmpeg()
ffmpeg_version = self.get_executable_version(['ffmpeg', '-version'])
ffprobe_version = self.get_executable_version(['ffprobe', '-version'])
# Locate ffmpeg and ffprobe
if "binary" not in ffmpeg_path:
ffmpeg_path = self.check_ffmpeg_location(['where', 'ffmpeg'])
if "binary" not in ffprobe_path:
ffprobe_path = self.check_ffmpeg_location(['where', 'ffprobe'])
ffmpeg_version = self.get_executable_version([ffprobe_path, '-version'])
ffprobe_version = self.get_executable_version([ffprobe_path, '-version'])
console.print(f"[cyan]Path[white]: [red]ffmpeg [bold yellow]'{ffmpeg_path}'[/bold yellow][white], [red]ffprobe '[bold yellow]{ffprobe_path}'[/bold yellow]")
console.print(f"[cyan]Exe versions[white]: [bold red]ffmpeg {ffmpeg_version}, ffprobe {ffprobe_version}[/bold red]")
@ -444,29 +459,27 @@ class OsSummary():
# Check if requirements.txt exists, if not on pyinstaller
if not getattr(sys, 'frozen', False):
requirements_file = 'requirements.txt'
if not os.path.exists(requirements_file):
await self.download_requirements(
self.download_requirements(
'https://raw.githubusercontent.com/Lovi-0/StreamingCommunity/refs/heads/main/requirements.txt',
requirements_file
)
# Read the optional libraries from the requirements file
optional_libraries = [line.strip() for line in open(requirements_file, 'r', encoding='utf-8-sig')]
# Read the optional libraries from the requirements file, get only name without version if "library==1.0.0"
optional_libraries = [line.strip().split("=")[0] for line in open(requirements_file, 'r', encoding='utf-8-sig')]
# Check if libraries are installed and prompt to install missing ones
for lib in optional_libraries:
installed_version = self.get_library_version(lib)
if 'not installed' in installed_version:
# Prompt user to install missing library using Prompt.ask()
user_response = msg.ask(f"{lib} is not installed. Do you want to install it? (yes/no)", default="y")
if user_response.lower().strip() in ["yes", "y"]:
self.install_library(lib)
else:
#console.print(f"[cyan]Library[white]: [bold red]{installed_version}[/bold red]")
logging.info(f"Library: {installed_version}")
console.print(f"[cyan]Libraries[white]: [bold red]{', '.join([self.get_library_version(lib) for lib in optional_libraries])}[/bold red]\n")

View File

@ -6,6 +6,8 @@
"show_message": true,
"clean_console": true,
"root_path": "Video",
"movie_folder_name": "Movie",
"serie_folder_name": "TV",
"map_episode_name": "%(tv_name)_S%(season)E%(episode)_%(episode_name)",
"config_qbit_tor": {
"host": "192.168.1.59",