mirror of
https://github.com/Arrowar/StreamingCommunity.git
synced 2025-06-06 11:35:29 +00:00
fix download audio
This commit is contained in:
parent
af55408c8a
commit
fbfaeb5cac
@ -11,26 +11,32 @@ Script to download film from streaming community without selenium, select movie
|
||||
</p>
|
||||
|
||||
## Requirement
|
||||
|
||||
* python [3.9](https://www.python.org/downloads/release/python-390/)
|
||||
* ffmpeg [win](https://www.gyan.dev/ffmpeg/builds/)
|
||||
|
||||
## Installation library
|
||||
|
||||
```bash
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
## Run
|
||||
|
||||
```bash
|
||||
python run.py
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
- Search for movies.
|
||||
- Search and download TV series episode.
|
||||
- Add audio if missing.
|
||||
- Auto add audio if missing
|
||||
|
||||
## Tutorial
|
||||
|
||||
https://www.youtube.com/watch?v=Ok7hQCgxqLg&ab_channel=Nothing
|
||||
|
||||
## Authors
|
||||
|
||||
- [@Ghost6446](https://www.github.com/Ghost6446)
|
||||
|
@ -4,7 +4,7 @@
|
||||
from Stream.util.headers import get_headers
|
||||
from Stream.util.console import console, msg
|
||||
from Stream.util.m3u8 import dw_m3u8, join_audio_to_video
|
||||
from Stream.util.util import convert_utf8_name, check_audio_presence
|
||||
from Stream.util.util import convert_utf8_name
|
||||
|
||||
# General import
|
||||
import requests, os, re, json
|
||||
@ -96,20 +96,13 @@ def main_dw_tv(tv_id, tv_name, version, domain):
|
||||
m3u8_url = get_m3u8_url(json_win_video, json_win_param)
|
||||
m3u8_key = get_m3u8_key_ep(json_win_video, json_win_param, tv_name, season_select, index_ep_select+1, eps[index_ep_select]['name'])
|
||||
|
||||
mp4_name = lower_tv_name.replace("+", "_") + "_"+str(season_select)+"__"+str(index_ep_select+1)
|
||||
mp4_name = f"{lower_tv_name.replace('+', '_')}_{str(season_select)}_{str(index_ep_select+1)}"
|
||||
mp4_format = mp4_name + ".mp4"
|
||||
base_path_mp4 = os.path.join("videos", mp4_format)
|
||||
base_audio_path = os.path.join("videos", mp4_format + "_audio.mp4")
|
||||
mp4_path = os.path.join("videos", mp4_format)
|
||||
|
||||
dw_m3u8(m3u8_url, m3u8_key, base_path_mp4)
|
||||
m3u8_url_audio = get_m3u8_audio(json_win_video, json_win_param, tv_name, season_select, index_ep_select+1, eps[index_ep_select]['name'])
|
||||
|
||||
if not check_audio_presence(base_path_mp4):
|
||||
|
||||
console.print("[red]Audio is not present, start download (Use all CPU)")
|
||||
m3u8_url_audio = get_m3u8_audio(json_win_video, json_win_param, tv_name, season_select, index_ep_select+1, eps[index_ep_select]['name'])
|
||||
if m3u8_url_audio != None:
|
||||
console.print("[red]=> Use m3u8 audio")
|
||||
|
||||
dw_m3u8(m3u8_url_audio, m3u8_key, base_audio_path)
|
||||
|
||||
join_audio_to_video(base_audio_path, base_path_mp4, base_audio_path)
|
||||
os.remove(base_audio_path)
|
||||
os.remove(base_path_mp4)
|
||||
dw_m3u8(m3u8_url, m3u8_url_audio, m3u8_key, mp4_path)
|
||||
|
@ -1,5 +1,5 @@
|
||||
__title__ = 'Streaming_community'
|
||||
__version__ = 'v0.6.1'
|
||||
__version__ = 'v0.7.0'
|
||||
__author__ = 'Ghost6446'
|
||||
__description__ = 'A command-line program to download film'
|
||||
__license__ = 'MIT License'
|
||||
|
@ -11,6 +11,7 @@ import moviepy.editor as mp
|
||||
# Class import
|
||||
from Stream.util.console import console
|
||||
from Stream.util.headers import get_headers
|
||||
from Stream.util.util import there_is_audio, merge_ts_files
|
||||
|
||||
# Variable
|
||||
os.makedirs("videos", exist_ok=True)
|
||||
@ -19,17 +20,20 @@ os.makedirs("videos", exist_ok=True)
|
||||
# [ main class ]
|
||||
class M3U8Downloader:
|
||||
|
||||
def __init__(self, m3u8_url, key=None, output_filename="output.mp4"):
|
||||
def __init__(self, m3u8_url, m3u8_audio = None, key=None, output_filename="output.mp4"):
|
||||
self.m3u8_url = m3u8_url
|
||||
self.m3u8_audio = m3u8_audio
|
||||
self.key = key
|
||||
self.output_filename = output_filename
|
||||
|
||||
self.segments = []
|
||||
self.segments_audio = []
|
||||
self.iv = None
|
||||
self.key = bytes.fromhex(key)
|
||||
|
||||
self.temp_folder = "tmp"
|
||||
os.makedirs(self.temp_folder, exist_ok=True)
|
||||
self.download_audio = False
|
||||
|
||||
def decode_ext_x_key(self, key_str):
|
||||
key_str = key_str.replace('"', '').lstrip("#EXT-X-KEY:")
|
||||
@ -42,6 +46,9 @@ class M3U8Downloader:
|
||||
self.iv = bytes.fromhex(raw_iv.replace("0x", ""))
|
||||
|
||||
def parse_m3u8(self, m3u8_content):
|
||||
if self.m3u8_audio != None:
|
||||
m3u8_audio_line = str(requests.get(self.m3u8_audio).content).split("\\n")
|
||||
|
||||
m3u8_base_url = self.m3u8_url.rstrip(self.m3u8_url.split("/")[-1])
|
||||
lines = m3u8_content.split('\n')
|
||||
|
||||
@ -57,9 +64,11 @@ class M3U8Downloader:
|
||||
|
||||
if not ts_url.startswith("http"):
|
||||
ts_url = m3u8_base_url + ts_url
|
||||
self.segments.append(ts_url)
|
||||
|
||||
console.print(f"[cyan]Find: {len(self.segments)} ts file to download")
|
||||
self.segments.append(ts_url)
|
||||
if self.m3u8_audio != None: self.segments_audio.append(m3u8_audio_line[i+1])
|
||||
|
||||
console.log(f"[cyan]Find: {len(self.segments)} ts file to download")
|
||||
|
||||
def download_m3u8(self):
|
||||
response = requests.get(self.m3u8_url, headers={'user-agent': get_headers()})
|
||||
@ -68,6 +77,19 @@ class M3U8Downloader:
|
||||
m3u8_content = response.text
|
||||
self.parse_m3u8(m3u8_content)
|
||||
|
||||
# Check there is audio in first ts file
|
||||
path_test_ts_file = os.path.join(self.temp_folder, "ts_test.ts")
|
||||
if self.key and self.iv:
|
||||
open(path_test_ts_file, "wb").write(self.decrypt_ts(requests.get(self.segments[0]).content))
|
||||
else:
|
||||
open(path_test_ts_file, "wb").write(requests.get(self.segments[0]).content)
|
||||
|
||||
if not there_is_audio(path_test_ts_file):
|
||||
self.download_audio = True
|
||||
console.log("[cyan]=> Make req to get video and audio file")
|
||||
|
||||
os.remove(path_test_ts_file)
|
||||
|
||||
def decrypt_ts(self, encrypted_data):
|
||||
cipher = Cipher(algorithms.AES(self.key), modes.CBC(self.iv), backend=default_backend())
|
||||
decryptor = cipher.decryptor()
|
||||
@ -75,27 +97,50 @@ class M3U8Downloader:
|
||||
|
||||
return decrypted_data
|
||||
|
||||
def decrypt_and_save(self, args):
|
||||
ts_url, index = args
|
||||
ts_filename = os.path.join(self.temp_folder, f"{index}.ts")
|
||||
def decrypt_and_save(self, index):
|
||||
|
||||
video_ts_url = self.segments[index]
|
||||
video_ts_filename = os.path.join(self.temp_folder, f"{index}_v.ts")
|
||||
|
||||
if not os.path.exists(ts_filename):
|
||||
ts_response = requests.get(ts_url, headers={'user-agent': get_headers()}).content
|
||||
if self.download_audio:
|
||||
audio_ts_url = self.segments_audio[index]
|
||||
audio_ts_filename = os.path.join(self.temp_folder, f"{index}_a.ts")
|
||||
video_audio_ts_filename = os.path.join(self.temp_folder, f"{index}_v_a.ts")
|
||||
|
||||
# Download video or audio ts file
|
||||
if not os.path.exists(video_ts_url):
|
||||
ts_response = requests.get(video_ts_url, headers={'user-agent': get_headers()}).content
|
||||
|
||||
if self.key and self.iv:
|
||||
decrypted_data = self.decrypt_ts(ts_response)
|
||||
with open(ts_filename, "wb") as ts_file:
|
||||
with open(video_ts_filename, "wb") as ts_file:
|
||||
ts_file.write(decrypted_data)
|
||||
|
||||
else:
|
||||
with open(ts_filename, "wb") as ts_file:
|
||||
with open(video_ts_filename, "wb") as ts_file:
|
||||
ts_file.write(ts_response)
|
||||
|
||||
# Donwload only audio ts file
|
||||
if self.download_audio:
|
||||
ts_response = requests.get(audio_ts_url, headers={'user-agent': get_headers()}).content
|
||||
|
||||
if self.key and self.iv:
|
||||
decrypted_data = self.decrypt_ts(ts_response)
|
||||
with open(audio_ts_filename, "wb") as ts_file:
|
||||
ts_file.write(decrypted_data)
|
||||
|
||||
else:
|
||||
with open(audio_ts_filename, "wb") as ts_file:
|
||||
ts_file.write(ts_response)
|
||||
|
||||
# Join ts video and audio
|
||||
merge_ts_files(video_ts_filename, audio_ts_filename, video_audio_ts_filename)
|
||||
os.remove(video_ts_filename)
|
||||
os.remove(audio_ts_filename)
|
||||
|
||||
def download_and_save_ts(self):
|
||||
with ThreadPoolExecutor(max_workers=30) as executor:
|
||||
|
||||
list(tqdm(executor.map(self.decrypt_and_save, zip(self.segments, range(len(self.segments)))),
|
||||
total=len(self.segments), unit="bytes", unit_scale=True, unit_divisor=1024, desc="[yellow]Download"))
|
||||
list(tqdm(executor.map(self.decrypt_and_save, range(len(self.segments)) ), total=len(self.segments), unit="bytes", unit_scale=True, unit_divisor=1024, desc="[yellow]Download"))
|
||||
|
||||
def join_ts_files(self):
|
||||
|
||||
@ -110,12 +155,12 @@ class M3U8Downloader:
|
||||
relative_path = os.path.relpath(os.path.join(self.temp_folder, ts_file), current_dir)
|
||||
f.write(f"file '{relative_path}'\n")
|
||||
|
||||
console.print("[cyan]Start join all file")
|
||||
console.log("[cyan]Start join all file")
|
||||
try:
|
||||
(
|
||||
ffmpeg.input(file_list_path, format='concat', safe=0).output(self.output_filename, c="copy", loglevel="quiet").run()
|
||||
ffmpeg.input(file_list_path, format='concat', safe=0).output(self.output_filename, c='copy', loglevel='quiet').run()
|
||||
)
|
||||
console.print(f"[cyan]Clean ...")
|
||||
console.log(f"[cyan]Clean ...")
|
||||
except ffmpeg.Error as e:
|
||||
print(f"Errore durante il salvataggio del file MP4: {e}")
|
||||
finally:
|
||||
@ -124,9 +169,9 @@ class M3U8Downloader:
|
||||
|
||||
|
||||
# [ function ]
|
||||
def dw_m3u8(url, key=None, output_filename="output.mp4"):
|
||||
def dw_m3u8(url, audio_url=None, key=None, output_filename="output.mp4"):
|
||||
|
||||
downloader = M3U8Downloader(url, key, output_filename)
|
||||
downloader = M3U8Downloader(url, audio_url, key, output_filename)
|
||||
|
||||
downloader.download_m3u8()
|
||||
downloader.download_and_save_ts()
|
||||
|
@ -1,15 +1,31 @@
|
||||
# 4.01.2023
|
||||
|
||||
# Import
|
||||
from moviepy.editor import VideoFileClip
|
||||
import ffmpeg, subprocess
|
||||
|
||||
def convert_utf8_name(name):
|
||||
return str(name).encode('utf-8').decode('latin-1')
|
||||
|
||||
def check_audio_presence(file_path):
|
||||
try:
|
||||
video_clip = VideoFileClip(file_path)
|
||||
audio = video_clip.audio
|
||||
return audio is not None
|
||||
except Exception as e:
|
||||
print(f"Si è verificato un errore: {str(e)}")
|
||||
def there_is_audio(ts_file_path):
|
||||
probe = ffmpeg.probe(ts_file_path)
|
||||
return any(stream['codec_type'] == 'audio' for stream in probe['streams'])
|
||||
|
||||
|
||||
def merge_ts_files(video_path, audio_path, output_path):
|
||||
|
||||
"""command = [
|
||||
'ffmpeg',
|
||||
'-i', video_path,
|
||||
'-i', audio_path,
|
||||
'-c', 'copy',
|
||||
'-map', '0',
|
||||
'-map', '1',
|
||||
'-y', output_path
|
||||
]
|
||||
|
||||
subprocess.run(command)"""
|
||||
|
||||
input_video = ffmpeg.input(video_path)
|
||||
input_audio = ffmpeg.input(audio_path)
|
||||
|
||||
ffmpeg.output(input_video, input_audio, output_path, format='mpegts', acodec='copy', vcodec='copy', loglevel='quiet').run()
|
@ -5,5 +5,4 @@ tqdm
|
||||
rich
|
||||
random-user-agent
|
||||
ffmpeg-python
|
||||
moviepy
|
||||
cryptography
|
Loading…
x
Reference in New Issue
Block a user