Rewrite hls downloader

This commit is contained in:
Lovi 2024-10-17 18:21:59 +02:00
parent 45660f7a02
commit e3ddf7a00d
58 changed files with 777 additions and 1966 deletions

View File

@ -63,11 +63,11 @@ sudo chmod +x unix_install.sh && ./unix_install.sh
Run the script with the following command: Run the script with the following command:
#### On Windows: #### On Windows:
```powershell ```powershell
.\run.py python .\run.py
``` ```
or or
```powershell ```powershell
.venv\Scripts\python .\run.py source .venv/bin/activate && python run.py && deactivate
``` ```
#### On Linux/MacOS/BSD: #### On Linux/MacOS/BSD:
@ -257,9 +257,8 @@ The `run-container` command mounts also the `config.json` file, so any change to
<a id="tutorial"></a> <a id="tutorial"></a>
## Tutorial 📖 ## Tutorial 📖
For a detailed walkthrough, refer to the [video tutorial](https://www.youtube.com/watch?v=Ok7hQCgxqLg&ab_channel=Nothing) [win]("https://www.youtube.com/watch?v=mZGqK4wdN-k")
Add [api_1](https://www.youtube.com/watch?v=3ylBSMyQlhM) [linux]("https://www.youtube.com/watch?v=0qUNXPE_mTg")
Add [api_2](https://www.youtube.com/watch?v=ReEYUIbdbG4)
<a id="to-do"></a> <a id="to-do"></a>
## To do 📝 ## To do 📝

View File

@ -1,9 +1,5 @@
# 02.07.24 # 02.07.24
import sys
import logging
# External libraries # External libraries
import httpx import httpx
from bs4 import BeautifulSoup from bs4 import BeautifulSoup

View File

@ -26,7 +26,6 @@ from ..Template.Class.SearchType import MediaItem
from .costant import ROOT_PATH, DOMAIN_NOW, SITE_NAME, MOVIE_FOLDER from .costant import ROOT_PATH, DOMAIN_NOW, SITE_NAME, MOVIE_FOLDER
def download_title(select_title: MediaItem): def download_title(select_title: MediaItem):
""" """
Downloads a media item and saves it as an MP4 file. Downloads a media item and saves it as an MP4 file.
@ -62,4 +61,4 @@ def download_title(select_title: MediaItem):
manager = TOR_downloader() manager = TOR_downloader()
manager.add_magnet_link(final_url) manager.add_magnet_link(final_url)
manager.start_download() manager.start_download()
manager.move_downloaded_files(mp4_path) manager.move_downloaded_files(mp4_path)

View File

@ -1,6 +1,5 @@
# 19.06.24 # 19.06.24
import sys
import logging import logging
from typing import List from typing import List

View File

@ -1,7 +1,6 @@
# 19.06.24 # 19.06.24
import sys import sys
import logging
# Internal utilities # Internal utilities
@ -85,4 +84,4 @@ def get_select_title(table_show_manager, media_search_manager):
else: else:
console.print("\n[red]Wrong index") console.print("\n[red]Wrong index")
sys.exit(0) sys.exit(0)

View File

@ -1,7 +1,6 @@
# 26.05.24 # 26.05.24
import re import re
import sys
import logging import logging
@ -175,4 +174,3 @@ class VideoSource:
except Exception as e: except Exception as e:
logging.error(f"An error occurred: {e}") logging.error(f"An error occurred: {e}")
return None return None

View File

@ -20,7 +20,6 @@ from ..Template.Class.SearchType import MediaItem
# Config # Config
from .costant import ROOT_PATH, SITE_NAME, MOVIE_FOLDER from .costant import ROOT_PATH, SITE_NAME, MOVIE_FOLDER
def download_film(select_title: MediaItem): def download_film(select_title: MediaItem):
""" """
@ -57,4 +56,4 @@ def download_film(select_title: MediaItem):
HLS_Downloader( HLS_Downloader(
m3u8_playlist = master_playlist, m3u8_playlist = master_playlist,
output_filename = os.path.join(mp4_path, mp4_name) output_filename = os.path.join(mp4_path, mp4_name)
).start() ).start()

View File

@ -1,9 +1,5 @@
# 26.05.24 # 26.05.24
import sys
import logging
# External libraries # External libraries
import httpx import httpx
from bs4 import BeautifulSoup from bs4 import BeautifulSoup
@ -23,7 +19,6 @@ media_search_manager = MediaManager()
table_show_manager = TVShowManager() table_show_manager = TVShowManager()
def title_search(title_search: str) -> int: def title_search(title_search: str) -> int:
""" """
Search for titles based on a search query. Search for titles based on a search query.
@ -68,4 +63,4 @@ def run_get_select_title():
""" """
Display a selection of titles and prompt the user to choose one. Display a selection of titles and prompt the user to choose one.
""" """
return get_select_title(table_show_manager, media_search_manager) return get_select_title(table_show_manager, media_search_manager)

View File

@ -1,6 +1,5 @@
# 01.03.24 # 01.03.24
import sys
import logging import logging
from urllib.parse import urljoin, urlparse, parse_qs, urlencode, urlunparse from urllib.parse import urljoin, urlparse, parse_qs, urlencode, urlunparse

View File

@ -13,6 +13,7 @@ from .anime import download_film, download_series
indice = 1 indice = 1
_deprecate = False _deprecate = False
def search(): def search():
# Make request to site to get content that corrsisponde to that string # Make request to site to get content that corrsisponde to that string
@ -34,4 +35,4 @@ def search():
console.print(f"\n[red]Nothing matching was found for[white]: [purple]{string_to_search}") console.print(f"\n[red]Nothing matching was found for[white]: [purple]{string_to_search}")
# Retry # Retry
search() search()

View File

@ -23,7 +23,6 @@ from .costant import ROOT_PATH, SITE_NAME, SERIES_FOLDER, MOVIE_FOLDER
video_source = VideoSource() video_source = VideoSource()
def download_episode(index_select: int): def download_episode(index_select: int):
""" """
Downloads the selected episode. Downloads the selected episode.

View File

@ -1,9 +1,5 @@
# 01.07.24 # 01.07.24
import sys
import logging
# External libraries # External libraries
import httpx import httpx
from bs4 import BeautifulSoup from bs4 import BeautifulSoup
@ -26,7 +22,6 @@ media_search_manager = MediaManager()
table_show_manager = TVShowManager() table_show_manager = TVShowManager()
def title_search(word_to_search: str) -> int: def title_search(word_to_search: str) -> int:
""" """
Search for titles based on a search query. Search for titles based on a search query.
@ -69,4 +64,4 @@ def run_get_select_title():
""" """
Display a selection of titles and prompt the user to choose one. Display a selection of titles and prompt the user to choose one.
""" """
return get_select_title(table_show_manager, media_search_manager) return get_select_title(table_show_manager, media_search_manager)

View File

@ -48,4 +48,4 @@ def download_title(select_title: MediaItem):
manager = TOR_downloader() manager = TOR_downloader()
manager.add_magnet_link(select_title.url) manager.add_magnet_link(select_title.url)
manager.start_download() manager.start_download()
manager.move_downloaded_files(mp4_path) manager.move_downloaded_files(mp4_path)

View File

@ -1,7 +1,6 @@
# 05.07.24 # 05.07.24
import re import re
import sys
import logging import logging

View File

@ -1,9 +1,5 @@
# 03.07.24 # 03.07.24
import sys
import logging
# External libraries # External libraries
import httpx import httpx
from bs4 import BeautifulSoup from bs4 import BeautifulSoup
@ -69,4 +65,4 @@ def run_get_select_title():
""" """
Display a selection of titles and prompt the user to choose one. Display a selection of titles and prompt the user to choose one.
""" """
return get_select_title(table_show_manager, media_search_manager) return get_select_title(table_show_manager, media_search_manager)

View File

@ -24,7 +24,6 @@ from ..costant import COOKIE
class GetSerieInfo: class GetSerieInfo:
def __init__(self, dict_serie: MediaItem) -> None: def __init__(self, dict_serie: MediaItem) -> None:
""" """
Initializes the GetSerieInfo object with default values. Initializes the GetSerieInfo object with default values.
@ -49,7 +48,6 @@ class GetSerieInfo:
List[Dict[str, str]]: List of dictionaries containing episode information. List[Dict[str, str]]: List of dictionaries containing episode information.
""" """
# Make an HTTP request to the series URL
try: try:
response = httpx.get(self.url + "?area=online", cookies=self.cookies, headers=self.headers, timeout=10) response = httpx.get(self.url + "?area=online", cookies=self.cookies, headers=self.headers, timeout=10)
response.raise_for_status() response.raise_for_status()

View File

@ -1,6 +1,5 @@
# 14.06.24 # 14.06.24
import sys
import logging import logging

View File

@ -1,6 +1,5 @@
# 13.06.24 # 13.06.24
import sys
import logging import logging
from typing import List, Dict from typing import List, Dict
@ -20,7 +19,6 @@ from ...Template.Class.SearchType import MediaItem
class GetSerieInfo: class GetSerieInfo:
def __init__(self, dict_serie: MediaItem) -> None: def __init__(self, dict_serie: MediaItem) -> None:
""" """
Initializes the GetSerieInfo object with default values. Initializes the GetSerieInfo object with default values.

View File

@ -1,7 +1,6 @@
# 26.05.24 # 26.05.24
import re import re
import sys
import logging import logging

View File

@ -70,4 +70,4 @@ def run_get_select_title():
""" """
Display a selection of titles and prompt the user to choose one. Display a selection of titles and prompt the user to choose one.
""" """
return get_select_title(table_show_manager, media_search_manager) return get_select_title(table_show_manager, media_search_manager)

View File

@ -13,13 +13,12 @@ from bs4 import BeautifulSoup
# Internal utilities # Internal utilities
from Src.Util.message import start_message from Src.Util.message import start_message
from Src.Util.console import console from Src.Util.console import console
from Src.Util.os import create_folder, can_create_file, remove_special_characters from Src.Util.os import can_create_file, remove_special_characters
from Src.Util.headers import get_headers from Src.Util.headers import get_headers
from Src.Lib.Downloader import HLS_Downloader from Src.Lib.Downloader import HLS_Downloader
# Logic class # Logic class
from ..Template.Class.SearchType import MediaItem
from ..guardaserie.Player.supervideo import VideoSource from ..guardaserie.Player.supervideo import VideoSource
from Src.Lib.TMBD import Json_film from Src.Lib.TMBD import Json_film
@ -47,9 +46,14 @@ def download_film(movie_details: Json_film):
response.raise_for_status() response.raise_for_status()
# Extract supervideo url # Extract supervideo url
soup = BeautifulSoup(response.text, "html.parser") try:
player_links = soup.find("ul", class_ = "_player-mirrors").find_all("li") soup = BeautifulSoup(response.text, "html.parser")
supervideo_url = "https:" + player_links[0].get("data-link") player_links = soup.find("ul", class_ = "_player-mirrors").find_all("li")
supervideo_url = "https:" + player_links[0].get("data-link")
except:
logging.error("Not found in the server.")
sys.exit(0)
# Set domain and media ID for the video source # Set domain and media ID for the video source
video_source = VideoSource() video_source = VideoSource()

View File

@ -223,5 +223,3 @@ class VideoSource:
final_url = urlunparse(new_url) # Construct the final URL from the modified parts final_url = urlunparse(new_url) # Construct the final URL from the modified parts
return final_url return final_url

View File

@ -1,60 +0,0 @@
# 03.03.24
from typing import Dict, Any, List
class Episode:
def __init__(self, data: Dict[str, Any]):
self.title: int = data.get('title', '')
self.url: str = data.get('link', '')
def __str__(self):
return f"Episode(title='{self.title}')"
class EpisodeManager:
def __init__(self):
self.episodes: List[Episode] = []
def add_episode(self, episode_data: Dict[str, Any]):
"""
Add a new episode to the manager.
Parameters:
- episode_data (Dict[str, Any]): A dictionary containing data for the new episode.
"""
episode = Episode(episode_data)
self.episodes.append(episode)
def get(self, index: int) -> Episode:
"""
Get an episode by its index.
Parameters:
- index (int): Index of the episode to retrieve.
Returns:
Episode: The episode object.
"""
return self.episodes[index]
def get_length(self) -> int:
"""
Get the number of episodes in the manager.
Returns:
int: Number of episodes.
"""
return len(self.episodes)
def clear(self) -> None:
"""
This method clears the episodes list.
Parameters:
- self: The object instance.
"""
self.episodes.clear()
def __str__(self):
return f"EpisodeManager(num_episodes={len(self.episodes)})"

View File

@ -1,56 +0,0 @@
# 03.03.24
from typing import List, Dict, Union
class Season:
def __init__(self, season_data: Dict[str, Union[int, str, None]]):
self.name: str = season_data.get('name')
def __str__(self):
return f"Season(name='{self.name}')"
class SeasonManager:
def __init__(self):
self.seasons: List[Season] = []
def add_season(self, season_data: Dict[str, Union[int, str, None]]):
"""
Add a new season to the manager.
Parameters:
- season_data (Dict[str, Union[int, str, None]]): A dictionary containing data for the new season.
"""
season = Season(season_data)
self.seasons.append(season)
def get(self, index: int) -> Season:
"""
Get a season item from the list by index.
Parameters:
- index (int): The index of the seasons item to retrieve.
Returns:
- Season: The media item at the specified index.
"""
return self.media_list[index]
def get_length(self) -> int:
"""
Get the number of seasons in the manager.
Returns:
- int: Number of seasons.
"""
return len(self.seasons)
def clear(self) -> None:
"""
This method clears the seasons list.
"""
self.seasons.clear()
def __str__(self):
return f"SeasonManager(num_seasons={len(self.seasons)})"

View File

@ -1,263 +0,0 @@
# 30.06.24
import time
import logging
# External library
from bs4 import BeautifulSoup
from seleniumbase import Driver
# Internal utilities
from Src.Util._jsonConfig import config_manager
# Config
USE_HEADLESS = config_manager.get_bool("BROWSER", "headless")
class DownloadAutomation:
def __init__(self, download_link):
self.download_link = download_link
self.driver = Driver(uc=True, uc_cdp_events=True, headless=USE_HEADLESS)
self.mp4_link = None
def run(self):
"""
Executes the entire automation process.
"""
try:
self.driver.get(self.download_link)
self._inject_css()
self._observe_title_change()
self._bypass_page_1()
self._bypass_page_2_verify_button()
self._bypass_page_2_two_steps_btn()
self._wait_for_document_complete()
self._wait_for_bypass_completion()
self._extract_download_link()
except Exception as e:
logging.error(f"Error occurred during automation: {str(e)}")
finally:
self.quit()
def _inject_css(self):
"""
Injects CSS to make all elements on the page invisible.
"""
try:
css_script = """
const voidCSS = `* {opacity: 0;z-index: -999999;}`;
function addStyle(css) {
let head = document.querySelector('head'),
style = document.createElement('style');
style.innerHTML = css;
head.appendChild(style);
}
"""
self.driver.execute_script(css_script)
logging.info("CSS injected.")
time.sleep(0.4)
except Exception as e:
logging.error(f"Error injecting CSS: {str(e)}")
def _observe_title_change(self):
"""
Observes changes in the document title and applies CSS injection.
"""
try:
observer_script = """
let headObserver = new MutationObserver(function() {
if (document.title) {
addStyle(voidCSS.replace(';', ' !important;'));
headObserver.disconnect();
}
});
headObserver.observe(document.documentElement, {childList: true, subtree: true});
"""
self.driver.execute_script(observer_script)
logging.info("Title observer set.")
time.sleep(0.4)
except Exception as e:
logging.error(f"Error setting title observer: {str(e)}")
def _bypass_page_1(self):
"""
Executes action to bypass Page 1.
"""
try:
action1_script = """
function action1() {
try {
document.querySelector('#landing').submit();
document.title = "Bypass Action (1/3)";
} catch {}
}
action1();
"""
self.driver.execute_script(action1_script)
logging.info("Page 1 bypassed.")
time.sleep(0.4)
except Exception as e:
logging.error(f"Error bypassing Page 1: {str(e)}")
def _bypass_page_2_verify_button(self):
"""
Executes action to bypass Page 2 by clicking on verify_button.
"""
try:
action2_script = """
function action2() {
try {
document.querySelector('#verify_button').click();
document.title = "Bypass Action (2/3)";
} catch {}
}
action2();
"""
self.driver.execute_script(action2_script)
logging.info("Page 2 bypassed.")
time.sleep(0.4)
except Exception as e:
logging.error(f"Error bypassing Page 2: {str(e)}")
def _bypass_page_2_two_steps_btn(self):
"""
Executes action to bypass Page 2 by waiting for and clicking two_steps_btn.
"""
try:
action3_script = """
function action3() {
try {
let observer = new MutationObserver(function() {
if (document.querySelector('#two_steps_btn').href !== "") {
observer.disconnect();
document.title = "Bypass Action (3/3)";
window.location = document.querySelector('#two_steps_btn').href;
}
});
observer.observe(document.querySelector('#two_steps_btn'), {attributes: true});
} catch {}
}
action3();
"""
self.driver.execute_script(action3_script)
logging.info("Page 2 bypassed with observation and redirect.")
time.sleep(0.4)
except Exception as e:
logging.error(f"Error bypassing Page 2 with observation: {str(e)}")
def _wait_for_document_complete(self):
"""
Waits for the document to be completely loaded to execute actions.
"""
try:
onreadystatechange_script = """
document.onreadystatechange = function () {
if (document.readyState === 'complete') {
action1();
action2();
action3();
}
}
"""
self.driver.execute_script(onreadystatechange_script)
logging.info("onreadystatechange set.")
time.sleep(0.4)
except Exception as e:
logging.error(f"Error setting onreadystatechange: {str(e)}")
def _wait_for_bypass_completion(self):
"""
Waits for the bypass process to complete.
"""
try:
while True:
if ".mkv" in self.driver.title or ".mp4" in self.driver.title:
logging.info("Bypass completed.")
break
time.sleep(0.5)
except Exception as e:
logging.error(f"Error waiting for bypass completion: {str(e)}")
def _extract_download_link(self):
"""
Extracts the final download link after bypassing and loads the download page.
"""
try:
final_html = self.driver.page_source
soup = BeautifulSoup(final_html, 'html.parser')
video_link = soup.find("a", class_="btn").get('href')
logging.info("Loading download page.")
self.driver.get(video_link)
logging.info(f"Download page link: {video_link}")
except Exception as e:
logging.error(f"Error extracting download link: {str(e)}")
def capture_url(self, req):
"""
Function to capture url in background
"""
try:
url = req['params']['documentURL']
# Filter for mp4 video download
if "googleusercontent" in str(url):
self.mp4_link = url
except:
pass
def quit(self):
"""
Quits the WebDriver instance.
"""
try:
logging.info("Removing ad headers.")
css_script = """
const voidCSS = ``;
function addStyle(css) {
let head = document.querySelector('head'),
style = document.createElement('style');
style.innerHTML = css;
head.appendChild(style);
}
"""
self.driver.execute_script(css_script)
self.driver.add_cdp_listener("*", lambda data: self.capture_url(data))
time.sleep(0.3)
logging.info("Clicking button.")
self.driver.execute_script("document.getElementById('ins').click();")
while True:
time.sleep(0.3)
if self.mp4_link is not None:
break
logging.info(f"MP4 Link: {self.mp4_link}")
logging.info("Quitting...")
self.driver.quit()
except Exception as e:
logging.error(f"Error during quitting: {str(e)}")

View File

@ -1,230 +0,0 @@
# 29.06.24
import re
import httpx
import logging
from bs4 import BeautifulSoup
# Logic class
from ..Class.EpisodeType import EpisodeManager
from ..Class.SeriesType import SeasonManager
class EpisodeScraper:
def __init__(self, url):
"""
The constructor for the EpisodeScraper class.
Parameters:
- url (str): The URL of the webpage to scrape.
"""
self.url = url
self.soup = self._get_soup()
self.info_site = self._extract_info()
self.stagioni = self._organize_by_season()
def _get_soup(self):
"""
Retrieves and parses the webpage content using BeautifulSoup.
Returns:
- BeautifulSoup: The parsed HTML content of the webpage.
"""
try:
response = httpx.get(self.url)
response.raise_for_status()
return BeautifulSoup(response.text, 'html.parser')
except Exception as e:
print(f"Error fetching the URL: {e}")
raise
def _extract_info(self):
"""
Extracts the episode information from the parsed HTML.
Returns:
- list: A list of dictionaries containing episode information.
"""
rows = self.soup.find_all("p", style="text-align: center;")
info_site = []
# Loop through each <p> tag and extract episode information
for i, row in enumerate(rows, start=1):
episodes = []
# Find all <a> tags with the specified class and extract title and link
for episode in row.find_all("a", class_="maxbutton-2"):
episodes.append({
'title': episode.text,
'link': episode.get('href')
})
# If there are episodes, add them to the info_site list
if len(episodes) > 0:
if i == 2:
title_name = rows[i-1].get_text().split("\n")[3]
if "Epis" not in str(title_name):
info_site.append({
'name': title_name,
'episode': episodes,
})
else:
title_name = rows[i-2].get_text()
if "Epis" not in str(title_name):
info_site.append({
'name': title_name,
'episode': episodes,
})
# For only episode
if len(info_site) == 0:
for i, row in enumerate(rows, start=1):
for episode in row.find_all("a", class_="maxbutton-1"):
info_site.append({
'name': rows[i-1].get_text().split("\n")[1],
'url': episode.get("href"),
})
# Get only fist quality
break
break
return info_site
def _organize_by_season(self):
"""
Organizes the extracted information into seasons.
Returns:
- dict: A dictionary organizing episodes by season.
"""
stagioni = {}
# Loop through each episode dictionary and organize by season
for dizionario in self.info_site:
nome = dizionario["name"]
# Use regex to search for season numbers (S01, S02, etc.)
match = re.search(r'S\d+', nome)
if match:
stagione = match.group(0)
if stagione not in stagioni:
stagioni[stagione] = []
stagioni[stagione].append(dizionario)
self.is_serie = len(list(stagioni.keys())) > 0
return stagioni
def get_available_seasons(self):
"""
Returns a list of available seasons.
Returns:
- list: A list of available seasons.
"""
return list(self.stagioni.keys())
def get_episodes_by_season(self, season):
"""
Returns a list of episodes for a given season.
Parameters:
- season (str): The season identifier (e.g., 'S01').
Returns:
- list: A list of episodes for the specified season.
"""
episodes = self.stagioni[season][0]['episode']
def find_group_size(episodes):
seen_titles = {}
for index, episode in enumerate(episodes):
title = episode["title"]
if title in seen_titles:
return index - seen_titles[title]
seen_titles[title] = index
return len(episodes)
# Find group size
group_size = find_group_size(episodes)
grouped_episodes = []
start_index = 0
while start_index < len(episodes):
group = episodes[start_index:start_index + group_size]
grouped_episodes.append(group)
start_index += group_size
return grouped_episodes[0]
def get_film(self):
"""
Retrieves the first element from the info_site list.
"""
return self.info_site[0]
class ApiManager:
def __init__(self, url):
"""
The constructor for the EpisodeScraper class.
Parameters:
- url (str): The URL of the webpage to scrape.
"""
self.url = url
self.episode_scraper = EpisodeScraper(url)
self.is_serie = self.episode_scraper.is_serie
self.obj_season_manager: SeasonManager = SeasonManager()
self.obj_episode_manager: EpisodeManager = EpisodeManager()
def collect_season(self):
"""
Collect available seasons from the webpage and add them to the season manager.
"""
available_seasons = self.episode_scraper.get_available_seasons()
for dict_season in available_seasons:
self.obj_season_manager.add_season({'name': dict_season})
def collect_episode(self, season_name):
"""
Collect episodes for a given season and add them to the episode manager.
Parameters:
- season_name (str): The name of the season for which to collect episodes.
"""
dict_episodes = self.episode_scraper.get_episodes_by_season(season_name)
for dict_episode in dict_episodes:
self.obj_episode_manager.add_episode(dict_episode)
def get_film_playlist(self):
"""
Get the film playlist from the episode scraper.
Returns:
- list: A list of films in the playlist.
"""
return self.episode_scraper.get_film()

View File

@ -1,39 +0,0 @@
# 09.06.24
# Internal utilities
from Src.Util.console import console, msg
# Logic class
from .site import title_search, run_get_select_title
from .serie import download_serie
# Variable
indice = 6
_deprecate = True
def search():
"""
Main function of the application for film and series.
"""
# Make request to site to get content that corrsisponde to that string
string_to_search = msg.ask("\n[purple]Insert word to search in all site").strip()
len_database = title_search(string_to_search)
if len_database > 0:
# Select title from list
select_title = run_get_select_title()
# Download only TV
download_serie(select_title)
else:
console.print(f"\n[red]Nothing matching was found for[white]: [purple]{string_to_search}")
# Retry
search()

View File

@ -1,15 +0,0 @@
# 09.06.24
import os
# Internal utilities
from Src.Util._jsonConfig import config_manager
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"

View File

@ -1,58 +0,0 @@
# 23.08.24
# 3.12.23
import os
import sys
import logging
from urllib.parse import urlparse
# Internal utilities
from Src.Util.console import console
from Src.Util.message import start_message
from Src.Util.os import create_folder, remove_special_characters
from Src.Lib.Downloader import MP4_downloader
# Logic class
from .Core.Player.driveleech import DownloadAutomation
# Variable
from .costant import ROOT_PATH, SITE_NAME, MOVIE_FOLDER
def download_film(name: str, url: str):
"""
Downloads a film using the provided url.
Parameters:
- name (str): Name of the film
- url (str): MP4 url of the film
"""
# Start message and display film information
start_message()
console.print(f"[yellow]Download: [red]{name} \n")
# Construct the MP4 file name and path
mp4_path = os.path.join(ROOT_PATH, SITE_NAME, MOVIE_FOLDER, remove_special_characters(name))
# Ensure the folder path exists
create_folder(mp4_path)
# Parse start page url
downloder_vario = DownloadAutomation(url)
downloder_vario.run()
downloder_vario.quit()
# Parse mp4 link
mp4_final_url = downloder_vario.mp4_link
parsed_url = urlparse(mp4_final_url)
MP4_downloader(
url = mp4_final_url,
path = os.path.join(mp4_path, "film_0.mp4"),
referer = f"{parsed_url.scheme}://{parsed_url.netloc}/",
)

View File

@ -1,204 +0,0 @@
# 29.06.24
import os
import sys
import logging
from urllib.parse import urlparse
# Internal utilities
from Src.Util.console import console, msg
from Src.Util.message import start_message
from Src.Util.os import create_folder, can_create_file
from Src.Util.table import TVShowManager
from Src.Lib.Downloader import MP4_downloader
from ..Template import manage_selection, map_episode_title, validate_selection, validate_episode_selection
# Logic class
from .Core.Player.episode_scraper import ApiManager
from .Core.Player.driveleech import DownloadAutomation
from ..Template.Class.SearchType import MediaItem
from .film import download_film
# Variable
from .costant import ROOT_PATH, SITE_NAME, SERIES_FOLDER
table_show_manager = TVShowManager()
def download_video(api_manager: ApiManager, index_season_selected: int, index_episode_selected: int) -> None:
"""
Download a single episode video.
Parameters:
- tv_name (str): Name of the TV series.
- index_season_selected (int): Index of the selected season.
- index_episode_selected (int): Index of the selected episode.
"""
start_message()
# Get info about episode
obj_episode = api_manager.obj_episode_manager.episodes[index_episode_selected - 1]
tv_name = api_manager.obj_season_manager.seasons[index_season_selected - 1].name
console.print(f"[yellow]Download: [red]{index_season_selected}:{index_episode_selected} {obj_episode.title}")
print()
# Define filename and path for the downloaded video
mp4_name = f"{map_episode_title(tv_name, index_season_selected, index_episode_selected, obj_episode.title)}.mp4"
mp4_path = os.path.join(ROOT_PATH, SITE_NAME, SERIES_FOLDER, tv_name, f"S{index_season_selected}")
# 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)
# Parse start page url
start_message()
downloder_vario = DownloadAutomation(obj_episode.url)
downloder_vario.run()
downloder_vario.quit()
# Parse mp4 link
mp4_final_url = downloder_vario.mp4_link
parsed_url = urlparse(mp4_final_url)
MP4_downloader(
url = mp4_final_url,
path = os.path.join(mp4_path, mp4_name),
referer = f"{parsed_url.scheme}://{parsed_url.netloc}/",
)
def download_episode(api_manager: ApiManager, index_season_selected: int, download_all: bool = False) -> None:
"""
Download all episodes of a season.
Parameters:
- tv_name (str): Name of the TV series.
- index_season_selected (int): Index of the selected season.
- download_all (bool): Download all seasons episodes
"""
# Clean memory of all episodes and get the number of the season (some dont follow rule of [1,2,3,4,5] but [1,2,3,145,5,6,7]).
api_manager.obj_episode_manager.clear()
season_name = api_manager.obj_season_manager.seasons[index_season_selected-1].name
# Collect all best episode
start_message()
api_manager.collect_episode(season_name)
episodes_count = api_manager.obj_episode_manager.get_length()
if download_all:
# Download all episodes without asking
for i_episode in range(1, episodes_count + 1):
download_video(api_manager, index_season_selected, i_episode)
console.print(f"\n[red]End downloaded [yellow]season: [red]{index_season_selected}.")
else:
# Display episodes list and manage user selection
last_command = display_episodes_list()
list_episode_select = manage_selection(last_command, episodes_count)
try:
list_episode_select = validate_episode_selection(list_episode_select, episodes_count)
except ValueError as e:
console.print(f"[red]{str(e)}")
return
# Download selected episodes
for i_episode in list_episode_select:
download_video(api_manager, index_season_selected, i_episode)
def download_serie(media: MediaItem):
"""
Downloads a media title using its API manager and WebAutomation driver.
Parameters:
media (MediaItem): The media item to be downloaded.
"""
start_message()
# Initialize the API manager with the media and driver
api_manager = ApiManager(media.url)
# Collect information about seasons
api_manager.collect_season()
seasons_count = api_manager.obj_season_manager.get_length()
if seasons_count > 0:
# Prompt user for season selection and download episodes
console.print(f"\n[green]Seasons found: [red]{seasons_count}")
index_season_selected = msg.ask(
"\n[cyan]Insert season number [yellow](e.g., 1), [red]* [cyan]to download all seasons, "
"[yellow](e.g., 1-2) [cyan]for a range of seasons, or [yellow](e.g., 3-*) [cyan]to download from a specific season to the end"
)
# Manage and validate the selection
list_season_select = manage_selection(index_season_selected, seasons_count)
try:
list_season_select = validate_selection(list_season_select, seasons_count)
except ValueError as e:
console.print(f"[red]{str(e)}")
return
# Loop through the selected seasons and download episodes
for i_season in list_season_select:
if len(list_season_select) > 1 or index_season_selected == "*":
# Download all episodes if multiple seasons are selected or if '*' is used
download_episode(api_manager, i_season, download_all=True)
else:
# Otherwise, let the user select specific episodes for the single season
download_episode(api_manager, i_season, download_all=False)
else:
# If not seasons find is a film
obj_film = api_manager.episode_scraper.info_site[0]
download_film(obj_film.get('name'), obj_film.get('url'))
def display_episodes_list(api_manager: ApiManager) -> str:
"""
Display episodes list and handle user input.
Returns:
last_command (str): Last command entered by the user.
"""
# Set up table for displaying episodes
table_show_manager.set_slice_end(10)
# Add columns to the table
column_info = {
"Index": {'color': 'red'},
"Name": {'color': 'magenta'},
}
table_show_manager.add_column(column_info)
# Populate the table with episodes information
for i, media in enumerate(api_manager.obj_episode_manager.episodes):
table_show_manager.add_tv_show({
'Index': str(i),
'Name': media.title
})
# Run the table and handle user input
last_command = table_show_manager.run()
if last_command == "q":
console.print("\n[red]Quit [white]...")
sys.exit(0)
return last_command

View File

@ -1,70 +0,0 @@
# 09.06.24
import logging
# External libraries
import httpx
from bs4 import BeautifulSoup
from unidecode import unidecode
# Internal utilities
from Src.Util.table import TVShowManager
from ..Template import search_domain, get_select_title
# Logic class
from ..Template.Class.SearchType import MediaManager
# Variable
from .costant import SITE_NAME
media_search_manager = MediaManager()
table_show_manager = TVShowManager()
def title_search(word_to_search: str) -> int:
"""
Search for titles based on a search query.
Parameters:
- title_search (str): The title to search for.
Returns:
- int: The number of titles found.
"""
# Create a web automation driver instance
domain_to_use, _ = search_domain(SITE_NAME, f"https://{SITE_NAME}")
# Construct the full site URL and load the search page
response = httpx.get(f"https://{SITE_NAME}.{domain_to_use}/search/{unidecode(word_to_search)}")
response.raise_for_status()
# Retrieve and parse the HTML content of the page
soup = BeautifulSoup(response.text, "html.parser")
table_content = soup.find_all("article")
# Iterate through the search results to find relevant titles
for title in table_content:
# Construct a media object with the title's details
obj = {
'url': title.find("a").get("href"),
'name': title.find("a").get("title"),
}
# Add the media object to the media search manager
media_search_manager.add_media(obj)
# Return the number of titles found
return media_search_manager.get_length()
def run_get_select_title():
"""
Display a selection of titles and prompt the user to choose one.
"""
return get_select_title(table_show_manager, media_search_manager)

View File

@ -1,84 +0,0 @@
# 29.06.24
import sys
import logging
import json
import urllib.parse
# Logic class
from ...Template.Class.SearchType import MediaItem
from Src.Lib.Driver import WebAutomation
# Variable
from ..costant import SITE_NAME, DOMAIN_NOW
full_site_name=f"{SITE_NAME}.{DOMAIN_NOW}"
class ApiManager:
def __init__(self, media: MediaItem, main_driver: WebAutomation) -> None:
"""
Initializes the ApiManager with a media item and a web automation driver.
Parameters:
- media (MediaItem): The media item to be processed.
- main_driver (WebAutomation): The driver to perform web automation tasks.
"""
self.media = media
self.id = self.media.url.split("/")[-1]
self.main_driver = main_driver
def get_playlist(self) -> str:
"""
Retrieves the URL of the best quality stream available for the media item.
Returns:
- str: The URL of the best quality stream.
"""
# Prepare the JSON payload
# !! NOTE: MISSING ALL OTHER PLAYER
json_payload = {
"0": {
"json": {
"type": self.media.type,
"id": self.id,
"provider": "showbox-internal"
}
}
}
# Convert the payload to a JSON string and properly escape it
json_string = json.dumps (json_payload)
encoded_json_string = urllib.parse.quote(json_string)
# Format the URL with the encoded JSON string
api_url = f"https://{full_site_name}/api/trpc/provider.run?batch=1&input={encoded_json_string}"
# Load the API URL in the web driver
self.main_driver.get_page(str(api_url))
# Retrieve and parse the page content
soup = self.main_driver.retrieve_soup()
content = soup.find("pre").text
if "error" in str(content):
logging.error("Failed to make request. Work in progress to add all other provider ...")
# TO DO !!! ADD ALL OTHER PROVIDER
sys.exit(0)
data = json.loads(content)[0]['result']['data']['json']['stream'][0]['qualities']
# Return the URL based on the available quality
if len(data.keys()) == 1:
return data.get('360')['url']
if len(data.keys()) == 2:
return data.get("720")['url']
if len(data.keys()) == 3:
return data.get('1080')['url']
if len(data.keys()) == 4:
return data.get('4k')['url']

View File

@ -1,47 +0,0 @@
# 09.06.24
import sys
import logging
# Internal utilities
from Src.Util.console import console, msg
# Logic class
from .site import title_search, run_get_select_title
from .film import download_film
# Variable
indice = 5
_deprecate = True
# !! NOTE: 23.08.24 Seleniumbase cant bypass site
def search():
"""
Main function of the application for film and series.
"""
# Make request to site to get content that corrsisponde to that string
string_to_search = msg.ask("\n[purple]Insert word to search in all site").strip()
len_database, main_driver = title_search(string_to_search)
if len_database > 0:
# Select title from list
select_title = run_get_select_title()
if select_title.type == "movie":
download_film(select_title, main_driver)
else:
logging.error(f"Not supported: {select_title.type}")
sys.exit(0)
else:
console.print(f"\n[red]Nothing matching was found for[white]: [purple]{string_to_search}")
# Retry
search()

View File

@ -1,20 +0,0 @@
# 09.06.24
import os
# Internal utilities
from Src.Util._jsonConfig import config_manager
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"
# Fix site name for .
# URL => https://watch.lonelil.ru
SITE_NAME = SITE_NAME.replace("_", ".")

View File

@ -1,65 +0,0 @@
# 29.06.24
import os
import sys
import logging
from urllib.parse import urlparse
# Internal utilities
from Src.Util.message import start_message
from Src.Util.os import create_folder, can_create_file, remove_special_characters
from Src.Lib.Downloader import MP4_downloader
# Logic class
from .Player.lonelil import ApiManager
from ..Template.Class.SearchType import MediaItem
from Src.Lib.Driver import WebAutomation
# Variable
from .costant import ROOT_PATH, SITE_NAME, SERIES_FOLDER
def download_film(media: MediaItem, main_driver: WebAutomation):
"""
Downloads a media title using its API manager and WebAutomation driver.
Parameters:
- media (MediaItem): The media item to be downloaded.
- main_driver (WebAutomation): The web automation driver instance.
"""
start_message()
# Initialize the API manager with the media and driver
api_manager = ApiManager(media, main_driver)
# Get the URL of the media playlist
url_playlist = api_manager.get_playlist()
# Construct the MP4 file name and path
mp4_name = remove_special_characters(media.name) + ".mp4"
mp4_path = os.path.join(ROOT_PATH, SITE_NAME, SERIES_FOLDER, remove_special_characters(media.name))
# Ensure the folder path exists
create_folder(mp4_path)
# Check if the MP4 file can be created
if not can_create_file(mp4_name):
logging.error("Invalid mp4 name.")
sys.exit(0)
# Parse the URL of the playlist
parsed_url = urlparse(url_playlist)
# Quit the main driver instance
main_driver.quit()
# Initiate the MP4 downloader with necessary parameters
MP4_downloader(
url=url_playlist,
path=os.path.join(mp4_path, mp4_name),
referer=f"{parsed_url.scheme}://{parsed_url.netloc}/",
)

View File

@ -1,68 +0,0 @@
# 09.06.24
import logging
# External libraries
from unidecode import unidecode
# Internal utilities
from Src.Util.table import TVShowManager
from Src.Lib.Driver import WebAutomation
from ..Template import search_domain, get_select_title
# Logic class
from ..Template.Class.SearchType import MediaManager
# Variable
from .costant import SITE_NAME, DOMAIN_NOW
media_search_manager = MediaManager()
table_show_manager = TVShowManager()
def title_search(word_to_search: str) -> int:
"""
Search for titles based on a search query.
Parameters:
- title_search (str): The title to search for.
Returns:
int: The number of titles found.
"""
# Create a web automation driver instance
main_driver = WebAutomation()
# Construct the full site URL and load the search page
full_site_name = f"{SITE_NAME}.{DOMAIN_NOW}"
main_driver.get_page(f"https://{full_site_name}/search?q={unidecode(word_to_search)}")
# Retrieve and parse the HTML content of the page
soup = main_driver.retrieve_soup()
content_table = soup.find_all("a")
# Iterate through the search results to find relevant titles
for title in content_table:
if any(keyword in str(title).lower() for keyword in ["show/", "movie/", "anime/"]):
obj = {
'url': f"https://{full_site_name}" + title.get("href"),
'name': title.find("img").get("alt"),
'type': title.find_all("p")[-1].get_text().split("·")[0].strip().lower()
}
media_search_manager.add_media(obj)
# Return the number of titles found
return media_search_manager.get_length(), main_driver
def run_get_select_title():
"""
Display a selection of titles and prompt the user to choose one.
"""
return get_select_title(table_show_manager, media_search_manager)

View File

@ -1,3 +0,0 @@
# 20.02.24
from .downloader import HLS_Downloader

File diff suppressed because it is too large Load Diff

View File

@ -2,7 +2,6 @@
import os import os
import sys import sys
import time
import logging import logging
from concurrent.futures import ThreadPoolExecutor from concurrent.futures import ThreadPoolExecutor

View File

@ -14,7 +14,6 @@ from concurrent.futures import ThreadPoolExecutor
# External libraries # External libraries
import httpx import httpx
from httpx import HTTPTransport
from tqdm import tqdm from tqdm import tqdm
@ -82,17 +81,6 @@ class M3U8_Segments:
# Server ip # Server ip
self.fake_proxy = False self.fake_proxy = False
def add_server_ip(self, list_ip: list):
"""
Add server IP addresses
Args:
list_ip (list): A list of IP addresses to be added.
"""
if list_ip is not None:
self.fake_proxy = True
self.fake_proxy_ip = list_ip
def __get_key__(self, m3u8_parser: M3U8_Parser) -> bytes: def __get_key__(self, m3u8_parser: M3U8_Parser) -> bytes:
""" """
Retrieves the encryption key from the M3U8 playlist. Retrieves the encryption key from the M3U8 playlist.
@ -289,7 +277,7 @@ class M3U8_Segments:
progress_bar.update(1) progress_bar.update(1)
except Exception as e: except Exception as e:
console.print(f"Failed download: '{ts_url}' with error: {e}") console.print(f"\nFailed to download: '{ts_url}' with error: {e}")
def write_segments_to_file(self): def write_segments_to_file(self):
""" """

View File

@ -1,3 +0,0 @@
# 23.06.24
from .downloader import MP4_downloader

View File

@ -1,3 +0,0 @@
# 23.06.24
from .downloader import TOR_downloader

View File

@ -207,4 +207,4 @@ class TOR_downloader:
break break
self.qb.delete_permanently(self.qb.torrents()[-1]['hash']) self.qb.delete_permanently(self.qb.torrents()[-1]['hash'])
return True return True

View File

@ -1,5 +1,5 @@
# 23.06.24 # 23.06.24
from .HLS import HLS_Downloader from .HLS.downloader import HLS_Downloader
from .MP4 import MP4_downloader from .MP4.downloader import MP4_downloader
from .TOR import TOR_downloader from .TOR.downloader import TOR_downloader

View File

@ -1,3 +0,0 @@
# 29.06.24
from .driver_1 import WebAutomation

View File

@ -1,7 +1,6 @@
# 17.09.24 # 17.09.24
import json from typing import Dict
from typing import List, Dict, Optional
class Json_film: class Json_film:

View File

@ -1,3 +0,0 @@
# 01.03.24
from .update import update

View File

@ -19,6 +19,7 @@ def get_call_stack():
- script (str): The name of the script file containing the function. - script (str): The name of the script file containing the function.
- line (int): The line number in the script where the function is defined. - line (int): The line number in the script where the function is defined.
""" """
stack = inspect.stack() stack = inspect.stack()
call_stack = [] call_stack = []

View File

@ -17,4 +17,4 @@ class Colors:
LIGHT_MAGENTA = "\033[95m" LIGHT_MAGENTA = "\033[95m"
LIGHT_CYAN = "\033[96m" LIGHT_CYAN = "\033[96m"
WHITE = "\033[97m" WHITE = "\033[97m"
RESET = "\033[0m" RESET = "\033[0m"

View File

@ -3,8 +3,9 @@
from rich.console import Console from rich.console import Console
from rich.prompt import Prompt, Confirm from rich.prompt import Prompt, Confirm
from rich.panel import Panel from rich.panel import Panel
from rich.table import Table
# Variable # Variable
msg = Prompt() msg = Prompt()
console = Console() console = Console()

View File

@ -2,7 +2,6 @@
import re import re
import random import random
import logging
# External library # External library

View File

@ -44,4 +44,4 @@ def start_message():
console.print(f"[magenta]Created by: Lovi\n") console.print(f"[magenta]Created by: Lovi\n")
row = "-" * console.width row = "-" * console.width
console.print(f"[yellow]{row} \n") console.print(f"[yellow]{row} \n")

View File

@ -17,15 +17,16 @@ import contextlib
import urllib.request import urllib.request
import importlib.metadata import importlib.metadata
# External library # External library
import httpx import httpx
import unicodedata import unicodedata
# Internal utilities # Internal utilities
from .console import console from .console import console
# --> OS FILE ASCII # --> OS FILE ASCII
special_chars_to_remove = [ special_chars_to_remove = [
'!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '[', ']', '{', '}', '<', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '[', ']', '{', '}', '<',
@ -34,7 +35,6 @@ special_chars_to_remove = [
] ]
def get_max_length_by_os(system: str) -> int: def get_max_length_by_os(system: str) -> int:
""" """
Determines the maximum length for a base name based on the operating system. Determines the maximum length for a base name based on the operating system.

View File

@ -2,7 +2,6 @@
from rich.console import Console from rich.console import Console
from rich.table import Table from rich.table import Table
from rich.text import Text
from rich.prompt import Prompt from rich.prompt import Prompt
from rich.style import Style from rich.style import Style
from typing import Dict, List, Any from typing import Dict, List, Any

7
Test/manual_config.json Normal file
View File

@ -0,0 +1,7 @@
{
"site": "",
"string_search": "",
"serie": true,
"season_cmd": "",
"episode_cmd": ""
}

View File

@ -8,13 +8,13 @@
"root_path": "Video", "root_path": "Video",
"map_episode_name": "%(tv_name)_S%(season)E%(episode)_%(episode_name)", "map_episode_name": "%(tv_name)_S%(season)E%(episode)_%(episode_name)",
"config_qbit_tor": { "config_qbit_tor": {
"host": "192.168.1.125", "host": "192.168.1.58",
"port": "8080", "port": "8080",
"user": "admin", "user": "admin",
"pass": "adminadmin" "pass": "adminadmin"
}, },
"not_close": false, "not_close": false,
"show_trending": true "show_trending": false
}, },
"REQUESTS": { "REQUESTS": {
"timeout": 10, "timeout": 10,

1
run.py
View File

@ -1,4 +1,3 @@
#!
# 10.12.23 # 10.12.23
import os import os

View File

@ -1,169 +1,134 @@
@echo off @echo off
:: BatchGotAdmin :: Controlla se lo script è in esecuzione come amministratore
::------------------------------------- net session >nul 2>&1
REM --> Check for permissions if %errorlevel% neq 0 (
>nul 2>&1 "%SYSTEMROOT%\system32\cacls.exe" "%SYSTEMROOT%\system32\config\system" echo Eseguendo come amministratore...
:: Riavvia lo script con privilegi di amministratore
REM --> If error flag set, we do not have admin. powershell -Command "Start-Process '%~f0' -Verb RunAs"
if '%errorlevel%' NEQ '0' ( exit /b
echo Requesting administrative privileges...
goto UACPrompt
) else ( goto gotAdmin )
:UACPrompt
echo Set UAC = CreateObject^("Shell.Application"^) > "%temp%\getadmin.vbs"
set params = %*:"="
echo UAC.ShellExecute "cmd.exe", "/c %~s0 %params%", "", "runas", 1 >> "%temp%\getadmin.vbs"
"%temp%\getadmin.vbs"
del "%temp%\getadmin.vbs"
exit /B
:gotAdmin
pushd "%CD%"
CD /D "%~dp0"
::--------------------------------------
REM Check if running in PowerShell
@REM Check and install python
@REM where /q python >nul 2>nul
@REM if %errorlevel% neq 1 (
@REM echo Checking Python...
@REM ) else (
@REM call (exit /b 0)
@REM echo python not found. Checking for Chocolatey...
@REM REM Check if Chocolatey is installed
@REM where /q choco >nul 2>nul
@REM if %errorlevel% neq 1 (
@REM echo Installing python using Chocolatey...
@REM choco install python -y
@REM ) else (
@REM echo Chocolatey is not installed.
@REM echo Please install Chocolatey first from https://chocolatey.org/install
@REM echo After installing Chocolatey, you can run this script again to install ffmpeg.
@REM echo Alternatively, you can install python manually from https://www.python.org/
@REM exit /b 1
@REM )
@REM )
REM Get the Python version
for /f "delims=" %%v in ('python -c "import sys; print('.'.join(map(str, sys.version_info[:3])))"') do set PYTHON_VERSION=%%v
REM Set the required version
set REQUIRED_VERSION=3.8
REM Compare the Python version with the required version
REM Split versions by dot and compare each segment
setlocal enabledelayedexpansion
for /f "tokens=1-3 delims=." %%a in ("%PYTHON_VERSION%") do (
set PYTHON_MAJOR=%%a
set PYTHON_MINOR=%%b
set PYTHON_PATCH=%%c
) )
for /f "tokens=1-3 delims=." %%a in ("%REQUIRED_VERSION%") do ( chcp 65001 > nul
set REQUIRED_MAJOR=%%a SETLOCAL ENABLEDELAYEDEXPANSION
set REQUIRED_MINOR=%%b
set REQUIRED_PATCH=%%c
)
REM Compare major version echo Inizio dello script...
if !PYTHON_MAJOR! LSS !REQUIRED_MAJOR! (
echo ERROR: Python version !PYTHON_VERSION! is < !REQUIRED_VERSION!. Exiting...
exit /b 1
) else if !PYTHON_MAJOR! EQU !REQUIRED_MAJOR! (
REM Compare minor version
if !PYTHON_MINOR! LSS !REQUIRED_MINOR! (
echo ERROR: Python version !PYTHON_VERSION! is < !REQUIRED_VERSION!. Exiting...
exit /b 1
) else if !PYTHON_MINOR! EQU !REQUIRED_MINOR! (
REM Compare patch version
if !PYTHON_PATCH! LSS !REQUIRED_PATCH! (
echo ERROR: Python version !PYTHON_VERSION! is < !REQUIRED_VERSION!. Exiting...
exit /b 1
)
)
)
echo Python version %PYTHON_VERSION% is >= %REQUIRED_VERSION%. Continuing... :: Controlla se Chocolatey è già installato
:check_choco
if exist ".venv\" ( echo Verifica se Chocolatey è installato...
echo .venv exists. Installing requirements.txt. choco --version >nul 2>&1
.venv\Scripts\python -m pip install -r requirements.txt IF %ERRORLEVEL% EQU 0 (
) else ( echo Chocolatey è già installato. Salto l'installazione.
echo Making .venv and installing requirements.txt... goto install_python
python -m venv .venv ) ELSE (
.venv\Scripts\python -m pip install -r requirements.txt echo Installazione di Chocolatey...
) @"%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe" -NoProfile -InputFormat None -ExecutionPolicy Bypass -Command "iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))" || (
echo Errore durante l'installazione di Chocolatey.
where /q ffmpeg >nul 2>nul
if %errorlevel% neq 1 (
echo ffmpeg exists.
) else (
call (exit /b 0)
echo ffmpeg not found. Checking for Chocolatey...
REM Check if Chocolatey is installed
where /q choco >nul 2>nul
if %errorlevel% neq 1 (
echo Installing ffmpeg using Chocolatey...
choco install ffmpeg -y
) else (
echo Chocolatey is not installed.
echo Please install Chocolatey first from https://chocolatey.org/install
echo After installing Chocolatey, you can run this script again to install ffmpeg.
echo Alternatively, you can install ffmpeg manually from https://www.ffmpeg.org/
exit /b 1 exit /b 1
) )
echo Chocolatey installato con successo.
call choco --version
echo.
) )
:: Controlla se Python è già installato
REM Check if OpenSSL exists :install_python
where /q openssl >nul 2>nul echo Verifica se Python è installato...
if %errorlevel% neq 1 ( python -V >nul 2>&1
echo openssl exists. IF %ERRORLEVEL% EQU 0 (
goto end echo Python è già installato. Salto l'installazione.
) goto install_openssl
call (exit /b 0) ) ELSE (
echo Installazione di Python...
REM Check if pycryptodome is installed choco install python --confirm --params="'/NoStore'" --allow-downgrade || (
.venv\Scripts\pip list | findstr /i "pycryptodome" >nul echo Errore durante l'installazione di Python.
if %errorlevel% equ 0 (
echo pycryptodome exists.
goto end
)
call (exit /b 0)
REM Prompt for installation option
echo Please choose an option:
echo 1) openssl
echo 2) pycryptodome
set /p choice="Enter your choice (1): "
REM Handle the choice
if "%choice%"=="2" (
echo Installing pycryptodome.
.venv\Scripts\pip install pycryptodome
) else (
echo Installing openssl.
echo Checking for Chocolatey...
REM Check if Chocolatey is installed
where /q choco >nul 2>nul
if %errorlevel% neq 1 (
echo Installing openssl using Chocolatey...
choco install openssl -y
) else (
echo Chocolatey is not installed.
echo Please install Chocolatey first from https://chocolatey.org/install
echo After installing Chocolatey, you can run this script again to install openssl.
echo Alternatively, you can install OpenSSH manually from https://www.openssl.com/.
exit /b 1 exit /b 1
) )
echo Python installato con successo.
call python -V
echo.
) )
:end :: Chiedi di riavviare il terminale
echo Si prega di riavviare il terminale per continuare...
setlocal enabledelayedexpansion & set "tempfile=%temp%\tempfile.txt" & (echo #^^!.venv\Scripts\python & type run.py | more +1) > "!tempfile!" & move /Y "!tempfile!" run.py >nul 2>nul
echo Everything is installed^^!
echo Run StreamingCommunity with '.\run.py'
pause pause
exit /b
:: Controlla se OpenSSL è già installato
:install_openssl
echo Verifica se OpenSSL è installato...
openssl version -a >nul 2>&1
IF %ERRORLEVEL% EQU 0 (
echo OpenSSL è già installato. Salto l'installazione.
goto install_ffmpeg
) ELSE (
echo Installazione di OpenSSL...
choco install openssl --confirm || (
echo Errore durante l'installazione di OpenSSL.
exit /b 1
)
echo OpenSSL installato con successo.
call openssl version -a
echo.
)
:: Controlla se FFmpeg è già installato
:install_ffmpeg
echo Verifica se FFmpeg è installato...
ffmpeg -version >nul 2>&1
IF %ERRORLEVEL% EQU 0 (
echo FFmpeg è già installato. Salto l'installazione.
goto create_venv
) ELSE (
echo Installazione di FFmpeg...
choco install ffmpeg --confirm || (
echo Errore durante l'installazione di FFmpeg.
exit /b 1
)
echo FFmpeg installato con successo.
call ffmpeg -version
echo.
)
:: Verifica delle installazioni
:verifica_installazioni
echo Verifica delle installazioni...
call choco --version
call python -V
call openssl version -a
call ffmpeg -version
echo Tutti i programmi sono stati installati e verificati con successo.
:: Crea un ambiente virtuale .venv
:create_venv
echo Verifica se l'ambiente virtuale .venv esiste già...
if exist .venv (
echo L'ambiente virtuale .venv esiste già. Salto la creazione.
) ELSE (
echo Creazione dell'ambiente virtuale .venv...
python -m venv .venv || (
echo Errore durante la creazione dell'ambiente virtuale.
exit /b 1
)
echo Ambiente virtuale creato con successo.
)
:: Attiva l'ambiente virtuale e installa i requisiti
echo Installazione dei requisiti...
call .venv\Scripts\activate.bat
pip install -r requirements.txt || (
echo Errore durante l'installazione dei requisiti.
exit /b 1
)
:: Esegui run.py
echo Esecuzione di run.py...
call .venv\Scripts\python .\run.py || (
echo Errore durante l'esecuzione di run.py.
exit /b 1
)
echo Fine dello script.
ENDLOCAL