Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 12 additions & 12 deletions .github/.domain/domains.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
{
"cb01new": {
"domain": "site",
"full_url": "https://cb01net.site/",
"old_domain": "xyz",
"time_change": "2025-10-06 15:20:32"
"domain": "bond",
"full_url": "https://cb01net.bond/",
"old_domain": "site",
"time_change": "2025-10-13 19:15:23"
},
"animeunity": {
"domain": "so",
Expand All @@ -18,10 +18,10 @@
"time_change": "2025-03-21 12:20:27"
},
"guardaserie": {
"domain": "one",
"full_url": "https://guardaserietv.one/",
"old_domain": "help",
"time_change": "2025-10-06 17:18:02"
"domain": "uno",
"full_url": "https://guardaserietv.uno/",
"old_domain": "one",
"time_change": "2025-10-13 19:15:26"
},
"streamingwatch": {
"domain": "org",
Expand All @@ -36,10 +36,10 @@
"time_change": "2025-09-06 18:24:29"
},
"streamingcommunity": {
"domain": "me",
"full_url": "https://streamingcommunityz.me/",
"old_domain": "li",
"time_change": "2025-10-06 13:30:00"
"domain": "it",
"full_url": "https://streamingcommunityz.it/",
"old_domain": "me",
"time_change": "2025-10-13 13:30:51"
},
"altadefinizionegratis": {
"domain": "ist",
Expand Down
54 changes: 54 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -538,6 +538,60 @@ make LOCAL_DIR=/path/to/download run-container

The `run-container` command mounts also the `config.json` file, so any change to the configuration file is reflected immediately without having to rebuild the image.

# Docker Compose

Code for Docker Compose:

```
stdownload:
container_name: stdownload
environment:
- NVIDIA_VISIBLE_DEVICES=void
- TZ=America/Chicago
group_add:
- '568' ##permissions for writing files
image: ghcr.io/arrowar/streamingcommunity:latest
platform: linux/amd64
privileged: False
restart: 'no'
stdin_open: False
tty: False
volumes:
- /mnt/qualcosa/st:/app
- /mnt/qualcosa/st/video:/app/video
volumes: {}
```

🛠️ Fix folder issue
After running Docker Compose, you need to do something a little strange. You need to enter the folder from outside the Docker shell (for example, with FTP or, personally, I use FileBrowser). Once inside the Docker folder, you need to delete all the files inside except for the video folder.
Then clone the repository on your PC and upload the files to the Docker folder.

🛠️ Run the container
Return to the Docker shell and ensure that Python is installed. To verify, use this command:

```
python --version
```

If Python is not installed, you can install it using the following command:

```
sudo apt install python3 python3-pip
```

If everything is ok, you can run the intallation script for dependencies:

```
pip3 install -r requirements.txt
```

At the end of the installation, you can run the test_run.py script to test the installation using this command:

```
python3 test_run.py
```

For the webui work in progress (:

# Telegram Usage

Expand Down
5 changes: 3 additions & 2 deletions StreamingCommunity/Api/Site/altadefinizione/film.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
# Variable
console = Console()
max_timeout = config_manager.get_int("REQUESTS", "timeout")
extension_output = config_manager.get("M3U8_CONVERSION", "extension")


def download_film(select_title: MediaItem) -> str:
Expand Down Expand Up @@ -92,8 +93,8 @@ def download_film(select_title: MediaItem) -> str:
master_playlist = video_source.get_playlist()

# Define the filename and path for the downloaded film
title_name = os_manager.get_sanitize_file(select_title.name) + ".mp4"
mp4_path = os.path.join(site_constant.MOVIE_FOLDER, title_name.replace(".mp4", ""))
title_name = os_manager.get_sanitize_file(select_title.name) + extension_output
mp4_path = os.path.join(site_constant.MOVIE_FOLDER, title_name.replace(extension_output, ""))

# Download the film using the m3u8 playlist, and output filename
hls_process = HLS_Downloader(
Expand Down
5 changes: 3 additions & 2 deletions StreamingCommunity/Api/Site/crunchyroll/film.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
# Variable
console = Console()
max_timeout = config_manager.get_int("REQUESTS", "timeout")
extension_output = config_manager.get("M3U8_CONVERSION", "extension")


def download_film(select_title: MediaItem) -> str:
Expand All @@ -49,8 +50,8 @@ def download_film(select_title: MediaItem) -> str:
return None, True

# Define filename and path for the downloaded video
mp4_name = os_manager.get_sanitize_file(select_title.name) + ".mp4"
mp4_path = os.path.join(site_constant.MOVIE_FOLDER, mp4_name.replace(".mp4", ""))
mp4_name = os_manager.get_sanitize_file(select_title.name) + extension_output
mp4_path = os.path.join(site_constant.MOVIE_FOLDER, mp4_name.replace(extension_output, ""))

# Generate mpd and license URLs
url_id = select_title.get('url').split('/')[-1]
Expand Down
14 changes: 8 additions & 6 deletions StreamingCommunity/Api/Site/mediasetinfinity/film.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@


# Internal utilities
from StreamingCommunity.Util.config_json import config_manager
from StreamingCommunity.Util.os import os_manager, get_wvd_path
from StreamingCommunity.Util.message import start_message
from StreamingCommunity.Util.headers import get_headers
Expand All @@ -27,6 +28,7 @@

# Variable
console = Console()
extension_output = config_manager.get("M3U8_CONVERSION", "extension")


def download_film(select_title: MediaItem) -> Tuple[str, bool]:
Expand All @@ -43,17 +45,17 @@ def download_film(select_title: MediaItem) -> Tuple[str, bool]:
console.print(f"\n[bold yellow]Download:[/bold yellow] [red]{site_constant.SITE_NAME}[/red] → [cyan]{select_title.name}[/cyan] \n")

# Define the filename and path for the downloaded film
title_name = os_manager.get_sanitize_file(select_title.name) + ".mp4"
mp4_path = os.path.join(site_constant.MOVIE_FOLDER, title_name.replace(".mp4", ""))
title_name = os_manager.get_sanitize_file(select_title.name) + extension_output
mp4_path = os.path.join(site_constant.MOVIE_FOLDER, title_name.replace(extension_output, ""))

# Generate mpd and license URLs
bearer = get_bearer_token()

playback_json = get_playback_url(bearer, select_title.id)
tracking_info = get_tracking_info(bearer, playback_json)[0]
playback_json = get_playback_url(select_title.id)
tracking_info = get_tracking_info(playback_json)['videos'][0]

license_url = generate_license_url(bearer, tracking_info)
mpd_url = get_manifest(tracking_info['video_src'])
license_url = generate_license_url(tracking_info)
mpd_url = get_manifest(tracking_info['url'])

# Download the episode
dash_process = DASH_Downloader(
Expand Down
9 changes: 5 additions & 4 deletions StreamingCommunity/Api/Site/raiplay/film.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@

# Internal utilities
from StreamingCommunity.Util.os import os_manager
from StreamingCommunity.Util.config_json import config_manager
from StreamingCommunity.Util.headers import get_headers
from StreamingCommunity.Util.os import get_wvd_path
from StreamingCommunity.Util.message import start_message

from StreamingCommunity.Util.os import get_wvd_path

# Logic class
from .util.get_license import generate_license_url
Expand All @@ -29,6 +29,7 @@

# Variable
console = Console()
extension_output = config_manager.get("M3U8_CONVERSION", "extension")


def download_film(select_title: MediaItem) -> Tuple[str, bool]:
Expand All @@ -51,8 +52,8 @@ def download_film(select_title: MediaItem) -> Tuple[str, bool]:
master_playlist = VideoSource.extract_m3u8_url(first_item_path)

# Define the filename and path for the downloaded film
mp4_name = os_manager.get_sanitize_file(select_title.name) + ".mp4"
mp4_path = os.path.join(site_constant.MOVIE_FOLDER, mp4_name.replace(".mp4", ""))
mp4_name = os_manager.get_sanitize_file(select_title.name) + extension_output
mp4_path = os.path.join(site_constant.MOVIE_FOLDER, mp4_name.replace(extension_output, ""))

# HLS
if ".mpd" not in master_playlist:
Expand Down
6 changes: 4 additions & 2 deletions StreamingCommunity/Api/Site/streamingcommunity/film.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

# Internal utilities
from StreamingCommunity.Util.os import os_manager
from StreamingCommunity.Util.config_json import config_manager
from StreamingCommunity.Util.message import start_message
from StreamingCommunity.TelegramHelp.telegram_bot import TelegramSession, get_bot_instance

Expand All @@ -25,6 +26,7 @@

# Variable
console = Console()
extension_output = config_manager.get("M3U8_CONVERSION", "extension")


def download_film(select_title: MediaItem) -> str:
Expand Down Expand Up @@ -67,8 +69,8 @@ def download_film(select_title: MediaItem) -> str:
return None

# Define the filename and path for the downloaded film
title_name = os_manager.get_sanitize_file(select_title.name) + ".mp4"
mp4_path = os.path.join(site_constant.MOVIE_FOLDER, title_name.replace(".mp4", ""))
title_name = os_manager.get_sanitize_file(select_title.name) + extension_output
mp4_path = os.path.join(site_constant.MOVIE_FOLDER, title_name.replace(extension_output, ""))

# Download the film using the m3u8 playlist, and output filename
hls_process = HLS_Downloader(
Expand Down
6 changes: 4 additions & 2 deletions StreamingCommunity/Api/Site/streamingwatch/film.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

# Internal utilities
from StreamingCommunity.Util.os import os_manager
from StreamingCommunity.Util.config_json import config_manager
from StreamingCommunity.Util.message import start_message


Expand All @@ -24,6 +25,7 @@

# Variable
console = Console()
extension_output = config_manager.get("M3U8_CONVERSION", "extension")


def download_film(select_title: MediaItem) -> str:
Expand All @@ -45,8 +47,8 @@ def download_film(select_title: MediaItem) -> str:
master_playlist = video_source.get_m3u8_url(select_title.url)

# Define the filename and path for the downloaded film
title_name = os_manager.get_sanitize_file(select_title.name) + ".mp4"
mp4_path = os.path.join(site_constant.MOVIE_FOLDER, title_name.replace(".mp4", ""))
title_name = os_manager.get_sanitize_file(select_title.name) + extension_output
mp4_path = os.path.join(site_constant.MOVIE_FOLDER, title_name.replace(extension_output, ""))

# Download the film using the m3u8 playlist, and output filename
hls_process = HLS_Downloader(
Expand Down
55 changes: 54 additions & 1 deletion StreamingCommunity/Lib/Downloader/DASH/decrypt.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,30 @@
import os
import subprocess
import logging
import threading
import time


# External libraries
from rich.console import Console
from tqdm import tqdm


# Internal utilities
from StreamingCommunity.Util.os import get_mp4decrypt_path
from StreamingCommunity.Util.color import Colors

# Variable
console = Console()


# NOTE!: SAREBBE MEGLIO FARLO PER OGNI FILE DURANTE IL DOWNLOAD ... MA PER ORA LO LASCIO COSI
def decrypt_with_mp4decrypt(encrypted_path, kid, key, output_path=None, cleanup=True):
def decrypt_with_mp4decrypt(type, encrypted_path, kid, key, output_path=None, cleanup=True):
"""
Decrypt an mp4/m4s file using mp4decrypt.

Args:
type (str): Type of file ('video' or 'audio').
encrypted_path (str): Path to encrypted file.
kid (str): Hexadecimal KID.
key (str): Hexadecimal key.
Expand All @@ -48,15 +53,63 @@ def decrypt_with_mp4decrypt(encrypted_path, kid, key, output_path=None, cleanup=
if not output_path:
output_path = os.path.splitext(encrypted_path)[0] + "_decrypted.mp4"

# Get file size for progress tracking
file_size = os.path.getsize(encrypted_path)

key_format = f"{kid.lower()}:{key.lower()}"
cmd = [get_mp4decrypt_path(), "--key", key_format, encrypted_path, output_path]
logging.info(f"Running command: {' '.join(cmd)}")

# Create progress bar with custom format
bar_format = (
f"{Colors.YELLOW}DECRYPT{Colors.CYAN} {type}{Colors.WHITE}: "
f"{Colors.MAGENTA}{{bar:40}} "
f"{Colors.LIGHT_GREEN}{{n_fmt}}{Colors.WHITE}/{Colors.CYAN}{{total_fmt}} "
f"{Colors.DARK_GRAY}[{Colors.YELLOW}{{elapsed}}{Colors.WHITE} < {Colors.CYAN}{{remaining}}{Colors.DARK_GRAY}] "
f"{Colors.WHITE}{{postfix}}"
)

progress_bar = tqdm(
total=100,
bar_format=bar_format,
unit="",
ncols=150
)

def monitor_output_file():
"""Monitor output file growth and update progress bar."""
last_size = 0
while True:
if os.path.exists(output_path):
current_size = os.path.getsize(output_path)
if current_size > 0:
progress_percent = min(int((current_size / file_size) * 100), 100)
progress_bar.n = progress_percent
progress_bar.refresh()

if current_size == last_size and current_size > 0:
# File stopped growing, likely finished
break

last_size = current_size

time.sleep(0.1)

# Start monitoring thread
monitor_thread = threading.Thread(target=monitor_output_file, daemon=True)
monitor_thread.start()

try:
result = subprocess.run(cmd, capture_output=True, text=True, timeout=300)
except Exception as e:
progress_bar.close()
console.print(f"[bold red] mp4decrypt execution failed: {e}[/bold red]")
return None

# Ensure progress bar reaches 100%
progress_bar.n = 100
progress_bar.refresh()
progress_bar.close()

if result.returncode == 0 and os.path.exists(output_path):

Expand Down
Loading