Skip to content

Commit 29a8305

Browse files
authored
Add force_resolution argument in the terminal.
* Add the force_resolution argument in the terminal. (#397) * Update README.md
1 parent fa88bac commit 29a8305

File tree

18 files changed

+90
-110
lines changed

18 files changed

+90
-110
lines changed

.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ __pycache__/
88
build/
99
develop-eggs/
1010
dist/
11-
downloads/
1211
eggs/
1312
.eggs/
1413
parts/

README.md

Lines changed: 37 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@
77
[![License](https://img.shields.io/github/license/Arrowar/StreamingCommunity?logo=gnu&logoColor=white&labelColor=2d3748&color=e53e3e&style=for-the-badge)](https://github.com/Arrowar/StreamingCommunity/blob/main/LICENSE)
88

99
## 💝 Support the Project
10-
[![Donate PayPal](https://img.shields.io/badge/💳_Donate-PayPal-00457C?style=for-the-badge&logo=paypal&logoColor=white&labelColor=2d3748)](https://www.paypal.com/donate/?hosted_button_id=UXTWMT8P6HE2C)
10+
<a href='https://ko-fi.com/E1E11LVC83' target='_blank'>
11+
<img height='36' style='border:0px;height:36px;' src='https://storage.ko-fi.com/cdn/kofi4.png?v=6' border='0' alt='Buy Me a Coffee at ko-fi.com' />
12+
</a>
1113

1214
## 🚀 Download & Install
1315
[![Windows](https://img.shields.io/badge/🪟_Windows-0078D4?style=for-the-badge&logo=windows&logoColor=white&labelColor=2d3748)](https://github.com/Arrowar/StreamingCommunity/releases/latest/download/StreamingCommunity_win.exe)
@@ -24,77 +26,62 @@
2426
---
2527

2628
## 📖 Table of Contents
27-
- [Installation](#manual-installation)
28-
- [Quick Start](#quick-start)
29-
- [Downloaders](#downloaders)
30-
- [Configuration](#configuration)
31-
- [Login](.github/.site/login.md)
32-
- [Usage Examples](#usage-examples)
33-
- [Global Search](#global-search)
34-
- [Advanced Features](#advanced-options)
35-
- [Deployment](#docker)
36-
- [Tutorials](#tutorials)
37-
- [Related Projects](#useful-project)
29+
- ⚙️ [Installation](#installation)
30+
- 🚀 [Quick Start](#quick-start)
31+
- 📥 [Downloaders](#downloaders)
32+
- 🛠️ [Configuration](#configuration)
33+
- 🔐 [Login](.github/.site/login.md)
34+
- 🌐 [Domain](https://arrowar.github.io/StreamingCommunity)
35+
- 💡 [Usage Examples](#usage-examples)
36+
- 🔍 [Global Search](#global-search)
37+
- 🧩 [Advanced Features](#advanced-options)
38+
- 🐳 [Deployment](#docker)
39+
- 🎓 [Tutorials](#tutorials)
40+
- 🔗 [Related Projects](#useful-project)
3841

3942
---
4043

41-
## Manual Installation
44+
## Installation
4245

43-
<summary>⚙️ Python Dependencies</summary>
46+
### Prerequisites
47+
Make sure you have Python installed on your system:
48+
- **Windows**: Download from [python.org](https://python.org) or install via Microsoft Store
49+
- **Linux**: `sudo apt install python3 python3-pip` (Ubuntu/Debian) or equivalent for your distro
50+
- **MacOS**: `brew install python3` or download from [python.org](https://python.org)
4451

45-
#### On Windows:
46-
47-
```powershell
52+
### Dependencies
53+
```bash
54+
# Windows
4855
pip install -r requirements.txt
49-
```
5056

51-
#### On Linux/MacOS:
52-
53-
```bash
57+
# Linux/MacOS
5458
pip3 install -r requirements.txt
55-
# or alternatively:
56-
python3 -m pip install -r requirements.txt
5759
```
5860

59-
<detail>
60-
<summary> Update </summary>
61-
62-
### On Windows:
63-
64-
```powershell
61+
### Update
62+
```bash
63+
# Windows
6564
python update.py
66-
```
6765

68-
### On Linux/MacOS:
69-
70-
```bash
66+
# Linux/MacOS
7167
python3 update.py
7268
```
7369

7470
---
7571

7672
## Quick Start
7773

78-
After installing via pip, just run:
74+
**Via pip installation:**
7975
```bash
8076
StreamingCommunity
8177
```
82-
to start the application.
83-
84-
Run the script:
85-
```bash
86-
python run_streaming.py
87-
```
8878

8979
**Manual execution:**
90-
91-
**Windows:**
92-
```powershell
80+
```bash
81+
# Windows
9382
python test_run.py
94-
```
9583

96-
**Linux/MacOS:**
97-
```bash
84+
# Linux/MacOS
9885
python3 test_run.py
9986
```
10087

@@ -117,7 +104,7 @@ downloader = HLS_Downloader(
117104
downloader.download()
118105
```
119106

120-
See [HLS example](./Test/EasyDownload//HLS.py) for complete usage.
107+
See [HLS example](./Test/Downloads//HLS.py) for complete usage.
121108

122109
<summary>📽️ MP4</summary>
123110

@@ -134,7 +121,7 @@ downloader = MP4_downloader(
134121
downloader.download()
135122
```
136123

137-
See [MP4 example](./Test/EasyDownload/MP4.py) for complete usage.
124+
See [MP4 example](./Test/Downloads/MP4.py) for complete usage.
138125

139126
<summary>🧲 TOR</summary>
140127

@@ -150,7 +137,7 @@ client.add_magnet_link("magnet:?xt=urn:btih:example_hash&dn=example_name", save_
150137
client.start_download()
151138
```
152139

153-
See [Torrent example](./Test/EasyDownload/TOR.py) for complete usage.
140+
See [Torrent example](./Test/Downloads/TOR.py) for complete usage.
154141

155142
<summary>🎞️ DASH</summary>
156143

@@ -172,7 +159,7 @@ if dash_process.download_and_decrypt():
172159
dash_process.get_status()
173160
```
174161

175-
See [DASH example](./Test/EasyDownload/DASH.py) for complete usage.
162+
See [DASH example](./Test/Downloads/DASH.py) for complete usage.
176163

177164
---
178165

StreamingCommunity/Api/Site/animeunity/serie.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ def download_episode(index_select: int, scrape_serie: ScrapeSerieAnime, video_so
4848

4949
# Get episode information
5050
obj_episode = scrape_serie.selectEpisode(1, index_select)
51-
console.print(f"[bold yellow]Download:[/bold yellow] [red]{site_constant.SITE_NAME}[/red] ([cyan]E{obj_episode.number}[/cyan]) \n")
51+
console.print(f"[bold yellow]Download:[/bold yellow] [red]{site_constant.SITE_NAME}[/red] → [cyan]{scrape_serie.series_name}[/cyan] ([cyan]E{obj_episode.number}[/cyan]) \n")
5252

5353
if site_constant.TELEGRAM_BOT:
5454
bot = get_bot_instance()

StreamingCommunity/Api/Site/animeworld/serie.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ def download_episode(index_select: int, scrape_serie: ScrapSerie) -> Tuple[str,b
4747

4848
# Get episode information
4949
episode_data = scrape_serie.selectEpisode(1, index_select)
50-
console.print(f"[bold yellow]Download:[/bold yellow] [red]{site_constant.SITE_NAME}[/red] ([cyan]E{index_select+1}[/cyan]) \n")
50+
console.print(f"[bold yellow]Download:[/bold yellow] [red]{site_constant.SITE_NAME}[/red] → [cyan]{scrape_serie.get_name()}[/cyan] ([cyan]E{str(index_select+1)}[/cyan]) \n")
5151

5252
# Define filename and path for the downloaded video
5353
mp4_name = f"{scrape_serie.get_name()}_EP_{dynamic_format_number(str(index_select+1))}.mp4"

StreamingCommunity/Api/Site/crunchyroll/series.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@ def download_video(index_season_selected: int, index_episode_selected: int, scra
5555

5656
# Get episode information
5757
obj_episode = scrape_serie.selectEpisode(index_season_selected, index_episode_selected-1)
58-
console.print(f"[bold yellow]Download:[/bold yellow] [red]{site_constant.SITE_NAME}[/red] → [bold magenta]{obj_episode.get('name')}[/bold magenta] ([cyan]S{index_season_selected}E{index_episode_selected}[/cyan]) \n")
58+
59+
console.print(f"[bold yellow]Download:[/bold yellow] [red]{site_constant.SITE_NAME}[/red] → [cyan]{scrape_serie.series_name}[/cyan] \\ [bold magenta]{obj_episode.get('name')}[/bold magenta] ([cyan]S{index_season_selected}E{index_episode_selected}[/cyan]) \n")
5960

6061
# Define filename and path for the downloaded video
6162
mp4_name = f"{map_episode_title(scrape_serie.series_name, index_season_selected, index_episode_selected, obj_episode.get('name'))}.mp4"

StreamingCommunity/Api/Site/raiplay/series.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ def download_video(index_season_selected: int, index_episode_selected: int, scra
5858

5959
# Get episode information
6060
obj_episode = scrape_serie.selectEpisode(index_season_selected, index_episode_selected-1)
61-
console.print(f"[bold yellow]Download:[/bold yellow] [red]{site_constant.SITE_NAME}[/red] → [bold magenta]{obj_episode.name}[/bold magenta] ([cyan]S{index_season_selected}E{index_episode_selected}[/cyan]) \n")
61+
console.print(f"[bold yellow]Download:[/bold yellow] [red]{site_constant.SITE_NAME}[/red] → [cyan]{scrape_serie.series_name}[/cyan] \\ [bold magenta]{obj_episode.name}[/bold magenta] ([cyan]S{index_season_selected}E{index_episode_selected}[/cyan]) \n")
6262

6363
# Define filename and path
6464
mp4_name = f"{map_episode_title(scrape_serie.series_name, index_season_selected, index_episode_selected, obj_episode.name)}.mp4"

StreamingCommunity/Lib/Downloader/HLS/segments.py

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -287,11 +287,7 @@ def download_segment(self, ts_url: str, index: int, progress_bar: tqdm, backoff_
287287
progress_bar.update(1)
288288
return
289289

290-
except Exception as e:
291-
error_msg = str(e)
292-
293-
if attempt == 0:
294-
logging.warning(f"Segment {index} failed on first attempt: {error_msg}")
290+
except Exception:
295291

296292
if attempt > self.info_maxRetry:
297293
self.info_maxRetry = attempt + 1

StreamingCommunity/Lib/FFmpeg/capture.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ def capture_output(process: subprocess.Popen, description: str) -> None:
5757

5858

5959
# Construct the progress string with formatted output information
60-
progress_string = (f" {description}[white]: "
60+
progress_string = (f"{description}[white]: "
6161
f"([green]'speed': [yellow]{data.get('speed', 'N/A')}[white], "
6262
f"[green]'size': [yellow]{internet_manager.format_file_size(byte_size)}[white])")
6363
max_length = max(max_length, len(progress_string))

StreamingCommunity/Lib/FFmpeg/command.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -164,13 +164,13 @@ def join_video(video_path: str, out_path: str, codec: M3U8_Codec = None):
164164
else:
165165

166166
if get_use_large_bar():
167-
capture_ffmpeg_real_time(ffmpeg_cmd, "[cyan]Join video")
167+
capture_ffmpeg_real_time(ffmpeg_cmd, "[yellow][FFMPEG] [cyan]Join video")
168168
print()
169169

170170
else:
171171
console.log("[purple]FFmpeg [white][[cyan]Join video[white]] ...")
172172
with suppress_output():
173-
capture_ffmpeg_real_time(ffmpeg_cmd, "[cyan]Join video")
173+
capture_ffmpeg_real_time(ffmpeg_cmd, "[yellow][FFMPEG] [cyan]Join video")
174174
print()
175175

176176
return out_path
@@ -299,13 +299,13 @@ def join_audios(video_path: str, audio_tracks: List[Dict[str, str]], out_path: s
299299

300300
else:
301301
if get_use_large_bar():
302-
capture_ffmpeg_real_time(ffmpeg_cmd, "[cyan]Join audio")
302+
capture_ffmpeg_real_time(ffmpeg_cmd, "[yellow][FFMPEG] [cyan]Join audio")
303303
print()
304304

305305
else:
306306
console.log("[purple]FFmpeg [white][[cyan]Join audio[white]] ...")
307307
with suppress_output():
308-
capture_ffmpeg_real_time(ffmpeg_cmd, "[cyan]Join audio")
308+
capture_ffmpeg_real_time(ffmpeg_cmd, "[yellow][FFMPEG] [cyan]Join audio")
309309
print()
310310

311311
return out_path, use_shortest
@@ -366,13 +366,13 @@ def join_subtitle(video_path: str, subtitles_list: List[Dict[str, str]], out_pat
366366

367367
else:
368368
if get_use_large_bar():
369-
capture_ffmpeg_real_time(ffmpeg_cmd, "[cyan]Join subtitle")
369+
capture_ffmpeg_real_time(ffmpeg_cmd, "[yellow][FFMPEG] [cyan]Join subtitle")
370370
print()
371371

372372
else:
373373
console.log("[purple]FFmpeg [white][[cyan]Join subtitle[white]] ...")
374374
with suppress_output():
375-
capture_ffmpeg_real_time(ffmpeg_cmd, "[cyan]Join subtitle")
375+
capture_ffmpeg_real_time(ffmpeg_cmd, "[yellow][FFMPEG] [cyan]Join subtitle")
376376
print()
377377

378378
return out_path

StreamingCommunity/Lib/FFmpeg/util.py

Lines changed: 11 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,10 @@ def print_duration_table(file_path: str, description: str = "Duration", return_s
133133
def get_ffprobe_info(file_path):
134134
"""
135135
Get format and codec information for a media file using ffprobe.
136+
136137
Parameters:
137138
- file_path (str): Path to the media file.
139+
138140
Returns:
139141
dict: A dictionary containing the format name and a list of codec names.
140142
Returns None if file does not exist or ffprobe crashes.
@@ -143,25 +145,8 @@ def get_ffprobe_info(file_path):
143145
logging.error(f"File not found: {file_path}")
144146
return None
145147

146-
# Get ffprobe path and verify it exists
147-
ffprobe_path = get_ffprobe_path()
148-
if not ffprobe_path or not os.path.exists(ffprobe_path):
149-
logging.error(f"FFprobe not found at path: {ffprobe_path}")
150-
return None
151-
152-
# Verify file permissions
153-
try:
154-
file_stat = os.stat(file_path)
155-
logging.info(f"File permissions: {oct(file_stat.st_mode)}")
156-
if not os.access(file_path, os.R_OK):
157-
logging.error(f"No read permission for file: {file_path}")
158-
return None
159-
except OSError as e:
160-
logging.error(f"Cannot access file {file_path}: {e}")
161-
return None
162-
163148
try:
164-
cmd = [ffprobe_path, '-v', 'error', '-show_format', '-show_streams', '-print_format', 'json', file_path]
149+
cmd = [get_ffprobe_path(), '-v', 'error', '-show_format', '-show_streams', '-print_format', 'json', file_path]
165150
logging.info(f"Running FFprobe command: {' '.join(cmd)}")
166151

167152
# Use subprocess.run instead of Popen for better error handling
@@ -177,20 +162,15 @@ def get_ffprobe_info(file_path):
177162
logging.error(f"FFprobe stderr: {result.stderr}")
178163
logging.error(f"FFprobe stdout: {result.stdout}")
179164
logging.error(f"Command: {' '.join(cmd)}")
180-
logging.error(f"FFprobe path permissions: {oct(os.stat(ffprobe_path).st_mode)}")
181165
return None
182166

183167
# Parse JSON output
184-
try:
185-
info = json.loads(result.stdout)
186-
return {
187-
'format_name': info.get('format', {}).get('format_name'),
188-
'codec_names': [stream.get('codec_name') for stream in info.get('streams', [])]
189-
}
190-
except json.JSONDecodeError as e:
191-
logging.error(f"Failed to parse FFprobe output: {e}")
192-
return None
193-
168+
info = json.loads(result.stdout)
169+
return {
170+
'format_name': info.get('format', {}).get('format_name'),
171+
'codec_names': [stream.get('codec_name') for stream in info.get('streams', [])]
172+
}
173+
194174
except Exception as e:
195175
logging.error(f"FFprobe execution failed: {e}")
196176
return None
@@ -223,11 +203,12 @@ def need_to_force_to_ts(file_path):
223203
Parameters:
224204
- file_path (str): Path to the input media file.
225205
"""
226-
logging.info(f"Processing file: {file_path}")
227206
file_info = get_ffprobe_info(file_path)
228207

229208
if is_png_format_or_codec(file_info):
209+
console.print(f"[yellow]Warning: The input file [green]{os.path.basename(file_path)}[/green] is in PNG format or contains a PNG codec. It will be converted to TS format for processing.[/yellow]")
230210
return True
211+
231212
return False
232213

233214

0 commit comments

Comments
 (0)