mirror of
https://github.com/Arrowar/StreamingCommunity.git
synced 2025-06-06 11:35:29 +00:00
Ea porsea gha fato i porsei
This commit is contained in:
parent
284d13bc22
commit
837bcf3110
10
README.md
10
README.md
@ -1,4 +1,4 @@
|
|||||||
# StreamingCommunity Downloader 🎬
|
# StreamingCommunity Downloader
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
@ -26,6 +26,9 @@ Chat, contribute, and have fun in our **Git_StreamingCommunity** Discord [Server
|
|||||||
- [Docker](#docker)
|
- [Docker](#docker)
|
||||||
- [Tutorial](#tutorials)
|
- [Tutorial](#tutorials)
|
||||||
- [To Do](#to-do)
|
- [To Do](#to-do)
|
||||||
|
- [Support](#support)
|
||||||
|
- [Contribute](#contributing)
|
||||||
|
- [Disclamer](#disclaimer)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -372,12 +375,11 @@ The `run-container` command mounts also the `config.json` file, so any change to
|
|||||||
| 1337xx | ✅ |
|
| 1337xx | ✅ |
|
||||||
| Altadefinizione | ✅ |
|
| Altadefinizione | ✅ |
|
||||||
| AnimeUnity | ✅ |
|
| AnimeUnity | ✅ |
|
||||||
| BitSearch | ✅ |
|
| Ilcorsaronero | ✅ |
|
||||||
| CB01New | ✅ |
|
| CB01New | ✅ |
|
||||||
| DDLStreamItaly | ✅ |
|
| DDLStreamItaly | ✅ |
|
||||||
| GuardaSerie | ✅ |
|
| GuardaSerie | ✅ |
|
||||||
| MostraGuarda | ✅ |
|
| MostraGuarda | ✅ |
|
||||||
| PirateBays | ✅ |
|
|
||||||
| StreamingCommunity | ✅ |
|
| StreamingCommunity | ✅ |
|
||||||
|
|
||||||
# Tutorials
|
# Tutorials
|
||||||
@ -391,7 +393,7 @@ The `run-container` command mounts also the `config.json` file, so any change to
|
|||||||
|
|
||||||
- Create website API -> https://github.com/Lovi-0/StreamingCommunity/tree/test_gui_1
|
- Create website API -> https://github.com/Lovi-0/StreamingCommunity/tree/test_gui_1
|
||||||
|
|
||||||
# SUPPORT
|
# Support
|
||||||
|
|
||||||
If you'd like to support this project, consider making a donation!
|
If you'd like to support this project, consider making a donation!
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# 02.07.24
|
# 02.07.24
|
||||||
|
|
||||||
from unidecode import unidecode
|
from urllib.parse import quote_plus
|
||||||
|
|
||||||
|
|
||||||
# Internal utilities
|
# Internal utilities
|
||||||
@ -30,7 +30,7 @@ def search(string_to_search: str = None, get_onylDatabase: bool = False):
|
|||||||
string_to_search = msg.ask(f"\n[purple]Insert word to search in [red]{SITE_NAME}").strip()
|
string_to_search = msg.ask(f"\n[purple]Insert word to search in [red]{SITE_NAME}").strip()
|
||||||
|
|
||||||
# Search on database
|
# Search on database
|
||||||
len_database = title_search(unidecode(string_to_search))
|
len_database = title_search(quote_plus(string_to_search))
|
||||||
|
|
||||||
# Return list of elements
|
# Return list of elements
|
||||||
if get_onylDatabase:
|
if get_onylDatabase:
|
||||||
@ -48,4 +48,4 @@ def search(string_to_search: str = None, get_onylDatabase: bool = False):
|
|||||||
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()
|
@ -34,6 +34,8 @@ def title_search(word_to_search: str) -> int:
|
|||||||
Returns:
|
Returns:
|
||||||
- int: The number of titles found.
|
- int: The number of titles found.
|
||||||
"""
|
"""
|
||||||
|
media_search_manager.clear()
|
||||||
|
table_show_manager.clear()
|
||||||
|
|
||||||
# Find new domain if prev dont work
|
# Find new domain if prev dont work
|
||||||
max_timeout = config_manager.get_int("REQUESTS", "timeout")
|
max_timeout = config_manager.get_int("REQUESTS", "timeout")
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# 26.05.24
|
# 26.05.24
|
||||||
|
|
||||||
from unidecode import unidecode
|
from urllib.parse import quote_plus
|
||||||
|
|
||||||
|
|
||||||
# Internal utilities
|
# Internal utilities
|
||||||
@ -30,7 +30,7 @@ def search(string_to_search: str = None, get_onylDatabase: bool = False):
|
|||||||
string_to_search = msg.ask(f"\n[purple]Insert word to search in [red]{SITE_NAME}").strip()
|
string_to_search = msg.ask(f"\n[purple]Insert word to search in [red]{SITE_NAME}").strip()
|
||||||
|
|
||||||
# Search on database
|
# Search on database
|
||||||
len_database = title_search(unidecode(string_to_search))
|
len_database = title_search(quote_plus(string_to_search))
|
||||||
|
|
||||||
# Return list of elements
|
# Return list of elements
|
||||||
if get_onylDatabase:
|
if get_onylDatabase:
|
||||||
@ -48,4 +48,4 @@ def search(string_to_search: str = None, get_onylDatabase: bool = False):
|
|||||||
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()
|
@ -25,13 +25,16 @@ from StreamingCommunity.Api.Player.supervideo import VideoSource
|
|||||||
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) -> str:
|
||||||
"""
|
"""
|
||||||
Downloads a film using the provided film ID, title name, and domain.
|
Downloads a film using the provided film ID, title name, and domain.
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
- title_name (str): The name of the film title.
|
- title_name (str): The name of the film title.
|
||||||
- url (str): The url of the video
|
- url (str): The url of the video
|
||||||
|
|
||||||
|
Return:
|
||||||
|
- str: output path
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Start message and display film information
|
# Start message and display film information
|
||||||
@ -56,14 +59,16 @@ def download_film(select_title: MediaItem):
|
|||||||
output_filename=os.path.join(mp4_path, title_name)
|
output_filename=os.path.join(mp4_path, title_name)
|
||||||
).start()
|
).start()
|
||||||
|
|
||||||
if r_proc == 404:
|
"""if r_proc == 404:
|
||||||
time.sleep(2)
|
time.sleep(2)
|
||||||
|
|
||||||
# Re call search function
|
# Re call search function
|
||||||
if msg.ask("[green]Do you want to continue [white]([red]y[white])[green] or return at home[white]([red]n[white]) ", choices=['y', 'n'], default='y', show_choices=True) == "n":
|
if msg.ask("[green]Do you want to continue [white]([red]y[white])[green] or return at home[white]([red]n[white]) ", choices=['y', 'n'], default='y', show_choices=True) == "n":
|
||||||
frames = get_call_stack()
|
frames = get_call_stack()
|
||||||
execute_search(frames[-4])
|
execute_search(frames[-4])"""
|
||||||
|
|
||||||
if r_proc != None:
|
if r_proc != None:
|
||||||
console.print("[green]Result: ")
|
console.print("[green]Result: ")
|
||||||
console.print(r_proc)
|
console.print(r_proc)
|
||||||
|
|
||||||
|
return os.path.join(mp4_path, title_name)
|
@ -34,13 +34,16 @@ def title_search(title_search: str) -> int:
|
|||||||
Returns:
|
Returns:
|
||||||
int: The number of titles found.
|
int: The number of titles found.
|
||||||
"""
|
"""
|
||||||
client = httpx.Client()
|
media_search_manager.clear()
|
||||||
|
table_show_manager.clear()
|
||||||
|
|
||||||
# Find new domain if prev dont work
|
# Find new domain if prev dont work
|
||||||
max_timeout = config_manager.get_int("REQUESTS", "timeout")
|
max_timeout = config_manager.get_int("REQUESTS", "timeout")
|
||||||
domain_to_use, _ = search_domain(SITE_NAME, f"https://{SITE_NAME}")
|
domain_to_use, _ = search_domain(SITE_NAME, f"https://{SITE_NAME}")
|
||||||
|
|
||||||
# Send request to search for title
|
# Send request to search for title
|
||||||
|
client = httpx.Client()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
response = client.get(
|
response = client.get(
|
||||||
url=f"https://{SITE_NAME}.{domain_to_use}/?story={title_search.replace(' ', '+')}&do=search&subaction=search&titleonly=3",
|
url=f"https://{SITE_NAME}.{domain_to_use}/?story={title_search.replace(' ', '+')}&do=search&subaction=search&titleonly=3",
|
||||||
@ -83,4 +86,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)
|
@ -1,6 +1,6 @@
|
|||||||
# 21.05.24
|
# 21.05.24
|
||||||
|
|
||||||
from unidecode import unidecode
|
from urllib.parse import quote_plus
|
||||||
|
|
||||||
|
|
||||||
# Internal utilities
|
# Internal utilities
|
||||||
@ -27,7 +27,7 @@ def search(string_to_search: str = None, get_onylDatabase: bool = False):
|
|||||||
string_to_search = msg.ask(f"\n[purple]Insert word to search in [red]{SITE_NAME}").strip()
|
string_to_search = msg.ask(f"\n[purple]Insert word to search in [red]{SITE_NAME}").strip()
|
||||||
|
|
||||||
# Search on database
|
# Search on database
|
||||||
len_database = title_search(unidecode(string_to_search))
|
len_database = title_search(quote_plus(string_to_search))
|
||||||
|
|
||||||
# Return list of elements
|
# Return list of elements
|
||||||
if get_onylDatabase:
|
if get_onylDatabase:
|
||||||
@ -48,4 +48,4 @@ def search(string_to_search: str = None, get_onylDatabase: bool = False):
|
|||||||
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()
|
@ -27,12 +27,15 @@ from .costant import ROOT_PATH, SITE_NAME, SERIES_FOLDER, MOVIE_FOLDER
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
def download_episode(index_select: int, scrape_serie: ScrapeSerieAnime, video_source: VideoSourceAnime):
|
def download_episode(index_select: int, scrape_serie: ScrapeSerieAnime, video_source: VideoSourceAnime) -> str:
|
||||||
"""
|
"""
|
||||||
Downloads the selected episode.
|
Downloads the selected episode.
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
- index_select (int): Index of the episode to download.
|
- index_select (int): Index of the episode to download.
|
||||||
|
|
||||||
|
Return:
|
||||||
|
- str: output path
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Get information about the selected episode
|
# Get information about the selected episode
|
||||||
@ -63,14 +66,16 @@ def download_episode(index_select: int, scrape_serie: ScrapeSerieAnime, video_so
|
|||||||
|
|
||||||
# Start downloading
|
# Start downloading
|
||||||
r_proc = MP4_downloader(
|
r_proc = MP4_downloader(
|
||||||
url = str(video_source.src_mp4).strip(),
|
url=str(video_source.src_mp4).strip(),
|
||||||
path = os.path.join(mp4_path, title_name)
|
path=os.path.join(mp4_path, title_name)
|
||||||
)
|
)
|
||||||
|
|
||||||
if r_proc != None:
|
if r_proc != None:
|
||||||
console.print("[green]Result: ")
|
console.print("[green]Result: ")
|
||||||
console.print(r_proc)
|
console.print(r_proc)
|
||||||
|
|
||||||
|
return os.path.join(mp4_path, title_name)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
logging.error(f"Skip index: {index_select} cant find info with api.")
|
logging.error(f"Skip index: {index_select} cant find info with api.")
|
||||||
|
|
||||||
|
@ -99,6 +99,8 @@ def title_search(title: str) -> int:
|
|||||||
Returns:
|
Returns:
|
||||||
- int: A number containing the length of media search manager.
|
- int: A number containing the length of media search manager.
|
||||||
"""
|
"""
|
||||||
|
media_search_manager.clear()
|
||||||
|
table_show_manager.clear()
|
||||||
|
|
||||||
# Get token and session value from configuration
|
# Get token and session value from configuration
|
||||||
max_timeout = config_manager.get_int("REQUESTS", "timeout")
|
max_timeout = config_manager.get_int("REQUESTS", "timeout")
|
||||||
|
@ -1,52 +0,0 @@
|
|||||||
# 01.07.24
|
|
||||||
|
|
||||||
from unidecode import unidecode
|
|
||||||
|
|
||||||
|
|
||||||
# Internal utilities
|
|
||||||
from StreamingCommunity.Util.console import console, msg
|
|
||||||
|
|
||||||
|
|
||||||
# Logic class
|
|
||||||
from .site import title_search, run_get_select_title, media_search_manager
|
|
||||||
from .title import download_title
|
|
||||||
|
|
||||||
|
|
||||||
# Variable
|
|
||||||
indice = 7
|
|
||||||
_useFor = "film_serie"
|
|
||||||
_deprecate = False
|
|
||||||
_priority = 2
|
|
||||||
_engineDownload = "tor"
|
|
||||||
from .costant import SITE_NAME
|
|
||||||
|
|
||||||
|
|
||||||
def search(string_to_search: str = None, get_onylDatabase:bool = False):
|
|
||||||
"""
|
|
||||||
Main function of the application for film and series.
|
|
||||||
"""
|
|
||||||
|
|
||||||
if string_to_search is None:
|
|
||||||
string_to_search = msg.ask(f"\n[purple]Insert word to search in [red]{SITE_NAME}").strip()
|
|
||||||
|
|
||||||
# Search on database
|
|
||||||
len_database = title_search(unidecode(string_to_search))
|
|
||||||
|
|
||||||
# Return list of elements
|
|
||||||
if get_onylDatabase:
|
|
||||||
return media_search_manager
|
|
||||||
|
|
||||||
if len_database > 0:
|
|
||||||
|
|
||||||
# Select title from list
|
|
||||||
select_title = run_get_select_title()
|
|
||||||
|
|
||||||
# Download title
|
|
||||||
download_title(select_title)
|
|
||||||
|
|
||||||
|
|
||||||
else:
|
|
||||||
console.print(f"\n[red]Nothing matching was found for[white]: [purple]{string_to_search}")
|
|
||||||
|
|
||||||
# Retry
|
|
||||||
search()
|
|
@ -1,15 +0,0 @@
|
|||||||
# 01.07.24
|
|
||||||
|
|
||||||
import os
|
|
||||||
|
|
||||||
|
|
||||||
# Internal utilities
|
|
||||||
from StreamingCommunity.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 = config_manager.get('DEFAULT', 'serie_folder_name')
|
|
||||||
MOVIE_FOLDER = config_manager.get('DEFAULT', 'movie_folder_name')
|
|
@ -1,84 +0,0 @@
|
|||||||
# 01.07.24
|
|
||||||
|
|
||||||
# External libraries
|
|
||||||
import httpx
|
|
||||||
from bs4 import BeautifulSoup
|
|
||||||
|
|
||||||
|
|
||||||
# Internal utilities
|
|
||||||
from StreamingCommunity.Util.console import console
|
|
||||||
from StreamingCommunity.Util._jsonConfig import config_manager
|
|
||||||
from StreamingCommunity.Util.headers import get_headers
|
|
||||||
from StreamingCommunity.Util.table import TVShowManager
|
|
||||||
|
|
||||||
|
|
||||||
# Logic class
|
|
||||||
from StreamingCommunity.Api.Template import get_select_title
|
|
||||||
from StreamingCommunity.Api.Template.Util import search_domain
|
|
||||||
from StreamingCommunity.Api.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.
|
|
||||||
"""
|
|
||||||
|
|
||||||
# Find new domain if prev dont work
|
|
||||||
max_timeout = config_manager.get_int("REQUESTS", "timeout")
|
|
||||||
domain_to_use, _ = search_domain(SITE_NAME, f"https://{SITE_NAME}")
|
|
||||||
|
|
||||||
# Construct the full site URL and load the search page
|
|
||||||
try:
|
|
||||||
response = httpx.get(
|
|
||||||
url=f"https://{SITE_NAME}.{domain_to_use}/search?q={word_to_search}&category=1&subcat=2&page=1",
|
|
||||||
headers={'user-agent': get_headers()},
|
|
||||||
timeout=max_timeout
|
|
||||||
)
|
|
||||||
response.raise_for_status()
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
console.print(f"Site: {SITE_NAME}, request search error: {e}")
|
|
||||||
|
|
||||||
# Create soup and find table
|
|
||||||
soup = BeautifulSoup(response.text, "html.parser")
|
|
||||||
|
|
||||||
for title_div in soup.find_all("li", class_ = "card"):
|
|
||||||
try:
|
|
||||||
div_stats = title_div.find("div", class_ = "stats")
|
|
||||||
|
|
||||||
title_info = {
|
|
||||||
'name': title_div.find("a").get_text(strip=True),
|
|
||||||
'url': title_div.find_all("a")[-1].get("href"),
|
|
||||||
#'nDownload': div_stats.find_all("div")[0].get_text(strip=True),
|
|
||||||
'size': div_stats.find_all("div")[1].get_text(strip=True),
|
|
||||||
'seader': div_stats.find_all("div")[2].get_text(strip=True),
|
|
||||||
'leacher': div_stats.find_all("div")[3].get_text(strip=True),
|
|
||||||
'date': div_stats.find_all("div")[4].get_text(strip=True)
|
|
||||||
}
|
|
||||||
|
|
||||||
media_search_manager.add_media(title_info)
|
|
||||||
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
# 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)
|
|
@ -1,6 +1,6 @@
|
|||||||
# 09.06.24
|
# 09.06.24
|
||||||
|
|
||||||
from unidecode import unidecode
|
from urllib.parse import quote_plus
|
||||||
|
|
||||||
|
|
||||||
# Internal utilities
|
# Internal utilities
|
||||||
@ -30,7 +30,7 @@ def search(string_to_search: str = None, get_onylDatabase: bool = False):
|
|||||||
string_to_search = msg.ask(f"\n[purple]Insert word to search in [red]{SITE_NAME}").strip()
|
string_to_search = msg.ask(f"\n[purple]Insert word to search in [red]{SITE_NAME}").strip()
|
||||||
|
|
||||||
# Search on database
|
# Search on database
|
||||||
len_database = title_search(unidecode(string_to_search))
|
len_database = title_search(quote_plus(string_to_search))
|
||||||
|
|
||||||
# Return list of elements
|
# Return list of elements
|
||||||
if get_onylDatabase:
|
if get_onylDatabase:
|
||||||
@ -49,4 +49,4 @@ def search(string_to_search: str = None, get_onylDatabase: bool = False):
|
|||||||
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()
|
@ -1,11 +1,10 @@
|
|||||||
# 03.07.24
|
# 03.07.24
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import time
|
|
||||||
|
|
||||||
|
|
||||||
# Internal utilities
|
# Internal utilities
|
||||||
from StreamingCommunity.Util.console import console, msg
|
from StreamingCommunity.Util.console import console
|
||||||
from StreamingCommunity.Util.os import os_manager
|
from StreamingCommunity.Util.os import os_manager
|
||||||
from StreamingCommunity.Util.message import start_message
|
from StreamingCommunity.Util.message import start_message
|
||||||
from StreamingCommunity.Util.call_stack import get_call_stack
|
from StreamingCommunity.Util.call_stack import get_call_stack
|
||||||
@ -25,12 +24,15 @@ from StreamingCommunity.Api.Player.maxstream import VideoSource
|
|||||||
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) -> str:
|
||||||
"""
|
"""
|
||||||
Downloads a film using the provided obj.
|
Downloads a film using the provided obj.
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
- select_title (MediaItem): The media item to be downloaded. This should be an instance of the MediaItem class, containing attributes like `name` and `url`.
|
- select_title (MediaItem): The media item to be downloaded. This should be an instance of the MediaItem class, containing attributes like `name` and `url`.
|
||||||
|
|
||||||
|
Return:
|
||||||
|
- str: output path
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Start message and display film information
|
# Start message and display film information
|
||||||
@ -56,14 +58,16 @@ def download_film(select_title: MediaItem):
|
|||||||
output_filename=os.path.join(mp4_path, title_name)
|
output_filename=os.path.join(mp4_path, title_name)
|
||||||
).start()
|
).start()
|
||||||
|
|
||||||
if r_proc == 404:
|
"""if r_proc == 404:
|
||||||
time.sleep(2)
|
time.sleep(2)
|
||||||
|
|
||||||
# Re call search function
|
# Re call search function
|
||||||
if msg.ask("[green]Do you want to continue [white]([red]y[white])[green] or return at home[white]([red]n[white]) ", choices=['y', 'n'], default='y', show_choices=True) == "n":
|
if msg.ask("[green]Do you want to continue [white]([red]y[white])[green] or return at home[white]([red]n[white]) ", choices=['y', 'n'], default='y', show_choices=True) == "n":
|
||||||
frames = get_call_stack()
|
frames = get_call_stack()
|
||||||
execute_search(frames[-4])
|
execute_search(frames[-4])"""
|
||||||
|
|
||||||
if r_proc != None:
|
if r_proc != None:
|
||||||
console.print("[green]Result: ")
|
console.print("[green]Result: ")
|
||||||
console.print(r_proc)
|
console.print(r_proc)
|
||||||
|
|
||||||
|
return os.path.join(mp4_path, title_name)
|
@ -33,6 +33,8 @@ def title_search(word_to_search: str) -> int:
|
|||||||
Returns:
|
Returns:
|
||||||
- int: The number of titles found.
|
- int: The number of titles found.
|
||||||
"""
|
"""
|
||||||
|
media_search_manager.clear()
|
||||||
|
table_show_manager.clear()
|
||||||
|
|
||||||
# Find new domain if prev dont work
|
# Find new domain if prev dont work
|
||||||
max_timeout = config_manager.get_int("REQUESTS", "timeout")
|
max_timeout = config_manager.get_int("REQUESTS", "timeout")
|
||||||
@ -71,4 +73,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)
|
@ -1,7 +1,7 @@
|
|||||||
# 09.06.24
|
# 09.06.24
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
from unidecode import unidecode
|
from urllib.parse import quote_plus
|
||||||
|
|
||||||
|
|
||||||
# Internal utilities
|
# Internal utilities
|
||||||
@ -33,7 +33,7 @@ def search(string_to_search: str = None, get_onylDatabase: bool = False):
|
|||||||
string_to_search = msg.ask(f"\n[purple]Insert word to search in [red]{SITE_NAME}").strip()
|
string_to_search = msg.ask(f"\n[purple]Insert word to search in [red]{SITE_NAME}").strip()
|
||||||
|
|
||||||
# Search on database
|
# Search on database
|
||||||
len_database = title_search(unidecode(string_to_search))
|
len_database = title_search(quote_plus(string_to_search))
|
||||||
|
|
||||||
# Return list of elements
|
# Return list of elements
|
||||||
if get_onylDatabase:
|
if get_onylDatabase:
|
||||||
@ -55,4 +55,4 @@ def search(string_to_search: str = None, get_onylDatabase: bool = False):
|
|||||||
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()
|
@ -29,13 +29,16 @@ table_show_manager = TVShowManager()
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
def download_video(index_episode_selected: int, scape_info_serie: GetSerieInfo, video_source: VideoSource) -> None:
|
def download_video(index_episode_selected: int, scape_info_serie: GetSerieInfo, video_source: VideoSource) -> str:
|
||||||
"""
|
"""
|
||||||
Download a single episode video.
|
Download a single episode video.
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
- tv_name (str): Name of the TV series.
|
- tv_name (str): Name of the TV series.
|
||||||
- index_episode_selected (int): Index of the selected episode.
|
- index_episode_selected (int): Index of the selected episode.
|
||||||
|
|
||||||
|
Return:
|
||||||
|
- str: output path
|
||||||
"""
|
"""
|
||||||
|
|
||||||
start_message()
|
start_message()
|
||||||
@ -65,15 +68,17 @@ def download_video(index_episode_selected: int, scape_info_serie: GetSerieInfo,
|
|||||||
|
|
||||||
# Start download
|
# Start download
|
||||||
r_proc = MP4_downloader(
|
r_proc = MP4_downloader(
|
||||||
url = master_playlist,
|
url=master_playlist,
|
||||||
path = os.path.join(mp4_path, title_name),
|
path=os.path.join(mp4_path, title_name),
|
||||||
referer = f"{parsed_url.scheme}://{parsed_url.netloc}/",
|
referer=f"{parsed_url.scheme}://{parsed_url.netloc}/",
|
||||||
)
|
)
|
||||||
|
|
||||||
if r_proc != None:
|
if r_proc != None:
|
||||||
console.print("[green]Result: ")
|
console.print("[green]Result: ")
|
||||||
console.print(r_proc)
|
console.print(r_proc)
|
||||||
|
|
||||||
|
return os.path.join(mp4_path, title_name)
|
||||||
|
|
||||||
|
|
||||||
def download_thread(dict_serie: MediaItem):
|
def download_thread(dict_serie: MediaItem):
|
||||||
"""
|
"""
|
||||||
|
@ -37,6 +37,8 @@ def title_search(word_to_search: str) -> int:
|
|||||||
Returns:
|
Returns:
|
||||||
- int: The number of titles found.
|
- int: The number of titles found.
|
||||||
"""
|
"""
|
||||||
|
media_search_manager.clear()
|
||||||
|
table_show_manager.clear()
|
||||||
|
|
||||||
# Find new domain if prev dont work
|
# Find new domain if prev dont work
|
||||||
max_timeout = config_manager.get_int("REQUESTS", "timeout")
|
max_timeout = config_manager.get_int("REQUESTS", "timeout")
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# 09.06.24
|
# 09.06.24
|
||||||
|
|
||||||
from unidecode import unidecode
|
from urllib.parse import quote_plus
|
||||||
|
|
||||||
|
|
||||||
# Internal utilities
|
# Internal utilities
|
||||||
@ -32,7 +32,7 @@ def search(string_to_search: str = None, get_onylDatabase: bool = False):
|
|||||||
string_to_search = msg.ask(f"\n[purple]Insert word to search in [red]{SITE_NAME}").strip()
|
string_to_search = msg.ask(f"\n[purple]Insert word to search in [red]{SITE_NAME}").strip()
|
||||||
|
|
||||||
# Search on database
|
# Search on database
|
||||||
len_database = title_search(unidecode(string_to_search))
|
len_database = title_search(quote_plus(string_to_search))
|
||||||
|
|
||||||
# Return list of elements
|
# Return list of elements
|
||||||
if get_onylDatabase:
|
if get_onylDatabase:
|
||||||
@ -50,4 +50,4 @@ def search(string_to_search: str = None, get_onylDatabase: bool = False):
|
|||||||
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()
|
@ -29,7 +29,7 @@ table_show_manager = TVShowManager()
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
def download_video(index_season_selected: int, index_episode_selected: int, scape_info_serie: GetSerieInfo) -> None:
|
def download_video(index_season_selected: int, index_episode_selected: int, scape_info_serie: GetSerieInfo) -> str:
|
||||||
"""
|
"""
|
||||||
Download a single episode video.
|
Download a single episode video.
|
||||||
|
|
||||||
@ -37,6 +37,9 @@ def download_video(index_season_selected: int, index_episode_selected: int, scap
|
|||||||
- tv_name (str): Name of the TV series.
|
- tv_name (str): Name of the TV series.
|
||||||
- index_season_selected (int): Index of the selected season.
|
- index_season_selected (int): Index of the selected season.
|
||||||
- index_episode_selected (int): Index of the selected episode.
|
- index_episode_selected (int): Index of the selected episode.
|
||||||
|
|
||||||
|
Return:
|
||||||
|
- str: output path
|
||||||
"""
|
"""
|
||||||
|
|
||||||
start_message()
|
start_message()
|
||||||
@ -62,18 +65,19 @@ def download_video(index_season_selected: int, index_episode_selected: int, scap
|
|||||||
output_filename=os.path.join(mp4_path, mp4_name)
|
output_filename=os.path.join(mp4_path, mp4_name)
|
||||||
).start()
|
).start()
|
||||||
|
|
||||||
if r_proc == 404:
|
"""if r_proc == 404:
|
||||||
time.sleep(2)
|
time.sleep(2)
|
||||||
|
|
||||||
# Re call search function
|
# Re call search function
|
||||||
if msg.ask("[green]Do you want to continue [white]([red]y[white])[green] or return at home[white]([red]n[white]) ", choices=['y', 'n'], default='y', show_choices=True) == "n":
|
if msg.ask("[green]Do you want to continue [white]([red]y[white])[green] or return at home[white]([red]n[white]) ", choices=['y', 'n'], default='y', show_choices=True) == "n":
|
||||||
frames = get_call_stack()
|
frames = get_call_stack()
|
||||||
execute_search(frames[-4])
|
execute_search(frames[-4])"""
|
||||||
|
|
||||||
if r_proc != None:
|
if r_proc != None:
|
||||||
console.print("[green]Result: ")
|
console.print("[green]Result: ")
|
||||||
console.print(r_proc)
|
console.print(r_proc)
|
||||||
|
|
||||||
|
return os.path.join(mp4_path, mp4_name)
|
||||||
|
|
||||||
|
|
||||||
def download_episode(scape_info_serie: GetSerieInfo, index_season_selected: int, download_all: bool = False) -> None:
|
def download_episode(scape_info_serie: GetSerieInfo, index_season_selected: int, download_all: bool = False) -> None:
|
||||||
|
@ -34,6 +34,8 @@ def title_search(word_to_search: str) -> int:
|
|||||||
Returns:
|
Returns:
|
||||||
- int: The number of titles found.
|
- int: The number of titles found.
|
||||||
"""
|
"""
|
||||||
|
media_search_manager.clear()
|
||||||
|
table_show_manager.clear()
|
||||||
|
|
||||||
# Find new domain if prev dont work
|
# Find new domain if prev dont work
|
||||||
max_timeout = config_manager.get_int("REQUESTS", "timeout")
|
max_timeout = config_manager.get_int("REQUESTS", "timeout")
|
||||||
@ -81,4 +83,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)
|
@ -1,6 +1,7 @@
|
|||||||
# 02.07.24
|
# 02.07.24
|
||||||
|
|
||||||
from unidecode import unidecode
|
import asyncio
|
||||||
|
from urllib.parse import quote_plus
|
||||||
|
|
||||||
|
|
||||||
# Internal utilities
|
# Internal utilities
|
||||||
@ -13,7 +14,7 @@ from .title import download_title
|
|||||||
|
|
||||||
|
|
||||||
# Variable
|
# Variable
|
||||||
indice = 8
|
indice = 9
|
||||||
_useFor = "film_serie"
|
_useFor = "film_serie"
|
||||||
_deprecate = False
|
_deprecate = False
|
||||||
_priority = 2
|
_priority = 2
|
||||||
@ -30,7 +31,7 @@ def search(string_to_search: str = None, get_onylDatabase: bool = False):
|
|||||||
string_to_search = msg.ask(f"\n[purple]Insert word to search in [red]{SITE_NAME}").strip()
|
string_to_search = msg.ask(f"\n[purple]Insert word to search in [red]{SITE_NAME}").strip()
|
||||||
|
|
||||||
# Search on database
|
# Search on database
|
||||||
len_database = title_search(unidecode(string_to_search))
|
len_database = asyncio.run(title_search(quote_plus(string_to_search)))
|
||||||
|
|
||||||
# Return list of elements
|
# Return list of elements
|
||||||
if get_onylDatabase:
|
if get_onylDatabase:
|
||||||
@ -48,4 +49,4 @@ def search(string_to_search: str = None, get_onylDatabase: bool = False):
|
|||||||
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()
|
63
StreamingCommunity/Api/Site/ilcorsaronero/site.py
Normal file
63
StreamingCommunity/Api/Site/ilcorsaronero/site.py
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
# 02.07.24
|
||||||
|
|
||||||
|
|
||||||
|
# Internal utilities
|
||||||
|
from StreamingCommunity.Util.table import TVShowManager
|
||||||
|
|
||||||
|
|
||||||
|
# Logic class
|
||||||
|
from StreamingCommunity.Api.Template import get_select_title
|
||||||
|
from StreamingCommunity.Api.Template.Util import search_domain
|
||||||
|
from StreamingCommunity.Api.Template.Class.SearchType import MediaManager
|
||||||
|
from .util.ilCorsarScraper import IlCorsaroNeroScraper
|
||||||
|
|
||||||
|
|
||||||
|
# Variable
|
||||||
|
from .costant import SITE_NAME
|
||||||
|
media_search_manager = MediaManager()
|
||||||
|
table_show_manager = TVShowManager()
|
||||||
|
|
||||||
|
|
||||||
|
async 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.
|
||||||
|
"""
|
||||||
|
media_search_manager.clear()
|
||||||
|
table_show_manager.clear()
|
||||||
|
|
||||||
|
# Find new domain if prev dont work
|
||||||
|
domain_to_use, _ = search_domain(SITE_NAME, f"https://{SITE_NAME}")
|
||||||
|
|
||||||
|
# Create scraper and collect result
|
||||||
|
print("\n")
|
||||||
|
scraper = IlCorsaroNeroScraper(f"https://{SITE_NAME}.{domain_to_use}/", 1)
|
||||||
|
results = await scraper.search(word_to_search)
|
||||||
|
|
||||||
|
# Add all result to media manager
|
||||||
|
for i, torrent in enumerate(results):
|
||||||
|
media_search_manager.add_media({
|
||||||
|
'name': torrent['name'],
|
||||||
|
'type': torrent['type'],
|
||||||
|
'seed': torrent['seed'],
|
||||||
|
'leech': torrent['leech'],
|
||||||
|
'size': torrent['size'],
|
||||||
|
'date': torrent['date'],
|
||||||
|
'url': torrent['url']
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
# 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)
|
@ -1,12 +1,12 @@
|
|||||||
# 01.07.24
|
# 02.07.24
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
|
||||||
# Internal utilities
|
# Internal utilities
|
||||||
from StreamingCommunity.Util.console import console
|
from StreamingCommunity.Util.console import console
|
||||||
from StreamingCommunity.Util.message import start_message
|
|
||||||
from StreamingCommunity.Util.os import os_manager
|
from StreamingCommunity.Util.os import os_manager
|
||||||
|
from StreamingCommunity.Util.message import start_message
|
||||||
from StreamingCommunity.Lib.Downloader import TOR_downloader
|
from StreamingCommunity.Lib.Downloader import TOR_downloader
|
||||||
|
|
||||||
|
|
||||||
@ -27,18 +27,17 @@ def download_title(select_title: MediaItem):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
start_message()
|
start_message()
|
||||||
|
|
||||||
console.print(f"[yellow]Download: [red]{select_title.name} \n")
|
console.print(f"[yellow]Download: [red]{select_title.name} \n")
|
||||||
print()
|
print()
|
||||||
|
|
||||||
# Define output path
|
# Define output path
|
||||||
title_name = os_manager.get_sanitize_file(select_title.name.replace("-", "_") + ".mp4")
|
title_name = os_manager.get_sanitize_file(select_title.name)
|
||||||
mp4_path = os_manager.get_sanitize_path(
|
mp4_path = os_manager.get_sanitize_path(
|
||||||
os.path.join(ROOT_PATH, SITE_NAME, MOVIE_FOLDER, title_name.replace(".mp4", ""))
|
os.path.join(ROOT_PATH, SITE_NAME, MOVIE_FOLDER, title_name.replace(".mp4", ""))
|
||||||
)
|
)
|
||||||
|
|
||||||
# Create output folder
|
# Create output folder
|
||||||
os_manager.create_path(mp4_path)
|
os_manager.create_path(mp4_path)
|
||||||
|
|
||||||
# Tor manager
|
# Tor manager
|
||||||
manager = TOR_downloader()
|
manager = TOR_downloader()
|
@ -0,0 +1,139 @@
|
|||||||
|
# 12.14.24
|
||||||
|
import logging
|
||||||
|
import asyncio
|
||||||
|
from typing import List, Dict, Optional
|
||||||
|
|
||||||
|
|
||||||
|
# External libraries
|
||||||
|
import httpx
|
||||||
|
from bs4 import BeautifulSoup
|
||||||
|
|
||||||
|
|
||||||
|
# Internal utilities
|
||||||
|
from StreamingCommunity.Util._jsonConfig import config_manager
|
||||||
|
from StreamingCommunity.Util.console import console
|
||||||
|
|
||||||
|
|
||||||
|
# Variable
|
||||||
|
max_timeout = config_manager.get_int("REQUESTS", "timeout")
|
||||||
|
|
||||||
|
|
||||||
|
class IlCorsaroNeroScraper:
|
||||||
|
def __init__(self, base_url: str, max_page: int = 1):
|
||||||
|
self.base_url = base_url
|
||||||
|
self.max_page = max_page
|
||||||
|
self.headers = {
|
||||||
|
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
|
||||||
|
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8',
|
||||||
|
'Accept-Language': 'en-US,en;q=0.5',
|
||||||
|
'Connection': 'keep-alive',
|
||||||
|
'Upgrade-Insecure-Requests': '1'
|
||||||
|
}
|
||||||
|
|
||||||
|
async def fetch_url(self, url: str) -> Optional[str]:
|
||||||
|
"""
|
||||||
|
Fetch the HTML content of a given URL.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
console.print(f"[cyan]Fetching url[white]: [red]{url}")
|
||||||
|
async with httpx.AsyncClient(headers=self.headers, follow_redirects=True, timeout=max_timeout) as client:
|
||||||
|
response = await client.get(url)
|
||||||
|
|
||||||
|
# If the request was successful, return the HTML content
|
||||||
|
response.raise_for_status()
|
||||||
|
return response.text
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logging.error(f"Error fetching {url}: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def parse_torrents(self, html: str) -> List[Dict[str, str]]:
|
||||||
|
"""
|
||||||
|
Parse the HTML content and extract torrent details.
|
||||||
|
"""
|
||||||
|
torrents = []
|
||||||
|
soup = BeautifulSoup(html, "html.parser")
|
||||||
|
table = soup.find("tbody")
|
||||||
|
|
||||||
|
for row in table.find_all("tr"):
|
||||||
|
try:
|
||||||
|
columns = row.find_all("td")
|
||||||
|
|
||||||
|
torrents.append({
|
||||||
|
'type': columns[0].get_text(strip=True),
|
||||||
|
'name': row.find("th").find("a").get_text(strip=True),
|
||||||
|
'seed': columns[1].get_text(strip=True),
|
||||||
|
'leech': columns[2].get_text(strip=True),
|
||||||
|
'size': columns[3].get_text(strip=True),
|
||||||
|
'date': columns[4].get_text(strip=True),
|
||||||
|
'url': "https://ilcorsaronero.link" + row.find("th").find("a").get("href")
|
||||||
|
})
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logging.error(f"Error parsing row: {e}")
|
||||||
|
continue
|
||||||
|
|
||||||
|
return torrents
|
||||||
|
|
||||||
|
async def fetch_real_url(self, url: str) -> Optional[str]:
|
||||||
|
"""
|
||||||
|
Fetch the real torrent URL from the detailed page.
|
||||||
|
"""
|
||||||
|
response_html = await self.fetch_url(url)
|
||||||
|
if not response_html:
|
||||||
|
return None
|
||||||
|
|
||||||
|
soup = BeautifulSoup(response_html, "html.parser")
|
||||||
|
links = soup.find_all("a")
|
||||||
|
|
||||||
|
# Find and return the magnet link
|
||||||
|
for link in links:
|
||||||
|
if "magnet" in str(link):
|
||||||
|
return link.get("href")
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
async def search(self, query: str) -> List[Dict[str, str]]:
|
||||||
|
"""
|
||||||
|
Search for torrents based on the query string.
|
||||||
|
"""
|
||||||
|
all_torrents = []
|
||||||
|
|
||||||
|
# Loop through each page
|
||||||
|
for page in range(self.max_page):
|
||||||
|
url = f'{self.base_url}search?q={query}&page={page}'
|
||||||
|
|
||||||
|
html = await self.fetch_url(url)
|
||||||
|
if not html:
|
||||||
|
console.print(f"[bold red]No HTML content for page {page}[/bold red]")
|
||||||
|
break
|
||||||
|
|
||||||
|
torrents = self.parse_torrents(html)
|
||||||
|
if not torrents:
|
||||||
|
console.print(f"[bold red]No torrents found on page {page}[/bold red]")
|
||||||
|
break
|
||||||
|
|
||||||
|
# Use asyncio.gather to fetch all real URLs concurrently
|
||||||
|
tasks = [self.fetch_real_url(result['url']) for result in torrents]
|
||||||
|
real_urls = await asyncio.gather(*tasks)
|
||||||
|
|
||||||
|
# Attach real URLs to the torrent data
|
||||||
|
for i, result in enumerate(torrents):
|
||||||
|
result['url'] = real_urls[i]
|
||||||
|
|
||||||
|
all_torrents.extend(torrents)
|
||||||
|
|
||||||
|
return all_torrents
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
scraper = IlCorsaroNeroScraper("https://ilcorsaronero.link/")
|
||||||
|
results = await scraper.search("cars")
|
||||||
|
|
||||||
|
if results:
|
||||||
|
for i, torrent in enumerate(results):
|
||||||
|
console.print(f"[bold green]{i} = {torrent}[/bold green] \n")
|
||||||
|
else:
|
||||||
|
console.print("[bold red]No torrents found.[/bold red]")
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
asyncio.run(main())
|
@ -1,6 +1,6 @@
|
|||||||
# 26.05.24
|
# 26.05.24
|
||||||
|
|
||||||
from unidecode import unidecode
|
from urllib.parse import quote_plus
|
||||||
|
|
||||||
|
|
||||||
# Internal utilities
|
# Internal utilities
|
||||||
@ -34,7 +34,7 @@ def search(string_to_search: str = None, get_onylDatabase: bool = False):
|
|||||||
return 0
|
return 0
|
||||||
|
|
||||||
# Search on database
|
# Search on database
|
||||||
movie_id = tmdb.search_movie(unidecode(string_to_search))
|
movie_id = tmdb.search_movie(quote_plus(string_to_search))
|
||||||
|
|
||||||
if movie_id is not None:
|
if movie_id is not None:
|
||||||
movie_details: Json_film = tmdb.get_movie_details(tmdb_id=movie_id)
|
movie_details: Json_film = tmdb.get_movie_details(tmdb_id=movie_id)
|
||||||
@ -46,4 +46,4 @@ def search(string_to_search: str = None, get_onylDatabase: bool = False):
|
|||||||
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()
|
@ -36,12 +36,15 @@ from StreamingCommunity.Lib.TMBD import Json_film
|
|||||||
from .costant import ROOT_PATH, SITE_NAME, DOMAIN_NOW, MOVIE_FOLDER
|
from .costant import ROOT_PATH, SITE_NAME, DOMAIN_NOW, MOVIE_FOLDER
|
||||||
|
|
||||||
|
|
||||||
def download_film(movie_details: Json_film):
|
def download_film(movie_details: Json_film) -> str:
|
||||||
"""
|
"""
|
||||||
Downloads a film using the provided tmbd id.
|
Downloads a film using the provided tmbd id.
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
- movie_details (Json_film): Class with info about film title.
|
- movie_details (Json_film): Class with info about film title.
|
||||||
|
|
||||||
|
Return:
|
||||||
|
- str: output path
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Start message and display film information
|
# Start message and display film information
|
||||||
@ -81,14 +84,16 @@ def download_film(movie_details: Json_film):
|
|||||||
output_filename=os.path.join(mp4_path, title_name)
|
output_filename=os.path.join(mp4_path, title_name)
|
||||||
).start()
|
).start()
|
||||||
|
|
||||||
if r_proc == 404:
|
"""if r_proc == 404:
|
||||||
time.sleep(2)
|
time.sleep(2)
|
||||||
|
|
||||||
# Re call search function
|
# Re call search function
|
||||||
if msg.ask("[green]Do you want to continue [white]([red]y[white])[green] or return at home[white]([red]n[white]) ", choices=['y', 'n'], default='y', show_choices=True) == "n":
|
if msg.ask("[green]Do you want to continue [white]([red]y[white])[green] or return at home[white]([red]n[white]) ", choices=['y', 'n'], default='y', show_choices=True) == "n":
|
||||||
frames = get_call_stack()
|
frames = get_call_stack()
|
||||||
execute_search(frames[-4])
|
execute_search(frames[-4])"""
|
||||||
|
|
||||||
if r_proc != None:
|
if r_proc != None:
|
||||||
console.print("[green]Result: ")
|
console.print("[green]Result: ")
|
||||||
console.print(r_proc)
|
console.print(r_proc)
|
||||||
|
|
||||||
|
return os.path.join(mp4_path, title_name)
|
@ -1,89 +0,0 @@
|
|||||||
# 02.07.24
|
|
||||||
|
|
||||||
# External libraries
|
|
||||||
import httpx
|
|
||||||
from bs4 import BeautifulSoup
|
|
||||||
|
|
||||||
|
|
||||||
# Internal utilities
|
|
||||||
from StreamingCommunity.Util.console import console
|
|
||||||
from StreamingCommunity.Util._jsonConfig import config_manager
|
|
||||||
from StreamingCommunity.Util.headers import get_headers
|
|
||||||
from StreamingCommunity.Util.table import TVShowManager
|
|
||||||
|
|
||||||
|
|
||||||
# Logic class
|
|
||||||
from StreamingCommunity.Api.Template import get_select_title
|
|
||||||
from StreamingCommunity.Api.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.
|
|
||||||
"""
|
|
||||||
|
|
||||||
# Find new domain if prev dont work
|
|
||||||
max_timeout = config_manager.get_int("REQUESTS", "timeout")
|
|
||||||
|
|
||||||
# Construct the full site URL and load the search page
|
|
||||||
try:
|
|
||||||
response = httpx.get(
|
|
||||||
url=f"https://1.{SITE_NAME}.{DOMAIN_NOW}/s/?q={word_to_search}&video=on",
|
|
||||||
headers={
|
|
||||||
'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
|
|
||||||
'accept-language': 'it-IT,it;q=0.9,en-US;q=0.8,en;q=0.7',
|
|
||||||
'referer': 'https://wwv.thepiratebay3.co/',
|
|
||||||
'user-agent': get_headers()
|
|
||||||
},
|
|
||||||
follow_redirects=True,
|
|
||||||
timeout=max_timeout
|
|
||||||
)
|
|
||||||
response.raise_for_status()
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
console.print(f"Site: {SITE_NAME}, request search error: {e}")
|
|
||||||
|
|
||||||
# Create soup and find table
|
|
||||||
soup = BeautifulSoup(response.text, "html.parser")
|
|
||||||
table = soup.find("tbody")
|
|
||||||
|
|
||||||
# Scrape div film in table on single page
|
|
||||||
for tr in table.find_all('tr'):
|
|
||||||
try:
|
|
||||||
|
|
||||||
title_info = {
|
|
||||||
'name': tr.find_all("a")[1].get_text(strip=True),
|
|
||||||
'url': tr.find_all("td")[3].find("a").get("href"),
|
|
||||||
'upload': tr.find_all("td")[2].get_text(strip=True),
|
|
||||||
'size': tr.find_all("td")[4].get_text(strip=True),
|
|
||||||
'seader': tr.find_all("td")[5].get_text(strip=True),
|
|
||||||
'leacher': tr.find_all("td")[6].get_text(strip=True),
|
|
||||||
'by': tr.find_all("td")[7].get_text(strip=True),
|
|
||||||
}
|
|
||||||
|
|
||||||
media_search_manager.add_media(title_info)
|
|
||||||
|
|
||||||
except:
|
|
||||||
continue
|
|
||||||
|
|
||||||
# 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)
|
|
@ -1,45 +0,0 @@
|
|||||||
# 02.07.24
|
|
||||||
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
|
|
||||||
|
|
||||||
# Internal utilities
|
|
||||||
from StreamingCommunity.Util.console import console
|
|
||||||
from StreamingCommunity.Util.message import start_message
|
|
||||||
from StreamingCommunity.Util.os import os_manager
|
|
||||||
from StreamingCommunity.Lib.Downloader import TOR_downloader
|
|
||||||
|
|
||||||
|
|
||||||
# Logic class
|
|
||||||
from StreamingCommunity.Api.Template.Class.SearchType import MediaItem
|
|
||||||
|
|
||||||
|
|
||||||
# Config
|
|
||||||
from .costant import ROOT_PATH, DOMAIN_NOW, SITE_NAME, MOVIE_FOLDER
|
|
||||||
|
|
||||||
|
|
||||||
def download_title(select_title: MediaItem):
|
|
||||||
"""
|
|
||||||
Downloads a media item and saves it as an MP4 file.
|
|
||||||
|
|
||||||
Parameters:
|
|
||||||
- select_title (MediaItem): The media item to be downloaded. This should be an instance of the MediaItem class, containing attributes like `name` and `url`.
|
|
||||||
"""
|
|
||||||
|
|
||||||
start_message()
|
|
||||||
console.print(f"[yellow]Download: [red]{select_title.name} \n")
|
|
||||||
print()
|
|
||||||
|
|
||||||
# Define output path
|
|
||||||
title_name = os_manager.get_sanitize_file(select_title.name.replace("-", "_") + ".mp4")
|
|
||||||
mp4_path = os.path.join(ROOT_PATH, SITE_NAME, MOVIE_FOLDER, title_name.replace(".mp4", ""))
|
|
||||||
|
|
||||||
# Create output folder
|
|
||||||
os_manager.create_path(mp4_path)
|
|
||||||
|
|
||||||
# Tor manager
|
|
||||||
manager = TOR_downloader()
|
|
||||||
manager.add_magnet_link(select_title.url)
|
|
||||||
manager.start_download()
|
|
||||||
manager.move_downloaded_files(mp4_path)
|
|
@ -1,6 +1,6 @@
|
|||||||
# 21.05.24
|
# 21.05.24
|
||||||
|
|
||||||
from unidecode import unidecode
|
from urllib.parse import quote_plus
|
||||||
|
|
||||||
|
|
||||||
# Internal utilities
|
# Internal utilities
|
||||||
@ -32,12 +32,12 @@ def search(string_to_search: str = None, get_onylDatabase: bool = False):
|
|||||||
|
|
||||||
# Get site domain and version and get result of the search
|
# Get site domain and version and get result of the search
|
||||||
site_version, domain = get_version_and_domain()
|
site_version, domain = get_version_and_domain()
|
||||||
len_database = title_search(unidecode(string_to_search), domain)
|
len_database = title_search(quote_plus(string_to_search), domain)
|
||||||
|
|
||||||
# Return list of elements
|
# Return list of elements
|
||||||
if get_onylDatabase:
|
if get_onylDatabase:
|
||||||
return media_search_manager
|
return media_search_manager
|
||||||
|
|
||||||
if len_database > 0:
|
if len_database > 0:
|
||||||
|
|
||||||
# Select title from list
|
# Select title from list
|
||||||
@ -53,4 +53,4 @@ def search(string_to_search: str = None, get_onylDatabase: bool = False):
|
|||||||
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()
|
@ -25,13 +25,16 @@ from StreamingCommunity.Api.Player.vixcloud import VideoSource
|
|||||||
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) -> str:
|
||||||
"""
|
"""
|
||||||
Downloads a film using the provided film ID, title name, and domain.
|
Downloads a film using the provided film ID, title name, and domain.
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
- domain (str): The domain of the site
|
- domain (str): The domain of the site
|
||||||
- version (str): Version of site.
|
- version (str): Version of site.
|
||||||
|
|
||||||
|
Return:
|
||||||
|
- str: output path
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Start message and display film information
|
# Start message and display film information
|
||||||
@ -57,14 +60,16 @@ def download_film(select_title: MediaItem):
|
|||||||
output_filename=os.path.join(mp4_path, title_name)
|
output_filename=os.path.join(mp4_path, title_name)
|
||||||
).start()
|
).start()
|
||||||
|
|
||||||
if r_proc == 404:
|
"""if r_proc == 404:
|
||||||
time.sleep(2)
|
time.sleep(2)
|
||||||
|
|
||||||
# Re call search function
|
# Re call search function
|
||||||
if msg.ask("[green]Do you want to continue [white]([red]y[white])[green] or return at home[white]([red]n[white]) ", choices=['y', 'n'], default='y', show_choices=True) == "n":
|
if msg.ask("[green]Do you want to continue [white]([red]y[white])[green] or return at home[white]([red]n[white]) ", choices=['y', 'n'], default='y', show_choices=True) == "n":
|
||||||
frames = get_call_stack()
|
frames = get_call_stack()
|
||||||
execute_search(frames[-4])
|
execute_search(frames[-4])"""
|
||||||
|
|
||||||
if r_proc != None:
|
if r_proc != None:
|
||||||
console.print("[green]Result: ")
|
console.print("[green]Result: ")
|
||||||
console.print(r_proc)
|
console.print(r_proc)
|
||||||
|
|
||||||
|
return os.path.join(mp4_path, title_name)
|
@ -29,16 +29,17 @@ table_show_manager = TVShowManager()
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
def download_video(tv_name: str, index_season_selected: int, index_episode_selected: int, scrape_serie: ScrapeSerie, video_source: VideoSource) -> None:
|
def download_video(index_season_selected: int, index_episode_selected: int, scrape_serie: ScrapeSerie, video_source: VideoSource) -> str:
|
||||||
"""
|
"""
|
||||||
Download a single episode video.
|
Download a single episode video.
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
- tv_name (str): Name of the TV series.
|
|
||||||
- index_season_selected (int): Index of the selected season.
|
- index_season_selected (int): Index of the selected season.
|
||||||
- index_episode_selected (int): Index of the selected episode.
|
- index_episode_selected (int): Index of the selected episode.
|
||||||
"""
|
|
||||||
|
|
||||||
|
Return:
|
||||||
|
- str: output path
|
||||||
|
"""
|
||||||
start_message()
|
start_message()
|
||||||
|
|
||||||
# Get info about episode
|
# Get info about episode
|
||||||
@ -47,8 +48,8 @@ def download_video(tv_name: str, index_season_selected: int, index_episode_selec
|
|||||||
print()
|
print()
|
||||||
|
|
||||||
# Define filename and path for the downloaded video
|
# Define filename and path for the downloaded video
|
||||||
mp4_name = f"{map_episode_title(tv_name, index_season_selected, index_episode_selected, obj_episode.name)}.mp4"
|
mp4_name = f"{map_episode_title(scrape_serie.series_name, index_season_selected, index_episode_selected, obj_episode.name)}.mp4"
|
||||||
mp4_path = os.path.join(ROOT_PATH, SITE_NAME, SERIES_FOLDER, tv_name, f"S{index_season_selected}")
|
mp4_path = os.path.join(ROOT_PATH, SITE_NAME, SERIES_FOLDER, scrape_serie.series_name, f"S{index_season_selected}")
|
||||||
|
|
||||||
# Retrieve scws and if available master playlist
|
# Retrieve scws and if available master playlist
|
||||||
video_source.get_iframe(obj_episode.id)
|
video_source.get_iframe(obj_episode.id)
|
||||||
@ -61,24 +62,25 @@ def download_video(tv_name: str, index_season_selected: int, index_episode_selec
|
|||||||
output_filename=os.path.join(mp4_path, mp4_name)
|
output_filename=os.path.join(mp4_path, mp4_name)
|
||||||
).start()
|
).start()
|
||||||
|
|
||||||
if r_proc == 404:
|
"""if r_proc == 404:
|
||||||
time.sleep(2)
|
time.sleep(2)
|
||||||
|
|
||||||
# Re call search function
|
# Re call search function
|
||||||
if msg.ask("[green]Do you want to continue [white]([red]y[white])[green] or return at home[white]([red]n[white]) ", choices=['y', 'n'], default='y', show_choices=True) == "n":
|
if msg.ask("[green]Do you want to continue [white]([red]y[white])[green] or return at home[white]([red]n[white]) ", choices=['y', 'n'], default='y', show_choices=True) == "n":
|
||||||
frames = get_call_stack()
|
frames = get_call_stack()
|
||||||
execute_search(frames[-4])
|
execute_search(frames[-4])"""
|
||||||
|
|
||||||
if r_proc != None:
|
if r_proc != None:
|
||||||
console.print("[green]Result: ")
|
console.print("[green]Result: ")
|
||||||
console.print(r_proc)
|
console.print(r_proc)
|
||||||
|
|
||||||
def download_episode(tv_name: str, index_season_selected: int, scrape_serie: ScrapeSerie, video_source: VideoSource, download_all: bool = False) -> None:
|
return os.path.join(mp4_path, mp4_name)
|
||||||
|
|
||||||
|
def download_episode(index_season_selected: int, scrape_serie: ScrapeSerie, video_source: VideoSource, download_all: bool = False) -> None:
|
||||||
"""
|
"""
|
||||||
Download episodes of a selected season.
|
Download episodes of a selected season.
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
- tv_name (str): Name of the TV series.
|
|
||||||
- index_season_selected (int): Index of the selected season.
|
- index_season_selected (int): Index of the selected season.
|
||||||
- download_all (bool): Download all episodes in the season.
|
- download_all (bool): Download all episodes in the season.
|
||||||
"""
|
"""
|
||||||
@ -95,7 +97,7 @@ def download_episode(tv_name: str, index_season_selected: int, scrape_serie: Scr
|
|||||||
|
|
||||||
# Download all episodes without asking
|
# Download all episodes without asking
|
||||||
for i_episode in range(1, episodes_count + 1):
|
for i_episode in range(1, episodes_count + 1):
|
||||||
download_video(tv_name, index_season_selected, i_episode, scrape_serie, video_source)
|
download_video(index_season_selected, i_episode, scrape_serie, video_source)
|
||||||
console.print(f"\n[red]End downloaded [yellow]season: [red]{index_season_selected}.")
|
console.print(f"\n[red]End downloaded [yellow]season: [red]{index_season_selected}.")
|
||||||
|
|
||||||
else:
|
else:
|
||||||
@ -112,7 +114,7 @@ def download_episode(tv_name: str, index_season_selected: int, scrape_serie: Scr
|
|||||||
|
|
||||||
# Download selected episodes
|
# Download selected episodes
|
||||||
for i_episode in list_episode_select:
|
for i_episode in list_episode_select:
|
||||||
download_video(tv_name, index_season_selected, i_episode, scrape_serie, video_source)
|
download_video(index_season_selected, i_episode, scrape_serie, video_source)
|
||||||
|
|
||||||
def download_series(select_season: MediaItem, version: str) -> None:
|
def download_series(select_season: MediaItem, version: str) -> None:
|
||||||
"""
|
"""
|
||||||
@ -160,11 +162,11 @@ def download_series(select_season: MediaItem, version: str) -> None:
|
|||||||
if len(list_season_select) > 1 or index_season_selected == "*":
|
if len(list_season_select) > 1 or index_season_selected == "*":
|
||||||
|
|
||||||
# Download all episodes if multiple seasons are selected or if '*' is used
|
# Download all episodes if multiple seasons are selected or if '*' is used
|
||||||
download_episode(select_season.slug, i_season, scrape_serie, video_source, download_all=True)
|
download_episode(i_season, scrape_serie, video_source, download_all=True)
|
||||||
else:
|
else:
|
||||||
|
|
||||||
# Otherwise, let the user select specific episodes for the single season
|
# Otherwise, let the user select specific episodes for the single season
|
||||||
download_episode(select_season.slug, i_season, scrape_serie, video_source, download_all=False)
|
download_episode(i_season, scrape_serie, video_source, download_all=False)
|
||||||
|
|
||||||
|
|
||||||
def display_episodes_list(scrape_serie) -> str:
|
def display_episodes_list(scrape_serie) -> str:
|
||||||
|
@ -101,6 +101,9 @@ def title_search(title_search: str, domain: str) -> int:
|
|||||||
Returns:
|
Returns:
|
||||||
int: The number of titles found.
|
int: The number of titles found.
|
||||||
"""
|
"""
|
||||||
|
media_search_manager.clear()
|
||||||
|
table_show_manager.clear()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
response = httpx.get(
|
response = httpx.get(
|
||||||
url=f"https://{SITE_NAME}.{domain}/api/search?q={title_search.replace(' ', '+')}",
|
url=f"https://{SITE_NAME}.{domain}/api/search?q={title_search.replace(' ', '+')}",
|
||||||
|
@ -826,11 +826,6 @@ class HLS_Downloader:
|
|||||||
Args:
|
Args:
|
||||||
out_path (str): The path of the output file to be cleaned up.
|
out_path (str): The path of the output file to be cleaned up.
|
||||||
"""
|
"""
|
||||||
def dict_to_seconds(d):
|
|
||||||
"""Converts a dictionary of time components to total seconds."""
|
|
||||||
if d is not None:
|
|
||||||
return d['h'] * 3600 + d['m'] * 60 + d['s']
|
|
||||||
return 0
|
|
||||||
|
|
||||||
# Check if the final output file exists
|
# Check if the final output file exists
|
||||||
logging.info(f"Check if end file converted exists: {out_path}")
|
logging.info(f"Check if end file converted exists: {out_path}")
|
||||||
@ -861,7 +856,8 @@ class HLS_Downloader:
|
|||||||
panel_content = (
|
panel_content = (
|
||||||
f"[bold green]Download completed![/bold green]\n"
|
f"[bold green]Download completed![/bold green]\n"
|
||||||
f"[cyan]File size: [bold red]{formatted_size}[/bold red]\n"
|
f"[cyan]File size: [bold red]{formatted_size}[/bold red]\n"
|
||||||
f"[cyan]Duration: [bold]{formatted_duration}[/bold]"
|
f"[cyan]Duration: [bold]{formatted_duration}[/bold]\n"
|
||||||
|
f"[cyan]Output: [bold]{self.output_filename}[/bold]"
|
||||||
)
|
)
|
||||||
|
|
||||||
if missing_ts:
|
if missing_ts:
|
||||||
|
@ -558,7 +558,7 @@ class M3U8_Segments:
|
|||||||
console.print(
|
console.print(
|
||||||
"[yellow]⚠ Warning:[/yellow] Too many retries detected! "
|
"[yellow]⚠ Warning:[/yellow] Too many retries detected! "
|
||||||
"Consider reducing the number of [cyan]workers[/cyan] in the [magenta]config.json[/magenta] file. "
|
"Consider reducing the number of [cyan]workers[/cyan] in the [magenta]config.json[/magenta] file. "
|
||||||
"This will impact [bold]performance[/bold]."
|
"This will impact [bold]performance[/bold]. \n"
|
||||||
)
|
)
|
||||||
|
|
||||||
# Info to return
|
# Info to return
|
||||||
|
@ -1,15 +1,18 @@
|
|||||||
# 23.06.24
|
# 23.06.24
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
import re
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
import shutil
|
import shutil
|
||||||
|
import psutil
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
|
||||||
# Internal utilities
|
# Internal utilities
|
||||||
from StreamingCommunity.Util.color import Colors
|
from StreamingCommunity.Util.color import Colors
|
||||||
from StreamingCommunity.Util.os import internet_manager
|
from StreamingCommunity.Util.os import internet_manager
|
||||||
|
from StreamingCommunity.Util.console import console
|
||||||
from StreamingCommunity.Util._jsonConfig import config_manager
|
from StreamingCommunity.Util._jsonConfig import config_manager
|
||||||
|
|
||||||
|
|
||||||
@ -42,16 +45,18 @@ class TOR_downloader:
|
|||||||
- username (str): Username for logging into qBittorrent.
|
- username (str): Username for logging into qBittorrent.
|
||||||
- password (str): Password for logging into qBittorrent.
|
- password (str): Password for logging into qBittorrent.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
|
console.print(f"[cyan]Connect to: [green]{HOST}:{PORT}")
|
||||||
self.qb = Client(f'http://{HOST}:{PORT}/')
|
self.qb = Client(f'http://{HOST}:{PORT}/')
|
||||||
except:
|
except:
|
||||||
logging.error("Start qbitorrent first.")
|
logging.error("Start qbitorrent first.")
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
self.username = USERNAME
|
self.username = USERNAME
|
||||||
self.password = PASSWORD
|
self.password = PASSWORD
|
||||||
self.logged_in = False
|
self.latest_torrent_hash = None
|
||||||
self.save_path = None
|
self.output_file = None
|
||||||
self.torrent_name = None
|
self.file_name = None
|
||||||
|
|
||||||
self.login()
|
self.login()
|
||||||
|
|
||||||
@ -68,155 +73,226 @@ class TOR_downloader:
|
|||||||
logging.error(f"Failed to log in: {str(e)}")
|
logging.error(f"Failed to log in: {str(e)}")
|
||||||
self.logged_in = False
|
self.logged_in = False
|
||||||
|
|
||||||
|
def delete_magnet(self, torrent_info):
|
||||||
|
|
||||||
|
if (int(torrent_info.get('dl_speed')) == 0 and
|
||||||
|
int(torrent_info.get('peers')) == 0 and
|
||||||
|
int(torrent_info.get('seeds')) == 0):
|
||||||
|
|
||||||
|
# Elimina il torrent appena aggiunto
|
||||||
|
console.print(f"[bold red]⚠️ Torrent non scaricabile. Rimozione in corso...[/bold red]")
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Rimuovi il torrent
|
||||||
|
self.qb.delete_permanently(torrent_info['hash'])
|
||||||
|
|
||||||
|
except Exception as delete_error:
|
||||||
|
logging.error(f"Errore durante la rimozione del torrent: {delete_error}")
|
||||||
|
|
||||||
|
# Resetta l'ultimo hash
|
||||||
|
self.latest_torrent_hash = None
|
||||||
|
|
||||||
def add_magnet_link(self, magnet_link):
|
def add_magnet_link(self, magnet_link):
|
||||||
"""
|
"""
|
||||||
Adds a torrent via magnet link to qBittorrent.
|
Aggiunge un magnet link e recupera le informazioni dettagliate.
|
||||||
|
|
||||||
Parameters:
|
Args:
|
||||||
- magnet_link (str): Magnet link of the torrent to be added.
|
magnet_link (str): Magnet link da aggiungere
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: Informazioni del torrent aggiunto, o None se fallisce
|
||||||
"""
|
"""
|
||||||
try:
|
|
||||||
self.qb.download_from_link(magnet_link)
|
|
||||||
logging.info("Added magnet link to qBittorrent.")
|
|
||||||
|
|
||||||
# Get the hash of the latest added torrent
|
# Estrai l'hash dal magnet link
|
||||||
torrents = self.qb.torrents()
|
magnet_hash_match = re.search(r'urn:btih:([0-9a-fA-F]+)', magnet_link)
|
||||||
if torrents:
|
|
||||||
self.latest_torrent_hash = torrents[-1]['hash']
|
if not magnet_hash_match:
|
||||||
logging.info(f"Latest torrent hash: {self.latest_torrent_hash}")
|
raise ValueError("Hash del magnet link non trovato")
|
||||||
|
|
||||||
|
magnet_hash = magnet_hash_match.group(1).lower()
|
||||||
|
|
||||||
|
# Estrai il nome del file dal magnet link (se presente)
|
||||||
|
name_match = re.search(r'dn=([^&]+)', magnet_link)
|
||||||
|
torrent_name = name_match.group(1).replace('+', ' ') if name_match else "Nome non disponibile"
|
||||||
|
|
||||||
|
# Salva il timestamp prima di aggiungere il torrent
|
||||||
|
before_add_time = time.time()
|
||||||
|
|
||||||
|
# Aggiungi il magnet link
|
||||||
|
console.print(f"[cyan]Aggiunta magnet link[/cyan]: [red]{magnet_link}")
|
||||||
|
self.qb.download_from_link(magnet_link)
|
||||||
|
|
||||||
|
# Aspetta un attimo per essere sicuri che il torrent sia stato aggiunto
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
# Cerca il torrent
|
||||||
|
torrents = self.qb.torrents()
|
||||||
|
matching_torrents = [
|
||||||
|
t for t in torrents
|
||||||
|
if (t['hash'].lower() == magnet_hash) or (t.get('added_on', 0) > before_add_time)
|
||||||
|
]
|
||||||
|
|
||||||
|
if not matching_torrents:
|
||||||
|
raise ValueError("Nessun torrent corrispondente trovato")
|
||||||
|
|
||||||
|
# Prendi il primo torrent corrispondente
|
||||||
|
torrent_info = matching_torrents[0]
|
||||||
|
|
||||||
|
# Formatta e stampa le informazioni
|
||||||
|
console.print("\n[bold green]🔗 Dettagli Torrent Aggiunto:[/bold green]")
|
||||||
|
console.print(f"[yellow]Nome:[/yellow] {torrent_info.get('name', torrent_name)}")
|
||||||
|
console.print(f"[yellow]Hash:[/yellow] {torrent_info['hash']}")
|
||||||
|
console.print(f"[yellow]Dimensione:[/yellow] {torrent_info.get('size', 'Non disponibile'):,} bytes")
|
||||||
|
console.print(f"[yellow]Stato:[/yellow] {torrent_info.get('state', 'Sconosciuto')}")
|
||||||
|
print()
|
||||||
|
|
||||||
except Exception as e:
|
# Salva l'hash per usi successivi e il path
|
||||||
logging.error(f"Failed to add magnet link: {str(e)}")
|
self.latest_torrent_hash = torrent_info['hash']
|
||||||
|
self.output_file = torrent_info['content_path']
|
||||||
|
self.file_name = torrent_info['name']
|
||||||
|
|
||||||
|
# Controlla che sia possibile il download
|
||||||
|
time.sleep(5)
|
||||||
|
self.delete_magnet(self.qb.get_torrent(self.latest_torrent_hash))
|
||||||
|
|
||||||
|
return torrent_info
|
||||||
|
|
||||||
def start_download(self):
|
def start_download(self):
|
||||||
"""
|
"""
|
||||||
Starts downloading the latest added torrent and monitors progress.
|
Starts downloading the latest added torrent and monitors progress.
|
||||||
"""
|
"""
|
||||||
try:
|
if self.latest_torrent_hash is not None:
|
||||||
|
try:
|
||||||
|
|
||||||
torrents = self.qb.torrents()
|
# Custom bar for mobile and pc
|
||||||
if not torrents:
|
if TQDM_USE_LARGE_BAR:
|
||||||
logging.error("No torrents found.")
|
bar_format = (
|
||||||
return
|
f"{Colors.YELLOW}[TOR] {Colors.WHITE}({Colors.CYAN}video{Colors.WHITE}): "
|
||||||
|
f"{Colors.RED}{{percentage:.2f}}% {Colors.MAGENTA}{{bar}} {Colors.WHITE}[ "
|
||||||
# Sleep to load magnet to qbit app
|
f"{Colors.YELLOW}{{elapsed}} {Colors.WHITE}< {Colors.CYAN}{{remaining}}{{postfix}} {Colors.WHITE}]"
|
||||||
time.sleep(10)
|
)
|
||||||
latest_torrent = torrents[-1]
|
else:
|
||||||
torrent_hash = latest_torrent['hash']
|
bar_format = (
|
||||||
|
f"{Colors.YELLOW}Proc{Colors.WHITE}: "
|
||||||
|
f"{Colors.RED}{{percentage:.2f}}% {Colors.WHITE}| "
|
||||||
|
f"{Colors.CYAN}{{remaining}}{{postfix}} {Colors.WHITE}]"
|
||||||
|
)
|
||||||
|
|
||||||
# Custom bar for mobile and pc
|
progress_bar = tqdm(
|
||||||
if TQDM_USE_LARGE_BAR:
|
total=100,
|
||||||
bar_format = (
|
ascii='░▒█',
|
||||||
f"{Colors.YELLOW}[TOR] {Colors.WHITE}({Colors.CYAN}video{Colors.WHITE}): "
|
bar_format=bar_format,
|
||||||
f"{Colors.RED}{{percentage:.2f}}% {Colors.MAGENTA}{{bar}} {Colors.WHITE}[ "
|
unit_scale=True,
|
||||||
f"{Colors.YELLOW}{{elapsed}} {Colors.WHITE}< {Colors.CYAN}{{remaining}}{{postfix}} {Colors.WHITE}]"
|
unit_divisor=1024,
|
||||||
)
|
mininterval=0.05
|
||||||
else:
|
|
||||||
bar_format = (
|
|
||||||
f"{Colors.YELLOW}Proc{Colors.WHITE}: "
|
|
||||||
f"{Colors.RED}{{percentage:.2f}}% {Colors.WHITE}| "
|
|
||||||
f"{Colors.CYAN}{{remaining}}{{postfix}} {Colors.WHITE}]"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
progress_bar = tqdm(
|
with progress_bar as pbar:
|
||||||
total=100,
|
while True:
|
||||||
ascii='░▒█',
|
|
||||||
bar_format=bar_format,
|
|
||||||
unit_scale=True,
|
|
||||||
unit_divisor=1024,
|
|
||||||
mininterval=0.05
|
|
||||||
)
|
|
||||||
|
|
||||||
with progress_bar as pbar:
|
# Get variable from qtorrent
|
||||||
while True:
|
torrent_info = self.qb.get_torrent(self.latest_torrent_hash)
|
||||||
|
self.save_path = torrent_info['save_path']
|
||||||
|
self.torrent_name = torrent_info['name']
|
||||||
|
|
||||||
# Get variable from qtorrent
|
# Fetch important variable
|
||||||
torrent_info = self.qb.get_torrent(torrent_hash)
|
pieces_have = torrent_info['pieces_have']
|
||||||
self.save_path = torrent_info['save_path']
|
pieces_num = torrent_info['pieces_num']
|
||||||
self.torrent_name = torrent_info['name']
|
progress = (pieces_have / pieces_num) * 100 if pieces_num else 0
|
||||||
|
pbar.n = progress
|
||||||
|
|
||||||
# Fetch important variable
|
download_speed = torrent_info['dl_speed']
|
||||||
pieces_have = torrent_info['pieces_have']
|
total_size = torrent_info['total_size']
|
||||||
pieces_num = torrent_info['pieces_num']
|
downloaded_size = torrent_info['total_downloaded']
|
||||||
progress = (pieces_have / pieces_num) * 100 if pieces_num else 0
|
|
||||||
pbar.n = progress
|
|
||||||
|
|
||||||
download_speed = torrent_info['dl_speed']
|
# Format variable
|
||||||
total_size = torrent_info['total_size']
|
downloaded_size_str = internet_manager.format_file_size(downloaded_size)
|
||||||
downloaded_size = torrent_info['total_downloaded']
|
downloaded_size = downloaded_size_str.split(' ')[0]
|
||||||
|
|
||||||
# Format variable
|
total_size_str = internet_manager.format_file_size(total_size)
|
||||||
downloaded_size_str = internet_manager.format_file_size(downloaded_size)
|
total_size = total_size_str.split(' ')[0]
|
||||||
downloaded_size = downloaded_size_str.split(' ')[0]
|
total_size_unit = total_size_str.split(' ')[1]
|
||||||
|
|
||||||
total_size_str = internet_manager.format_file_size(total_size)
|
average_internet_str = internet_manager.format_transfer_speed(download_speed)
|
||||||
total_size = total_size_str.split(' ')[0]
|
average_internet = average_internet_str.split(' ')[0]
|
||||||
total_size_unit = total_size_str.split(' ')[1]
|
average_internet_unit = average_internet_str.split(' ')[1]
|
||||||
|
|
||||||
average_internet_str = internet_manager.format_transfer_speed(download_speed)
|
# Update the progress bar's postfix
|
||||||
average_internet = average_internet_str.split(' ')[0]
|
if TQDM_USE_LARGE_BAR:
|
||||||
average_internet_unit = average_internet_str.split(' ')[1]
|
pbar.set_postfix_str(
|
||||||
|
f"{Colors.WHITE}[ {Colors.GREEN}{downloaded_size} {Colors.WHITE}< {Colors.GREEN}{total_size} {Colors.RED}{total_size_unit} "
|
||||||
|
f"{Colors.WHITE}| {Colors.CYAN}{average_internet} {Colors.RED}{average_internet_unit}"
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
pbar.set_postfix_str(
|
||||||
|
f"{Colors.WHITE}[ {Colors.GREEN}{downloaded_size}{Colors.RED} {total_size} "
|
||||||
|
f"{Colors.WHITE}| {Colors.CYAN}{average_internet} {Colors.RED}{average_internet_unit}"
|
||||||
|
)
|
||||||
|
|
||||||
|
pbar.refresh()
|
||||||
|
time.sleep(0.2)
|
||||||
|
|
||||||
# Update the progress bar's postfix
|
# Break at the end
|
||||||
if TQDM_USE_LARGE_BAR:
|
if int(progress) == 100:
|
||||||
pbar.set_postfix_str(
|
break
|
||||||
f"{Colors.WHITE}[ {Colors.GREEN}{downloaded_size} {Colors.WHITE}< {Colors.GREEN}{total_size} {Colors.RED}{total_size_unit} "
|
|
||||||
f"{Colors.WHITE}| {Colors.CYAN}{average_internet} {Colors.RED}{average_internet_unit}"
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
pbar.set_postfix_str(
|
|
||||||
f"{Colors.WHITE}[ {Colors.GREEN}{downloaded_size}{Colors.RED} {total_size} "
|
|
||||||
f"{Colors.WHITE}| {Colors.CYAN}{average_internet} {Colors.RED}{average_internet_unit}"
|
|
||||||
)
|
|
||||||
|
|
||||||
pbar.refresh()
|
|
||||||
time.sleep(0.2)
|
|
||||||
|
|
||||||
# Break at the end
|
except KeyboardInterrupt:
|
||||||
if int(progress) == 100:
|
logging.info("Download process interrupted.")
|
||||||
break
|
|
||||||
|
|
||||||
except KeyboardInterrupt:
|
def is_file_in_use(self, file_path: str) -> bool:
|
||||||
logging.info("Download process interrupted.")
|
"""Check if a file is in use by any process."""
|
||||||
|
for proc in psutil.process_iter(['open_files']):
|
||||||
|
try:
|
||||||
|
if any(file_path == f.path for f in proc.info['open_files'] or []):
|
||||||
|
return True
|
||||||
|
except (psutil.NoSuchProcess, psutil.AccessDenied):
|
||||||
|
continue
|
||||||
|
|
||||||
except Exception as e:
|
return False
|
||||||
logging.error(f"Download error: {str(e)}")
|
|
||||||
sys.exit(0)
|
|
||||||
|
|
||||||
def move_downloaded_files(self, destination=None):
|
def move_downloaded_files(self, destination: str):
|
||||||
"""
|
"""
|
||||||
Moves downloaded files of the latest torrent to another location.
|
Moves downloaded files of the latest torrent to another location.
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
- save_path (str): Current save path (output directory) of the torrent.
|
- destination (str): Destination directory to move files.
|
||||||
- destination (str, optional): Destination directory to move files. If None, moves to current directory.
|
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
- bool: True if files are moved successfully, False otherwise.
|
- bool: True if files are moved successfully, False otherwise.
|
||||||
"""
|
"""
|
||||||
|
console.print(f"[cyan]Destination folder: [red]{destination}")
|
||||||
video_extensions = {'.mp4', '.mkv', 'avi'}
|
|
||||||
time.sleep(2)
|
|
||||||
|
|
||||||
# List directories in the save path
|
try:
|
||||||
dirs = [d for d in os.listdir(self.save_path) if os.path.isdir(os.path.join(self.save_path, d))]
|
|
||||||
|
|
||||||
for dir_name in dirs:
|
|
||||||
if self.torrent_name.split(" ")[0] in dir_name:
|
|
||||||
dir_path = os.path.join(self.save_path, dir_name)
|
|
||||||
|
|
||||||
# Ensure destination is set; if not, use current directory
|
# Ensure the file is not in use
|
||||||
destination = destination or os.getcwd()
|
timeout = 3
|
||||||
|
elapsed = 0
|
||||||
|
while self.is_file_in_use(self.output_file) and elapsed < timeout:
|
||||||
|
time.sleep(1)
|
||||||
|
elapsed += 1
|
||||||
|
|
||||||
|
if elapsed == timeout:
|
||||||
|
raise Exception(f"File '{self.output_file}' is in use and could not be moved.")
|
||||||
|
|
||||||
# Move only video files
|
# Ensure destination directory exists
|
||||||
for file_name in os.listdir(dir_path):
|
os.makedirs(destination, exist_ok=True)
|
||||||
file_path = os.path.join(dir_path, file_name)
|
|
||||||
|
|
||||||
# Check if it's a file and if it has a video extension
|
|
||||||
if os.path.isfile(file_path) and os.path.splitext(file_name)[1] in video_extensions:
|
|
||||||
shutil.move(file_path, os.path.join(destination, file_name))
|
|
||||||
logging.info(f"Moved file {file_name} to {destination}")
|
|
||||||
|
|
||||||
time.sleep(2)
|
# Perform the move operation
|
||||||
self.qb.delete_permanently(self.qb.torrents()[-1]['hash'])
|
try:
|
||||||
return True
|
shutil.move(self.output_file, destination)
|
||||||
|
|
||||||
|
except OSError as e:
|
||||||
|
if e.errno == 17: # Cross-disk move error
|
||||||
|
# Perform copy and delete manually
|
||||||
|
shutil.copy2(self.output_file, destination)
|
||||||
|
os.remove(self.output_file)
|
||||||
|
else:
|
||||||
|
raise
|
||||||
|
|
||||||
|
# Delete the torrent data
|
||||||
|
#self.qb.delete_permanently(self.qb.torrents()[-1]['hash'])
|
||||||
|
return True
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error moving file: {e}")
|
||||||
|
return False
|
@ -1,5 +1,5 @@
|
|||||||
__title__ = 'StreamingCommunity'
|
__title__ = 'StreamingCommunity'
|
||||||
__version__ = '1.9.2'
|
__version__ = '1.9.4'
|
||||||
__author__ = 'Lovi-0'
|
__author__ = 'Lovi-0'
|
||||||
__description__ = 'A command-line program to download film'
|
__description__ = 'A command-line program to download film'
|
||||||
__copyright__ = 'Copyright 2024'
|
__copyright__ = 'Copyright 2024'
|
||||||
|
@ -162,11 +162,8 @@ class TVShowManager:
|
|||||||
# Get the search function
|
# Get the search function
|
||||||
search_func = getattr(module, 'media_search_manager')
|
search_func = getattr(module, 'media_search_manager')
|
||||||
|
|
||||||
# Ask for search string
|
|
||||||
string_to_search = Prompt.ask(f"\n[purple]Insert word to search in [red]{research_func['folder_base']}").strip()
|
|
||||||
|
|
||||||
# Call the search function with the search string
|
# Call the search function with the search string
|
||||||
search_func(string_to_search)
|
search_func(None)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.console.print(f"[red]Error during search: {e}")
|
self.console.print(f"[red]Error during search: {e}")
|
||||||
@ -227,13 +224,10 @@ class TVShowManager:
|
|||||||
module = importlib.import_module(module_path)
|
module = importlib.import_module(module_path)
|
||||||
|
|
||||||
# Get the search function
|
# Get the search function
|
||||||
search_func = getattr(module, 'media_search_manager')
|
search_func = getattr(module, 'search')
|
||||||
|
|
||||||
# Ask for search string
|
|
||||||
string_to_search = Prompt.ask(f"\n[purple]Insert word to search in [red]{research_func['folder_base']}").strip()
|
|
||||||
|
|
||||||
# Call the search function with the search string
|
# Call the search function with the search string
|
||||||
search_func(string_to_search)
|
search_func(None)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.console.print(f"[red]Error during search: {e}")
|
self.console.print(f"[red]Error during search: {e}")
|
||||||
|
@ -120,11 +120,11 @@ def initialize():
|
|||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
# Attempting GitHub update
|
# Attempting GitHub update
|
||||||
try:
|
"""try:
|
||||||
git_update()
|
git_update()
|
||||||
print()
|
print()
|
||||||
except:
|
except:
|
||||||
console.log("[red]Error with loading github.")
|
console.log("[red]Error with loading github.")"""
|
||||||
|
|
||||||
# Show trending film and series
|
# Show trending film and series
|
||||||
if SHOW_TRENDING:
|
if SHOW_TRENDING:
|
||||||
|
@ -19,7 +19,7 @@ start_message()
|
|||||||
logger = Logger()
|
logger = Logger()
|
||||||
manager = TOR_downloader()
|
manager = TOR_downloader()
|
||||||
|
|
||||||
magnet_link = "magnet:?x"
|
magnet_link = "magnet:?xt="
|
||||||
manager.add_magnet_link(magnet_link)
|
manager.add_magnet_link(magnet_link)
|
||||||
manager.start_download()
|
manager.start_download()
|
||||||
manager.move_downloaded_files()
|
manager.move_downloaded_files()
|
||||||
|
11
config.json
11
config.json
@ -10,7 +10,7 @@
|
|||||||
"serie_folder_name": "TV",
|
"serie_folder_name": "TV",
|
||||||
"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.59",
|
"host": "192.168.1.58",
|
||||||
"port": "8080",
|
"port": "8080",
|
||||||
"user": "admin",
|
"user": "admin",
|
||||||
"pass": "adminadmin"
|
"pass": "adminadmin"
|
||||||
@ -85,16 +85,13 @@
|
|||||||
"domain": "to"
|
"domain": "to"
|
||||||
},
|
},
|
||||||
"cb01new": {
|
"cb01new": {
|
||||||
"domain": "club"
|
"domain": "icu"
|
||||||
},
|
|
||||||
"bitsearch": {
|
|
||||||
"domain": "to"
|
|
||||||
},
|
},
|
||||||
"1337xx": {
|
"1337xx": {
|
||||||
"domain": "to"
|
"domain": "to"
|
||||||
},
|
},
|
||||||
"piratebays": {
|
"ilcorsaronero": {
|
||||||
"domain": "to"
|
"domain": "link"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
2
setup.py
2
setup.py
@ -11,7 +11,7 @@ with open("requirements.txt", "r", encoding="utf-8-sig") as f:
|
|||||||
|
|
||||||
setup(
|
setup(
|
||||||
name="StreamingCommunity",
|
name="StreamingCommunity",
|
||||||
version="1.9.2",
|
version="1.9.4",
|
||||||
long_description=read_readme(),
|
long_description=read_readme(),
|
||||||
long_description_content_type="text/markdown",
|
long_description_content_type="text/markdown",
|
||||||
author="Lovi-0",
|
author="Lovi-0",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user