mirror of
https://github.com/Arrowar/StreamingCommunity.git
synced 2025-06-07 03:55:24 +00:00
add subtitle download
This commit is contained in:
parent
9089caa191
commit
53d2a1a7f4
@ -1,9 +1,9 @@
|
|||||||
# 3.12.23 -> 10.12.23
|
# 3.12.23 -> 10.12.23
|
||||||
|
|
||||||
# Class import
|
# Class import
|
||||||
from Src.Util.Helper.headers import get_headers
|
from Src.Util.headers import get_headers
|
||||||
from Src.Util.Helper.console import console
|
from Src.Util.console import console
|
||||||
from Src.Util.FFmpeg.m3u8 import dw_m3u8
|
from Src.Lib.FFmpeg.my_m3u8 import download_m3u8
|
||||||
|
|
||||||
# General import
|
# General import
|
||||||
import requests, os, re, json, sys
|
import requests, os, re, json, sys
|
||||||
@ -102,5 +102,5 @@ def main_dw_film(id_film, title_name, domain):
|
|||||||
|
|
||||||
if m3u8_url_audio != None:
|
if m3u8_url_audio != None:
|
||||||
console.print("[blue]Use m3u8 audio => [red]True")
|
console.print("[blue]Use m3u8 audio => [red]True")
|
||||||
|
|
||||||
dw_m3u8(m3u8_url, m3u8_url_audio, m3u8_key, mp4_path)
|
download_m3u8(m3u8_index=m3u8_url, m3u8_audio=m3u8_url_audio, m3u8_subtitle=m3u8_url, key=m3u8_key, output_filename=mp4_path)
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
# 10.12.23
|
# 10.12.23
|
||||||
|
|
||||||
# Class import
|
# Class import
|
||||||
from Src.Util.Helper.headers import get_headers
|
from Src.Util.headers import get_headers
|
||||||
from Src.Util.Helper.console import console
|
from Src.Util.console import console
|
||||||
|
|
||||||
# General import
|
# General import
|
||||||
import requests, sys, json
|
import requests, sys, json
|
||||||
@ -11,15 +11,24 @@ from bs4 import BeautifulSoup
|
|||||||
def domain_version():
|
def domain_version():
|
||||||
|
|
||||||
console.print("[green]Get rules ...")
|
console.print("[green]Get rules ...")
|
||||||
req_repo = requests.get("https://raw.githubusercontent.com/Ghost6446/Streaming_comunity_data/main/data.json")
|
req_repo = requests.get("https://raw.githubusercontent.com/Ghost6446/Streaming_comunity_data/main/data.json", headers={'user-agent': get_headers()}, timeout=5)
|
||||||
|
domain = req_repo.json()['domain']
|
||||||
|
|
||||||
if req_repo.ok:
|
if req_repo.ok:
|
||||||
site_req = requests.get(f"https://streamingcommunity.{req_repo.json()['domain']}/", headers={'user-agent': get_headers()}).text
|
console.print(f"[blue]Test domain [white]=> [red]{domain}")
|
||||||
soup = BeautifulSoup(site_req, "lxml")
|
site_url = f"https://streamingcommunity.{domain}"
|
||||||
version = json.loads(soup.find("div", {"id": "app"}).get("data-page"))['version']
|
site_request = requests.get(site_url, headers={'user-agent': get_headers()})
|
||||||
console.print(f"[blue]Rules [white]=> [red].{req_repo.json()['domain']}")
|
|
||||||
|
|
||||||
return req_repo.json()['domain'], version
|
try:
|
||||||
|
soup = BeautifulSoup(site_request.text, "lxml")
|
||||||
|
version = json.loads(soup.find("div", {"id": "app"}).get("data-page"))['version']
|
||||||
|
console.print(f"[blue]Rules [white]=> [red].{domain}")
|
||||||
|
|
||||||
|
return domain, version
|
||||||
|
|
||||||
|
except:
|
||||||
|
console.log("[red]Cant get version, problem with domain")
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
console.log(f"[red]Error: {req_repo.status_code}")
|
console.log(f"[red]Error: {req_repo.status_code}")
|
||||||
@ -30,7 +39,11 @@ def search(title_search, domain):
|
|||||||
req = requests.get(f"https://streamingcommunity.{domain}/api/search?q={title_search}", headers={'user-agent': get_headers()})
|
req = requests.get(f"https://streamingcommunity.{domain}/api/search?q={title_search}", headers={'user-agent': get_headers()})
|
||||||
|
|
||||||
if req.ok:
|
if req.ok:
|
||||||
return [{'name': title['name'], 'type': title['type'], 'id': title['id'], 'slug': title['slug']} for title in req.json()['data']]
|
return [{'name': title['name'], 'type': title['type'], 'id': title['id'], 'slug': title['slug']} for title in req.json()['data']][0:21]
|
||||||
else:
|
else:
|
||||||
console.log(f"[red]Error: {req.status_code}")
|
console.log(f"[red]Error: {req.status_code}")
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
|
def display_search_results(db_title):
|
||||||
|
for i, title in enumerate(db_title):
|
||||||
|
console.print(f"[yellow]{i} [white]-> [green]{title['name']} [white]- [cyan]{title['type']}")
|
||||||
|
@ -1,14 +1,15 @@
|
|||||||
# 3.12.23 -> 10.12.23
|
# 3.12.23 -> 10.12.23
|
||||||
|
|
||||||
# Class import
|
# Class import
|
||||||
from Src.Util.Helper.headers import get_headers
|
from Src.Util.headers import get_headers
|
||||||
from Src.Util.Helper.console import console, msg
|
from Src.Util.console import console, msg
|
||||||
from Src.Util.FFmpeg.m3u8 import dw_m3u8
|
from Src.Lib.FFmpeg.my_m3u8 import download_m3u8
|
||||||
|
|
||||||
# General import
|
# General import
|
||||||
import requests, os, re, json, sys
|
import requests, os, re, json, sys
|
||||||
from bs4 import BeautifulSoup
|
from bs4 import BeautifulSoup
|
||||||
|
|
||||||
|
|
||||||
# [func]
|
# [func]
|
||||||
def get_token(id_tv, domain):
|
def get_token(id_tv, domain):
|
||||||
session = requests.Session()
|
session = requests.Session()
|
||||||
@ -47,6 +48,12 @@ def get_iframe(tv_id, ep_id, domain, token):
|
|||||||
'user-agent': get_headers()
|
'user-agent': get_headers()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
# Change user agent m3u8
|
||||||
|
custom_headers_req = {
|
||||||
|
'referer': f'https://streamingcommunity.{domain}/watch/{tv_id}?e={ep_id}',
|
||||||
|
'user-agent': get_headers()
|
||||||
|
}
|
||||||
|
|
||||||
if req.ok:
|
if req.ok:
|
||||||
url_embed = BeautifulSoup(req.text, "lxml").find("iframe").get("src")
|
url_embed = BeautifulSoup(req.text, "lxml").find("iframe").get("src")
|
||||||
req_embed = requests.get(url_embed, headers = {"User-agent": get_headers()}).text
|
req_embed = requests.get(url_embed, headers = {"User-agent": get_headers()}).text
|
||||||
@ -93,7 +100,7 @@ def get_m3u8_key_ep(json_win_video, json_win_param, tv_name, n_stagione, n_ep, e
|
|||||||
console.log(f"[red]Error: {req.status_code}")
|
console.log(f"[red]Error: {req.status_code}")
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
def get_m3u8_audio(json_win_video, json_win_param, tv_name, n_stagione, n_ep, ep_title, token_render):
|
def get_m3u8_playlist(json_win_video, json_win_param, tv_name, n_stagione, n_ep, ep_title, token_render):
|
||||||
req = requests.get(f'https://vixcloud.co/playlist/{json_win_video["id"]}', params={'token': json_win_param['token'], 'expires': json_win_param["expires"] }, headers={
|
req = requests.get(f'https://vixcloud.co/playlist/{json_win_video["id"]}', params={'token': json_win_param['token'], 'expires': json_win_param["expires"] }, headers={
|
||||||
'referer': f'https://vixcloud.co/embed/{json_win_video["id"]}?token={json_win_param[token_render]}&title={tv_name}&referer=1&expires={json_win_param["expires"]}&description=S{n_stagione}%3AE{n_ep}+{ep_title}&nextEpisode=1'
|
'referer': f'https://vixcloud.co/embed/{json_win_video["id"]}?token={json_win_param[token_render]}&title={tv_name}&referer=1&expires={json_win_param["expires"]}&description=S{n_stagione}%3AE{n_ep}+{ep_title}&nextEpisode=1'
|
||||||
})
|
})
|
||||||
@ -102,7 +109,7 @@ def get_m3u8_audio(json_win_video, json_win_param, tv_name, n_stagione, n_ep, ep
|
|||||||
m3u8_cont = req.text.split()
|
m3u8_cont = req.text.split()
|
||||||
for row in m3u8_cont:
|
for row in m3u8_cont:
|
||||||
if "audio" in str(row) and "ita" in str(row):
|
if "audio" in str(row) and "ita" in str(row):
|
||||||
return row.split(",")[-1].split('"')[-2]
|
return row.split(",")[-1].split('"')[-2], req.text
|
||||||
else:
|
else:
|
||||||
console.log(f"[red]Error: {req.status_code}")
|
console.log(f"[red]Error: {req.status_code}")
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
@ -125,12 +132,12 @@ def dw_single_ep(tv_id, eps, index_ep_select, domain, token, tv_name, season_sel
|
|||||||
mp4_format = mp4_name + ".mp4"
|
mp4_format = mp4_name + ".mp4"
|
||||||
mp4_path = os.path.join("videos", mp4_format)
|
mp4_path = os.path.join("videos", mp4_format)
|
||||||
|
|
||||||
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'], token_render)
|
m3u8_url_audio, m3u8_playlist_content = get_m3u8_playlist(json_win_video, json_win_param, tv_name, season_select, index_ep_select+1, eps[index_ep_select]['name'], token_render)
|
||||||
|
|
||||||
if m3u8_url_audio != None:
|
if m3u8_url_audio != None:
|
||||||
console.print("[blue]Use m3u8 audio => [red]True")
|
console.print("[blue]Use m3u8 audio => [red]True")
|
||||||
|
|
||||||
dw_m3u8(m3u8_url, m3u8_url_audio, m3u8_key, mp4_path)
|
download_m3u8(m3u8_playlist=m3u8_playlist_content, m3u8_index=m3u8_url, m3u8_audio=m3u8_url_audio, m3u8_subtitle=m3u8_url, key=m3u8_key, output_filename=mp4_path)
|
||||||
|
|
||||||
def main_dw_tv(tv_id, tv_name, version, domain):
|
def main_dw_tv(tv_id, tv_name, version, domain):
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
__title__ = 'Streaming_community'
|
__title__ = 'Streaming_community'
|
||||||
__version__ = 'v0.8.3'
|
__version__ = 'v0.8.5'
|
||||||
__author__ = 'Ghost6446'
|
__author__ = 'Ghost6446'
|
||||||
__description__ = 'A command-line program to download film'
|
__description__ = 'A command-line program to download film'
|
||||||
__license__ = 'MIT License'
|
__license__ = 'MIT License'
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
# 13.09.2023
|
# 13.09.2023
|
||||||
|
|
||||||
# Class import
|
# Class import
|
||||||
from Src.Util.Helper.console import console
|
from Src.Util.console import console
|
||||||
|
|
||||||
# General import
|
# General import
|
||||||
import os, requests, time
|
import os, requests, time
|
||||||
|
@ -1,63 +0,0 @@
|
|||||||
# 24.01.2023
|
|
||||||
|
|
||||||
# Class import
|
|
||||||
from Src.Util.Helper.console import console
|
|
||||||
|
|
||||||
# Import
|
|
||||||
import subprocess, os, requests, zipfile, sys
|
|
||||||
|
|
||||||
import ctypes, os, sys
|
|
||||||
|
|
||||||
def isAdmin():
|
|
||||||
try:
|
|
||||||
is_admin = (os.getuid() == 0)
|
|
||||||
except AttributeError:
|
|
||||||
is_admin = ctypes.windll.shell32.IsUserAnAdmin() != 0
|
|
||||||
return is_admin
|
|
||||||
|
|
||||||
def download_ffmpeg():
|
|
||||||
|
|
||||||
# Specify the URL for the FFmpeg binary zip file for Windows
|
|
||||||
ffmpeg_url = "https://www.gyan.dev/ffmpeg/builds/ffmpeg-git-full.7z"
|
|
||||||
|
|
||||||
# Name of the directory where FFmpeg will be extracted
|
|
||||||
ffmpeg_dir = "ffmpeg"
|
|
||||||
console.print("[yellow]Downloading FFmpeg...[/yellow]")
|
|
||||||
|
|
||||||
# Download the FFmpeg zip file
|
|
||||||
response = requests.get(ffmpeg_url)
|
|
||||||
os.makedirs(ffmpeg_dir, exist_ok=True)
|
|
||||||
|
|
||||||
# Save the zip file
|
|
||||||
zip_file_path = os.path.join(ffmpeg_dir, "ffmpeg.zip")
|
|
||||||
with open(zip_file_path, "wb") as zip_file:
|
|
||||||
zip_file.write(response.content)
|
|
||||||
|
|
||||||
with zipfile.ZipFile(zip_file_path, "r") as zip_ref:
|
|
||||||
zip_ref.extractall(ffmpeg_dir)
|
|
||||||
|
|
||||||
# Add the FFmpeg directory to the system PATH
|
|
||||||
ffmpeg_bin_dir = os.path.join(os.getcwd(), ffmpeg_dir, "bin")
|
|
||||||
os.environ["PATH"] += os.pathsep + ffmpeg_bin_dir
|
|
||||||
os.remove(zip_file_path)
|
|
||||||
|
|
||||||
def check_ffmpeg():
|
|
||||||
|
|
||||||
console.print("[green]Checking ffmpeg ...")
|
|
||||||
|
|
||||||
try:
|
|
||||||
subprocess.run(["ffmpeg", "-version"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=True)
|
|
||||||
console.print("[blue]FFmpeg [white]=> [red]Add to system path")
|
|
||||||
except:
|
|
||||||
try:
|
|
||||||
console.print("[cyan]FFmpeg is not in the PATH. Downloading and adding to the PATH...[/cyan]")
|
|
||||||
|
|
||||||
if not isAdmin():
|
|
||||||
console.log("[red]You need to be admin to proceed!")
|
|
||||||
sys.exit(0)
|
|
||||||
|
|
||||||
download_ffmpeg()
|
|
||||||
sys.exit(0) # Exit
|
|
||||||
except:
|
|
||||||
console.print("[red]Unable to download or add FFmpeg to the PATH.[/red]")
|
|
||||||
sys.exit(0) # Exit
|
|
@ -1,195 +0,0 @@
|
|||||||
# 5.01.24 -> 7.01.24
|
|
||||||
|
|
||||||
# Class import
|
|
||||||
from Src.Util.Helper.console import console, config_logger
|
|
||||||
from Src.Util.Helper.headers import get_headers
|
|
||||||
from Src.Util.FFmpeg.util import print_duration_table
|
|
||||||
|
|
||||||
# Import
|
|
||||||
import requests, re, os, ffmpeg, time, sys, warnings, logging, shutil, subprocess
|
|
||||||
from tqdm.rich import tqdm
|
|
||||||
from concurrent.futures import ThreadPoolExecutor
|
|
||||||
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
|
|
||||||
from cryptography.hazmat.backends import default_backend
|
|
||||||
|
|
||||||
# Disable warning
|
|
||||||
from tqdm import TqdmExperimentalWarning
|
|
||||||
warnings.filterwarnings("ignore", category=TqdmExperimentalWarning)
|
|
||||||
warnings.filterwarnings("ignore", category=UserWarning, module="cryptography")
|
|
||||||
|
|
||||||
# Variable
|
|
||||||
os.makedirs("videos", exist_ok=True)
|
|
||||||
DOWNLOAD_WORKERS = 30
|
|
||||||
|
|
||||||
|
|
||||||
# [ main class ]
|
|
||||||
class Decryption():
|
|
||||||
def __init__(self, key):
|
|
||||||
self.iv = None
|
|
||||||
self.key = key
|
|
||||||
|
|
||||||
def decode_ext_x_key(self, key_str):
|
|
||||||
logging.debug(f"String to decode: {key_str}")
|
|
||||||
key_str = key_str.replace('"', '').lstrip("#EXT-X-KEY:")
|
|
||||||
v_list = re.findall(r"[^,=]+", key_str)
|
|
||||||
key_map = {v_list[i]: v_list[i+1] for i in range(0, len(v_list), 2)}
|
|
||||||
logging.debug(f"Output string: {key_map}")
|
|
||||||
return key_map
|
|
||||||
|
|
||||||
def parse_key(self, raw_iv):
|
|
||||||
self.iv = bytes.fromhex(raw_iv.replace("0x", ""))
|
|
||||||
|
|
||||||
def decrypt_ts(self, encrypted_data):
|
|
||||||
cipher = Cipher(algorithms.AES(self.key), modes.CBC(self.iv), backend=default_backend())
|
|
||||||
decryptor = cipher.decryptor()
|
|
||||||
decrypted_data = decryptor.update(encrypted_data) + decryptor.finalize()
|
|
||||||
|
|
||||||
return decrypted_data
|
|
||||||
|
|
||||||
class M3U8():
|
|
||||||
def __init__(self, url, key=None):
|
|
||||||
self.url = url
|
|
||||||
self.key = bytes.fromhex(key) if key is not None else key
|
|
||||||
self.temp_folder = "tmp"
|
|
||||||
os.makedirs(self.temp_folder, exist_ok=True)
|
|
||||||
|
|
||||||
def parse_data(self, m3u8_content):
|
|
||||||
self.decription = Decryption(self.key)
|
|
||||||
self.segments = []
|
|
||||||
base_url = self.url.rstrip(self.url.split("/")[-1])
|
|
||||||
lines = m3u8_content.split('\n')
|
|
||||||
|
|
||||||
for i in range(len(lines)):
|
|
||||||
line = str(lines[i])
|
|
||||||
|
|
||||||
if line.startswith("#EXT-X-KEY:"):
|
|
||||||
x_key_dict = self.decription.decode_ext_x_key(line)
|
|
||||||
self.decription.parse_key(x_key_dict['IV'])
|
|
||||||
|
|
||||||
if line.startswith("#EXTINF"):
|
|
||||||
ts_url = lines[i+1]
|
|
||||||
|
|
||||||
if not ts_url.startswith("http"):
|
|
||||||
ts_url = base_url + ts_url
|
|
||||||
|
|
||||||
logging.debug(f"Add to segment: {ts_url}")
|
|
||||||
self.segments.append(ts_url)
|
|
||||||
|
|
||||||
def get_info(self):
|
|
||||||
self.max_retry = 3
|
|
||||||
response = requests.get(self.url, headers={'user-agent': get_headers()})
|
|
||||||
|
|
||||||
if response.ok:
|
|
||||||
self.parse_data(response.text)
|
|
||||||
console.log(f"[red]Ts segments find [white]=> [yellow]{len(self.segments)}")
|
|
||||||
else:
|
|
||||||
console.log("[red]Wrong m3u8 url")
|
|
||||||
sys.exit(0)
|
|
||||||
|
|
||||||
def get_req_ts(self, ts_url):
|
|
||||||
|
|
||||||
try:
|
|
||||||
response = requests.get(ts_url, headers={'user-agent': get_headers()})
|
|
||||||
|
|
||||||
if response.status_code == 200:
|
|
||||||
return response.content
|
|
||||||
else:
|
|
||||||
print(f"Failed: {ts_url}, with error: {response.status_code}")
|
|
||||||
self.segments.remove(ts_url)
|
|
||||||
logging.error(f"Failed download: {ts_url}")
|
|
||||||
return None
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Failed: {ts_url}, with error: {e}")
|
|
||||||
self.segments.remove(ts_url)
|
|
||||||
logging.error(f"Failed download: {ts_url}")
|
|
||||||
return None
|
|
||||||
|
|
||||||
def save_ts(self, index):
|
|
||||||
ts_url = self.segments[index]
|
|
||||||
ts_filename = os.path.join(self.temp_folder, f"{index}.ts")
|
|
||||||
|
|
||||||
if not os.path.exists(ts_filename):
|
|
||||||
ts_content = self.get_req_ts(ts_url)
|
|
||||||
|
|
||||||
if ts_content is not None:
|
|
||||||
with open(ts_filename, "wb") as ts_file:
|
|
||||||
if self.key and self.decription.iv:
|
|
||||||
decrypted_data = self.decription.decrypt_ts(ts_content)
|
|
||||||
ts_file.write(decrypted_data)
|
|
||||||
else:
|
|
||||||
ts_file.write(ts_content)
|
|
||||||
|
|
||||||
def download_ts(self):
|
|
||||||
with ThreadPoolExecutor(max_workers=DOWNLOAD_WORKERS) as executor:
|
|
||||||
list(tqdm(executor.map(self.save_ts, range(len(self.segments)) ), total=len(self.segments), unit="bytes", unit_scale=True, unit_divisor=1024, desc="[yellow]Download"))
|
|
||||||
|
|
||||||
def join(self, output_filename):
|
|
||||||
|
|
||||||
current_dir = os.path.dirname(os.path.realpath(__file__))
|
|
||||||
file_list_path = os.path.join(current_dir, 'file_list.txt')
|
|
||||||
|
|
||||||
ts_files = [f for f in os.listdir(self.temp_folder) if f.endswith(".ts")]
|
|
||||||
def extract_number(file_name):
|
|
||||||
return int(''.join(filter(str.isdigit, file_name)))
|
|
||||||
ts_files.sort(key=extract_number)
|
|
||||||
|
|
||||||
with open(file_list_path, 'w') as f:
|
|
||||||
for ts_file in ts_files:
|
|
||||||
relative_path = os.path.relpath(os.path.join(self.temp_folder, ts_file), current_dir)
|
|
||||||
f.write(f"file '{relative_path}'\n")
|
|
||||||
|
|
||||||
console.log("[cyan]Start join all file")
|
|
||||||
try:
|
|
||||||
ffmpeg.input(file_list_path, format='concat', safe=0).output(output_filename, c='copy', loglevel='quiet').run()
|
|
||||||
except ffmpeg.Error as e:
|
|
||||||
console.log(f"[red]Error saving MP4: {e.stdout}")
|
|
||||||
sys.exit(0)
|
|
||||||
|
|
||||||
console.log(f"[cyan]Clean ...")
|
|
||||||
os.remove(file_list_path)
|
|
||||||
shutil.rmtree("tmp", ignore_errors=True)
|
|
||||||
|
|
||||||
class M3U8Downloader:
|
|
||||||
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.video_path = output_filename
|
|
||||||
self.audio_path = os.path.join("videos", "audio.mp4")
|
|
||||||
|
|
||||||
def start(self):
|
|
||||||
video_m3u8 = M3U8(self.m3u8_url, self.key)
|
|
||||||
console.log("[green]Download video ts")
|
|
||||||
video_m3u8.get_info()
|
|
||||||
video_m3u8.download_ts()
|
|
||||||
video_m3u8.join(self.video_path)
|
|
||||||
print_duration_table(self.video_path)
|
|
||||||
print("\n")
|
|
||||||
|
|
||||||
if self.m3u8_audio != None:
|
|
||||||
audio_m3u8 = M3U8(self.m3u8_audio, self.key)
|
|
||||||
console.log("[green]Download audio ts")
|
|
||||||
audio_m3u8.get_info()
|
|
||||||
audio_m3u8.download_ts()
|
|
||||||
audio_m3u8.join(self.audio_path)
|
|
||||||
print_duration_table(self.audio_path)
|
|
||||||
|
|
||||||
self.join_audio()
|
|
||||||
|
|
||||||
def join_audio(self):
|
|
||||||
output_path = self.video_path + ".mp4"
|
|
||||||
try:
|
|
||||||
video_stream = ffmpeg.input(self.video_path)
|
|
||||||
audio_stream = ffmpeg.input(self.audio_path)
|
|
||||||
ffmpeg.output(video_stream, audio_stream, output_path, vcodec="copy", acodec="copy").global_args('-map', '0:v:0', '-map', '1:a:0', '-shortest', '-strict', 'experimental').run(overwrite_output=True)
|
|
||||||
except ffmpeg.Error as e:
|
|
||||||
print("ffmpeg error:", e.stderr)
|
|
||||||
|
|
||||||
os.remove(self.video_path)
|
|
||||||
os.remove(self.audio_path)
|
|
||||||
|
|
||||||
# [ main function ]
|
|
||||||
def dw_m3u8(url, audio_url=None, key=None, output_filename="output.mp4"):
|
|
||||||
print("\n")
|
|
||||||
M3U8Downloader(url, audio_url, key, output_filename).start()
|
|
@ -1,28 +0,0 @@
|
|||||||
# 31.01.24
|
|
||||||
|
|
||||||
# Class import
|
|
||||||
from Src.Util.Helper.console import console
|
|
||||||
|
|
||||||
# Import
|
|
||||||
import ffmpeg
|
|
||||||
|
|
||||||
def get_video_duration(file_path):
|
|
||||||
try:
|
|
||||||
probe = ffmpeg.probe(file_path)
|
|
||||||
duration = float(probe['format']['duration'])
|
|
||||||
return duration
|
|
||||||
except ffmpeg.Error as e:
|
|
||||||
print(f"Error: {e.stderr}")
|
|
||||||
return None
|
|
||||||
|
|
||||||
def format_duration(seconds):
|
|
||||||
hours, remainder = divmod(seconds, 3600)
|
|
||||||
minutes, seconds = divmod(remainder, 60)
|
|
||||||
return int(hours), int(minutes), int(seconds)
|
|
||||||
|
|
||||||
def print_duration_table(file_path):
|
|
||||||
video_duration = get_video_duration(file_path)
|
|
||||||
|
|
||||||
if video_duration is not None:
|
|
||||||
hours, minutes, seconds = format_duration(video_duration)
|
|
||||||
console.log(f"[cyan]Info [green]'{file_path}': [purple]{int(hours)}[red]h [purple]{int(minutes)}[red]m [purple]{int(seconds)}[red]s")
|
|
@ -1,7 +1,7 @@
|
|||||||
# 3.12.23
|
# 3.12.23
|
||||||
|
|
||||||
# Import
|
# Import
|
||||||
from Src.Util.Helper.console import console
|
from Src.Util.console import console
|
||||||
|
|
||||||
def msg_start():
|
def msg_start():
|
||||||
|
|
@ -6,3 +6,4 @@ rich
|
|||||||
random-user-agent
|
random-user-agent
|
||||||
ffmpeg-python
|
ffmpeg-python
|
||||||
cryptography==3.4.8 # Problem with new version
|
cryptography==3.4.8 # Problem with new version
|
||||||
|
m3u8
|
||||||
|
27
run.py
27
run.py
@ -1,18 +1,25 @@
|
|||||||
# 10.12.23 -> 31.01.24
|
# 10.12.23 -> 31.01.24
|
||||||
|
|
||||||
# Class import
|
# Class
|
||||||
import Src.Api.page as Page
|
import Src.Api.page as Page
|
||||||
from Src.Api.film import main_dw_film as download_film
|
from Src.Api.film import main_dw_film as download_film
|
||||||
from Src.Api.tv import main_dw_tv as download_tv
|
from Src.Api.tv import main_dw_tv as download_tv
|
||||||
from Src.Util.Helper.message import msg_start
|
from Src.Util.message import msg_start
|
||||||
from Src.Util.Helper.console import console, msg
|
from Src.Util.console import console, msg
|
||||||
|
from Src.Util.os import remove_folder
|
||||||
from Src.Upload.update import main_update
|
from Src.Upload.update import main_update
|
||||||
from Src.Util.FFmpeg.installer import check_ffmpeg
|
from Src.Lib.FFmpeg.installer import check_ffmpeg
|
||||||
from Src.Util.Helper.os import remove_folder
|
|
||||||
|
# Import
|
||||||
|
import sys
|
||||||
|
|
||||||
# [ main ]
|
# [ main ]
|
||||||
def initialize():
|
def initialize():
|
||||||
|
|
||||||
|
if sys.version_info < (3, 11):
|
||||||
|
console.log("Install python version > 3.11")
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
remove_folder("tmp")
|
remove_folder("tmp")
|
||||||
msg_start()
|
msg_start()
|
||||||
|
|
||||||
@ -24,10 +31,6 @@ def initialize():
|
|||||||
check_ffmpeg()
|
check_ffmpeg()
|
||||||
print("\n")
|
print("\n")
|
||||||
|
|
||||||
def display_search_results(db_title):
|
|
||||||
for i, title in enumerate(db_title):
|
|
||||||
console.print(f"[yellow]{i} [white]-> [green]{title['name']} [white]- [cyan]{title['type']}")
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
|
||||||
initialize()
|
initialize()
|
||||||
@ -35,7 +38,7 @@ def main():
|
|||||||
|
|
||||||
film_search = msg.ask("\n[blue]Insert word to search in all site: ").strip()
|
film_search = msg.ask("\n[blue]Insert word to search in all site: ").strip()
|
||||||
db_title = Page.search(film_search, domain)
|
db_title = Page.search(film_search, domain)
|
||||||
display_search_results(db_title)
|
Page.display_search_results(db_title)
|
||||||
|
|
||||||
if len(db_title) != 0:
|
if len(db_title) != 0:
|
||||||
index_select = int(msg.ask("\n[blue]Index to download: "))
|
index_select = int(msg.ask("\n[blue]Index to download: "))
|
||||||
@ -55,7 +58,7 @@ def main():
|
|||||||
else:
|
else:
|
||||||
console.print("[red]Cant find a single element")
|
console.print("[red]Cant find a single element")
|
||||||
|
|
||||||
console.print("\n[red]Done")
|
console.print("[red]Done")
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
main()
|
main()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user