From 661cb949e0213f965fc0328e5e3e07db4690b57e Mon Sep 17 00:00:00 2001 From: Ghost <62809003+Ghost6446@users.noreply.github.com> Date: Sun, 9 Jun 2024 17:45:03 +0200 Subject: [PATCH] Add guardaserie ... --- Src/Api/Altadefinizione/film.py | 2 +- Src/Api/Animeunity/anime.py | 9 +- Src/Api/Ddlstreamitaly/site.py | 6 +- Src/Api/Guardaserie/Core/Player/supervideo.py | 170 ++++++++++++++++++ Src/Api/Guardaserie/__init__.py | 3 + Src/Api/Guardaserie/costant.py | 4 + Src/Api/Guardaserie/site.py | 68 +++++++ Src/Api/Streamingcommunity/film.py | 2 +- run.py | 11 +- 9 files changed, 258 insertions(+), 17 deletions(-) create mode 100644 Src/Api/Guardaserie/Core/Player/supervideo.py create mode 100644 Src/Api/Guardaserie/__init__.py create mode 100644 Src/Api/Guardaserie/costant.py create mode 100644 Src/Api/Guardaserie/site.py diff --git a/Src/Api/Altadefinizione/film.py b/Src/Api/Altadefinizione/film.py index ff69187..5b6d1f8 100644 --- a/Src/Api/Altadefinizione/film.py +++ b/Src/Api/Altadefinizione/film.py @@ -50,7 +50,7 @@ def download_film(title_name: str, url: str): # Get m3u8 master playlist master_playlist = video_source.get_playlist() - # Download the film using the m3u8 playlist, key, and output filename + # Download the film using the m3u8 playlist, and output filename Downloader( m3u8_playlist = master_playlist, output_filename = os.path.join(mp4_path, mp4_name) diff --git a/Src/Api/Animeunity/anime.py b/Src/Api/Animeunity/anime.py index 9d236ed..7b030c7 100644 --- a/Src/Api/Animeunity/anime.py +++ b/Src/Api/Animeunity/anime.py @@ -54,14 +54,11 @@ def download_episode(index_select: int): else: mp4_path = os.path.join(ROOT_PATH, MAIN_FOLDER, MOVIE_FOLDER, video_source.series_name) - # Crete downloader - obj_download = Downloader( + # Start downloading + Downloader( m3u8_playlist = video_source.get_playlist(), output_filename = os.path.join(mp4_path, mp4_name) - ) - - # Start downloading - obj_download.start() + ).start() def donwload_series(tv_id: int, tv_name: str): diff --git a/Src/Api/Ddlstreamitaly/site.py b/Src/Api/Ddlstreamitaly/site.py index e8a5804..3d2c1bb 100644 --- a/Src/Api/Ddlstreamitaly/site.py +++ b/Src/Api/Ddlstreamitaly/site.py @@ -60,14 +60,14 @@ def title_search() -> int: parsed_url = urlparse(url_search) path_parts = parsed_url.path.split('/') - title_name = path_parts[-2] if path_parts[-1] == '' else path_parts[-1] + ".mp4" + mp4_name = path_parts[-2] if path_parts[-1] == '' else path_parts[-1] + ".mp4" # Create destination folder mp4_path = os.path.join(ROOT_PATH, MAIN_FOLDER, MOVIE_FOLDER) # Check if can create file output create_folder(mp4_path) - if not can_create_file(title_name): + if not can_create_file(mp4_name): logging.error("Invalid mp4 name.") sys.exit(0) @@ -75,7 +75,7 @@ def title_search() -> int: start_message() MP4_downloader( url = mp4_link, - path = os.path.join(mp4_path, title_name), + path = os.path.join(mp4_path, mp4_name), referer = f"{parsed_url.scheme}://{parsed_url.netloc}/", add_desc=f"{Colors.MAGENTA}video" ) diff --git a/Src/Api/Guardaserie/Core/Player/supervideo.py b/Src/Api/Guardaserie/Core/Player/supervideo.py new file mode 100644 index 0000000..44292ef --- /dev/null +++ b/Src/Api/Guardaserie/Core/Player/supervideo.py @@ -0,0 +1,170 @@ +# 26.05.24 + +import re +import sys +import logging + + +# External libraries +import requests +from bs4 import BeautifulSoup + + +# Internal utilities +from Src.Util.headers import get_headers +from Src.Util.os import run_node_script + + +class VideoSource: + + def __init__(self) -> None: + """ + Initializes the VideoSource object with default values. + + Attributes: + headers (dict): An empty dictionary to store HTTP headers. + """ + self.headers = {'user-agent': get_headers()} + + def setup(self, url: str) -> None: + """ + Sets up the video source with the provided URL. + + Args: + url (str): The URL of the video source. + """ + self.url = url + + def make_request(self, url: str) -> str: + """ + Make an HTTP GET request to the provided URL. + + Args: + url (str): The URL to make the request to. + + Returns: + str: The response content if successful, None otherwise. + """ + + try: + response = requests.get(url, headers=self.headers) + response.raise_for_status() + + with open('index.html', 'w', encoding='utf-8') as file: + file.write(response.text) + + return response.text + + except Exception as e: + logging.error(f"Request failed: {e}") + return None + + def parse_html(self, html_content: str) -> BeautifulSoup: + """ + Parse the provided HTML content using BeautifulSoup. + + Args: + html_content (str): The HTML content to parse. + + Returns: + BeautifulSoup: Parsed HTML content if successful, None otherwise. + """ + + try: + soup = BeautifulSoup(html_content, "html.parser") + return soup + + except Exception as e: + logging.error(f"Failed to parse HTML content: {e}") + return None + + def get_iframe(self, soup): + """ + Extracts the source URL of the second iframe in the provided BeautifulSoup object. + + Args: + soup (BeautifulSoup): A BeautifulSoup object representing the parsed HTML. + + Returns: + str: The source URL of the second iframe, or None if not found. + """ + tag_a = soup.find_all('a', href='#') + if tag_a and len(tag_a) > 1: + return tag_a[1].get("data-link") + + return None + + def find_content(self, url): + """ + Makes a request to the specified URL and parses the HTML content. + + Args: + url (str): The URL to fetch content from. + + Returns: + BeautifulSoup: A BeautifulSoup object representing the parsed HTML content, or None if the request fails. + """ + content = self.make_request(url) + if content: + return self.parse_html(content) + + return None + + def get_result_node_js(self, soup): + """ + Prepares and runs a Node.js script from the provided BeautifulSoup object to retrieve the video URL. + + Args: + soup (BeautifulSoup): A BeautifulSoup object representing the parsed HTML content. + + Returns: + str: The output from the Node.js script, or None if the script cannot be found or executed. + """ + for script in soup.find_all("script"): + if "eval" in str(script): + new_script = str(script.text).replace("eval", "var a = ") + new_script = new_script.replace(")))", ")));console.log(a);") + return run_node_script(new_script) + + return None + + def get_playlist(self) -> str: + """ + Download a video from the provided URL. + + Returns: + str: The URL of the downloaded video if successful, None otherwise. + """ + try: + html_content = self.make_request(self.url) + if not html_content: + logging.error("Failed to fetch HTML content.") + return None + + soup = self.parse_html(html_content) + if not soup: + logging.error("Failed to parse HTML content.") + return None + + iframe_src = self.get_iframe(soup) + if not iframe_src: + logging.error("No iframe found.") + return None + + down_page_soup = self.find_content(iframe_src) + if not down_page_soup: + logging.error("Failed to fetch down page content.") + return None + + result = self.get_result_node_js(down_page_soup) + if not result: + logging.error("No video URL found in script.") + return None + + master_playlist = str(result).split(":")[3].split('"}')[0] + return f"https:{master_playlist}" + + except Exception as e: + logging.error(f"An error occurred: {e}") + return None + diff --git a/Src/Api/Guardaserie/__init__.py b/Src/Api/Guardaserie/__init__.py new file mode 100644 index 0000000..f42d854 --- /dev/null +++ b/Src/Api/Guardaserie/__init__.py @@ -0,0 +1,3 @@ +# 09.06.24 + +from .site import title_search \ No newline at end of file diff --git a/Src/Api/Guardaserie/costant.py b/Src/Api/Guardaserie/costant.py new file mode 100644 index 0000000..512ce52 --- /dev/null +++ b/Src/Api/Guardaserie/costant.py @@ -0,0 +1,4 @@ +# 09.06.24 + +MAIN_FOLDER = "guardaserie" +MOVIE_FOLDER = "Serie" diff --git a/Src/Api/Guardaserie/site.py b/Src/Api/Guardaserie/site.py new file mode 100644 index 0000000..cdbab6e --- /dev/null +++ b/Src/Api/Guardaserie/site.py @@ -0,0 +1,68 @@ +# 09.06.24 + +import os +import sys +import logging +from urllib.parse import urlparse + + +# External libraries +import requests + + +# Internal utilities +from Src.Util.console import console, msg +from Src.Util.os import create_folder, can_create_file +from Src.Util._jsonConfig import config_manager +from Src.Util.headers import get_headers +from Src.Lib.Hls.downloader import Downloader + + +# Logic class +from .Core.Player.supervideo import VideoSource + + +# Config +ROOT_PATH = config_manager.get('DEFAULT', 'root_path') +from .costant import MAIN_FOLDER, MOVIE_FOLDER + + +def title_search() -> int: + """ + Search for titles based on a search query. + """ + + print() + url_search = msg.ask(f"[cyan]Insert url title") + + # Send request to search for titles + response = requests.get(url_search, headers={'user-agent': get_headers()}) + response.raise_for_status() + + # Get playlist + video_source = VideoSource() + video_source.setup(url_search) + + + parsed_url = urlparse(url_search) + path_parts = parsed_url.path.split('/') + mp4_name = path_parts[-2] if path_parts[-1] == '' else path_parts[-1] + ".mp4" + + # Create destination folder + mp4_path = os.path.join(ROOT_PATH, MAIN_FOLDER, MOVIE_FOLDER) + + # Check if can create file output + create_folder(mp4_path) + if not can_create_file(mp4_name): + logging.error("Invalid mp4 name.") + sys.exit(0) + + + # Get m3u8 master playlist + master_playlist = video_source.get_playlist() + + # Download the film using the m3u8 playlist, and output filename + Downloader( + m3u8_playlist = master_playlist, + output_filename = os.path.join(mp4_path, mp4_name) + ).start() \ No newline at end of file diff --git a/Src/Api/Streamingcommunity/film.py b/Src/Api/Streamingcommunity/film.py index deff998..b564649 100644 --- a/Src/Api/Streamingcommunity/film.py +++ b/Src/Api/Streamingcommunity/film.py @@ -55,7 +55,7 @@ def download_film(id_film: str, title_name: str, domain: str): mp4_format = (mp4_name) + ".mp4" mp4_path = os.path.join(ROOT_PATH, MAIN_FOLDER, MOVIE_FOLDER, title_name) - # Download the film using the m3u8 playlist, key, and output filename + # Download the film using the m3u8 playlist, and output filename Downloader( m3u8_playlist = master_playlist, output_filename = os.path.join(mp4_path, mp4_format) diff --git a/run.py b/run.py index b926326..5e77350 100644 --- a/run.py +++ b/run.py @@ -22,6 +22,7 @@ from Src.Api.Streamingcommunity import main_film_series as streamingcommunity_fi from Src.Api.Animeunity import main_anime as streamingcommunity_anime from Src.Api.Altadefinizione import main_film as altadefinizione_film from Src.Api.Ddlstreamitaly import title_search as ddlstreamitaly_film_serie +from Src.Api.Guardaserie import title_search as guardaserie_serie # Config @@ -81,16 +82,12 @@ def main(): parser = argparse.ArgumentParser(description='Script to download film and series from the internet.') parser.add_argument('-sa', '--streaming_anime', action='store_true', help='') parser.add_argument('-sf', '--streaming_film', action='store_true', help='') - parser.add_argument('-af', '--altadefinizione_film', action='store_true', help='') - parser.add_argument('-ddd', '--ddlstreamitaly_film_serie', action='store_true', help='') args = parser.parse_args() # Mapping command-line arguments to functions arg_to_function = { 'streaming_anime': streamingcommunity_anime, 'streaming_film': streamingcommunity_film_serie, - 'altadefinizione_film': altadefinizione_film, - 'ddlstreamitaly_film_serie': ddlstreamitaly_film_serie } # Check which argument is provided and run the corresponding function @@ -104,7 +101,8 @@ def main(): '0': streamingcommunity_film_serie, '1': streamingcommunity_anime, '2': altadefinizione_film, - '3': ddlstreamitaly_film_serie + '3': ddlstreamitaly_film_serie, + '4': guardaserie_serie, } # Create dynamic prompt message and choices @@ -113,7 +111,8 @@ def main(): '0': "Streamingcommunity", '1': "Animeunity", '2': "Altadefinizione", - '3': "Ddlstreamitaly" + '3': "Ddlstreamitaly", + '4': "Guardaserie", } prompt_message = "[cyan]Insert category [white](" + ", ".join( f"[red]{key}[white]: [bold magenta]{label}[white]" for key, label in choice_labels.items()