rearange files and updateing files

This commit is contained in:
SumGuyV5 committed 2026-09-11 20:08:26 +00:00
1 parent 20acb4bc9f
commit 2de2c461e2
28 files changed
+283 -186

No files matched your search

@@ -1,16 +1,16 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import requests import requests
import os import os
import linux import package.linux as linux
import time import time
from database import Database from package.database import Database
import uploader import uploader
from uploader import CategoryId from uploader import CategoryId
import youtube_hashtags import youtube_hashtags
import transcribe_video import package.transcribe_video as transcribe_video
CHANNEL_NAME = 'teampgp' # Replace with the streamer's username CHANNEL_NAME = 'teampgp' # Replace with the streamer's username
DB = None DB = None
+1 -1
View File
@@ -3,7 +3,7 @@ import requests
import subprocess import subprocess
from datetime import datetime from datetime import datetime
from database import Database from package.database import Database
import uploader import uploader
from uploader import CategoryId from uploader import CategoryId
File renamed without changes.
View File
File renamed without changes.
View File
File renamed without changes.
File renamed without changes.
+63
View File
@@ -0,0 +1,63 @@
#!/usr/bin/env python3
from datetime import datetime, UTC
import package.database as database
DB = None
def has_no_timezone(dt_string: str) -> bool:
try:
# fromisoformat parses standard formats like YYYY-MM-DD HH:MM:SS
dt = datetime.fromisoformat(dt_string)
# Check if tzinfo is completely missing OR if its offset is undefined
return dt.tzinfo is None or dt.tzinfo.utcoffset(dt) is None
except ValueError:
print(f"Error: '{dt_string}' is not a valid date-time string.")
return False
def fix_time():
chats = DB.get_vods()
#chats = DB.get_clips()
for chat in chats:
(
id,
title,
created_at,
view_count,
duration,
url,
thumbnail_url,
game_id,
game_name,
stream_id,
creator_name,
clip_is,
downloaded,
uploaded_yt,
uploaded_yt_chats,
uploaded_yt_shorts,
) = chat
if "T" in created_at:
date_string = created_at.replace("T", " ")
DB.update_datetime(id, date_string)
if has_no_timezone(created_at):
dt_with_utc = datetime.fromisoformat(created_at).replace(tzinfo=UTC)
date_string = dt_with_utc.isoformat().strftime('%Y-%m-%d %H:%M:%S %z')
DB.update_datetime(id, date_string)
print("====================================================")
print(f"✅ Processing: Times Fix.")
print("====================================================")
def main():
global DB
DB = database.Database()
fix_time()
if __name__ == "__main__":
main()
+52
View File
@@ -0,0 +1,52 @@
#!/usr/bin/env python3
from pathlib import Path
import package.database as database
DB = None
def fix_download():
chats = DB.get_undownloaded()
#chats = DB.get_clips()
for chat in chats:
(
id,
title,
created_at,
view_count,
duration,
url,
thumbnail_url,
game_id,
game_name,
stream_id,
creator_name,
clip_is,
downloaded,
uploaded_yt,
uploaded_yt_chats,
uploaded_yt_shorts,
) = chat
if clip_is:
file_name = Path(f"download/clips/{id}/{id}.mp4")
else:
file_name = Path(f"download/videos/{id}/{id}.mp4")
if file_name.exists():
DB.mark_as_downloaded(id)
print("====================================================")
print(f"✅ Processing: download Fix.")
print("====================================================")
def main():
global DB
DB = database.Database()
fix_download()
if __name__ == "__main__":
main()
+3 -3
View File
@@ -4,8 +4,8 @@ import json
import asyncio import asyncio
from pathlib import Path from pathlib import Path
import database import package.database as database
import twitch_video_info import package.twitch.video_info as video_info
DB = None DB = None
def format_to_hms(total_seconds): def format_to_hms(total_seconds):
@@ -44,7 +44,7 @@ def read_json(file_path: str):
video_length = format_to_hms(video_length_seconds) video_length = format_to_hms(video_length_seconds)
game_id = asyncio.run(twitch_video_info.get_game_id_by_name(video_game)) game_id = asyncio.run(video_info.get_game_id_by_name(video_game))
DB.insert_video_record( DB.insert_video_record(
video_id, video_id,
File renamed without changes.
+1 -1
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import database import package.database as database
from pathlib import Path from pathlib import Path
DB = None DB = None
@@ -1,5 +1,5 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import database import package.database as database
DB = None DB = None
@@ -1,6 +1,6 @@
import os import os
import database import package.database as database
DB = None DB = None
+8 -8
View File
@@ -1,23 +1,23 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import asyncio import asyncio
import twitch_video_info import package.twitch.video_info as video_info
import twitch_download_videos import package.twitch.download_videos as download_videos
import twitch_download_thumbnails import package.twitch.download_thumbnails as download_thumbnails
import build_videos import package.build_videos as build_videos
if __name__ == "__main__": if __name__ == "__main__":
# Get Twitch Video Info # Get Twitch Video Info
asyncio.run(twitch_video_info.main()) asyncio.run(video_info())
# Download Twitch Videos # Download Twitch Videos
twitch_download_videos.main() download_videos()
twitch_download_thumbnails.main() download_thumbnails()
#Build #Build
build_videos.main() build_videos()
print("====================================================") print("====================================================")
print(f"✅ Done.") print(f"✅ Done.")
+35
View File
@@ -0,0 +1,35 @@
# package/__init__.py
import os
# 1. Package Metadata
__version__ = "1.0.0"
__author__ = "Richard Allen"
# 2. Initialization Logic
print("Initializing package...")
# Ensure a required directory exists when the package loads
CACHE_DIR = os.path.join(os.path.expanduser("~"), ".package_cache")
os.makedirs(CACHE_DIR, exist_ok=True)
# 3. Expose Database Tools (Added)
# Replace 'DatabaseClient' and 'connect_to_db' with your actual class/function names
from .build_videos import main as build_videos
from .config import CHANNEL_NAME, DB
from .database import Database
from .transcribe_video import transcribe_to_srt
from .utils import run_command
# 4. Expose Subpackages
from . import twitch
# (Optional) Defines what is exposed during 'from package import *'
__all__ = [
"build_videos",
"CHANNEL_NAME",
"DB",
"Database",
"transcribe_to_srt",
"utils",
"twitch",
]
+4 -8
View File
@@ -1,10 +1,8 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import database
import youtube_short import youtube_short
import transcribe_video import package.transcribe_video as transcribe_video
import twitch_chat_vod import package.twitch.chat_vod as chat_vod
from package.config import DB as DB
DB = None
def build_chat_video(): def build_chat_video():
chats = DB.get_unuploaded_chats() chats = DB.get_unuploaded_chats()
@@ -33,7 +31,7 @@ def build_chat_video():
print(f"🚀 Chat Video: {title}") print(f"🚀 Chat Video: {title}")
print("====================================================") print("====================================================")
twitch_chat_vod.combine_twitch_vod_and_chat(f"download/videos/{id}/{id}.mp4", "side-by-side") chat_vod.combine_twitch_vod_and_chat(f"download/videos/{id}/{id}.mp4", "side-by-side")
print("====================================================") print("====================================================")
print(f"✅ Processing: Chat Video Done.") print(f"✅ Processing: Chat Video Done.")
@@ -117,8 +115,6 @@ def build_shorts():
print("====================================================") print("====================================================")
def main(): def main():
global DB
DB = database.Database()
build_shorts() build_shorts()
build_transcribe() build_transcribe()
build_chat_video() build_chat_video()
+6
View File
@@ -0,0 +1,6 @@
#!/usr/bin/env python3
import package.database as database
CHANNEL_NAME = "teampgp"
DB = database.Database()
+7
View File
@@ -80,6 +80,13 @@ class Database:
"""Flags a specific row record to downloaded (0).""" """Flags a specific row record to downloaded (0)."""
self.__mark_as(record_id, "downloaded", "0") self.__mark_as(record_id, "downloaded", "0")
def update_datetime(self, record_id: str, created_at: str):
"""Updates the Datetime for timezone fix"""
self.cursor.execute(
f"UPDATE twitch_videos SET created_at = ? WHERE id = ?",
(created_at, record_id))
self.conn.commit()
def __get_unuploaded(self, set_row: str, also: str = "") -> list[Any]: def __get_unuploaded(self, set_row: str, also: str = "") -> list[Any]:
"""Retrieve all rows that were download but not uploaded""" """Retrieve all rows that were download but not uploaded"""
self.cursor.execute(f"SELECT {self.columns} FROM twitch_videos WHERE downloaded = 1 AND {set_row} = 0 {also}") self.cursor.execute(f"SELECT {self.columns} FROM twitch_videos WHERE downloaded = 1 AND {set_row} = 0 {also}")
@@ -1,6 +1,5 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import os import os
import sys
import shutil import shutil
import subprocess import subprocess
from pathlib import Path from pathlib import Path
+15
View File
@@ -0,0 +1,15 @@
# package/twitch/__init__.py
# Expose components from individual modules using relative imports
from .chat_vod import combine_twitch_vod_and_chat
from .download_thumbnails import main as download_thumbnails
from .download_videos import main as download_videos
from .video_info import main as video_info
# Explicitly define what is exposed when importing the subpackage
__all__ = [
"combine_twitch_vod_and_chat",
"download_thumbnails",
"download_videos",
"video_info",
]
@@ -1,7 +1,7 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import os import os
import cv2 import cv2
import linux import package.utils as utils
def get_video_height(video_path: str) -> int: def get_video_height(video_path: str) -> int:
# Open the video file # Open the video file
@@ -86,12 +86,14 @@ def combine_twitch_vod_and_chat(vod_path: str, layout: str = "side-by-side", for
chat_cmd = (f"{chat_cmd} --generate-mask ") chat_cmd = (f"{chat_cmd} --generate-mask ")
if not os.path.exists(temp_chat): if not os.path.exists(temp_chat):
chat_success = linux.run_command(chat_cmd, look_for=["[STATUS]"]) chat_success = utils.run_command(chat_cmd, look_for=["[STATUS]"])
if chat_success: if chat_success:
print("✅ Success: TwitchDownloaderCLI render chat video.") print("✅ Success: TwitchDownloaderCLI render chat video.")
else: else:
print("❌ Error: TwitchDownloaderCLI failed to render chat video.") print("❌ Error: TwitchDownloaderCLI failed to render chat video.")
if os.path.exists(temp_chat):
os.remove(temp_chat) os.remove(temp_chat)
if os.path.exists(mask_path):
os.remove(mask_path) os.remove(mask_path)
return False return False
@@ -119,7 +121,7 @@ def combine_twitch_vod_and_chat(vod_path: str, layout: str = "side-by-side", for
else: else:
raise ValueError("Invalid layout choice. Choose 'side-by-side' or 'overlay'.") raise ValueError("Invalid layout choice. Choose 'side-by-side' or 'overlay'.")
ffmpeg_success = linux.run_command(ffmpeg_cmd, progress_prefix="FFmpeg Merge") ffmpeg_success = utils.run_command(ffmpeg_cmd, progress_prefix="FFmpeg Merge")
# Step 4: Final verification and cleanup # Step 4: Final verification and cleanup
if ffmpeg_success and os.path.exists(temp_with_chat): if ffmpeg_success and os.path.exists(temp_with_chat):
+24
View File
@@ -0,0 +1,24 @@
#!/usr/bin/env python3
import json
from twitchAPI.twitch import Twitch
from twitchAPI.helper import first
from package.config import CHANNEL_NAME as CHANNEL_NAME
# 1. Fill in your credentials from the Twitch Developer Console
SECRETS = None
TWITCH = None
USER = None
async def get_twitch():
global SECRETS, TWITCH, USER
if SECRETS is None:
with open('twitch_secrets.json', 'r') as f:
SECRETS = json.load(f)
if TWITCH is None:
TWITCH = await Twitch(SECRETS['client_id'], SECRETS['client_secret'])
if USER is None:
USER = await first(TWITCH.get_users(logins=[CHANNEL_NAME]))
if not USER:
print("User not found.")
@@ -1,30 +1,12 @@
#!/usr/bin/env python3
import os import os
import json
import asyncio import asyncio
import requests import requests
from twitchAPI.twitch import Twitch
from twitchAPI.helper import first from twitchAPI.helper import first
import database import package.config as config
import package.database as database
# 1. Fill in your credentials from the Twitch Developer Console
SECRETS = None
TWITCH = None
USER = None
CHANNEL_NAME = "teampgp"
async def get_twitch():
global SECRETS, TWITCH, USER
if SECRETS is None:
with open('twitch_secrets.json', 'r') as f:
SECRETS = json.load(f)
if TWITCH is None:
TWITCH = await Twitch(SECRETS['client_id'], SECRETS['client_secret'])
if USER is None:
USER = await first(TWITCH.get_users(logins=[CHANNEL_NAME]))
if not USER:
print("User not found.")
async def download_live_thumbnail(twitch_client, streamer_username: str, w: int = 1920, h: int = 1080): async def download_live_thumbnail(twitch_client, streamer_username: str, w: int = 1920, h: int = 1080):
"""Fetches and saves the live stream thumbnail for an active broadcast.""" """Fetches and saves the live stream thumbnail for an active broadcast."""
@@ -100,12 +82,12 @@ def save_image(url: str, filename: str, stream: bool = True):
async def main(): async def main():
# Initialize connection & automatically authorize the App token # Initialize connection & automatically authorize the App token
await get_twitch() await config.get_twitch()
twitch = TWITCH # Twitch(APP_ID, APP_SECRET) twitch = config.TWITCH # Twitch(APP_ID, APP_SECRET)
# --- OPTION A: Download Live Thumbnail --- # --- OPTION A: Download Live Thumbnail ---
# Target user must be streaming live right now # Target user must be streaming live right now
target_streamer = CHANNEL_NAME target_streamer = config.CHANNEL_NAME
#await download_live_thumbnail(twitch, target_streamer, 1920, 1080) #await download_live_thumbnail(twitch, target_streamer, 1920, 1080)
# --- OPTION B: Download Past Broadcast VOD Thumbnail --- # --- OPTION B: Download Past Broadcast VOD Thumbnail ---
@@ -3,11 +3,8 @@ import csv
import subprocess import subprocess
from datetime import datetime, timedelta, timezone from datetime import datetime, timedelta, timezone
import linux import package.utils as utils
from database import Database from package.config import DB as DB
CHANNEL_NAME = 'teampgp'
DB = None
def write_csv(data, file_name): def write_csv(data, file_name):
# Open file with newline='' to prevent extra blank rows across platforms # Open file with newline='' to prevent extra blank rows across platforms
@@ -78,8 +75,8 @@ def download():
csv_file = f"{target_dir}/{id}.csv" csv_file = f"{target_dir}/{id}.csv"
# 3. FIXED: Use the live streaming function to prevent Out-Of-Memory crashes # 3. FIXED: Use the live streaming function to prevent Out-Of-Memory crashes
output = linux.run_command(cmd, look_for=["[STATUS]"]) output = utils.run_command(cmd, look_for=["[STATUS]"])
output2 = linux.run_command(f"TwitchDownloaderCLI chatdownload --id {id} -o {target_dir}/{id}_chat.json -E --collision Overwrite --temp-path download/temp", look_for=["[STATUS]"]) output2 = utils.run_command(f"TwitchDownloaderCLI chatdownload --id {id} -o {target_dir}/{id}_chat.json -E --collision Overwrite --temp-path download/temp", look_for=["[STATUS]"])
if output: if output:
# Only write CSV and update database if download actually completed # Only write CSV and update database if download actually completed
@@ -100,8 +97,6 @@ def download():
print("Finished Downloading Pipeline.") print("Finished Downloading Pipeline.")
def main(): def main():
global DB
DB = Database()
download() download()
if __name__ == "__main__": if __name__ == "__main__":
@@ -1,25 +1,21 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import asyncio import asyncio
import json
import httpx # Switched from requests to prevent async loop freezing import httpx # Switched from requests to prevent async loop freezing
import database
from twitchAPI.twitch import Twitch
from twitchAPI.helper import first from twitchAPI.helper import first
from twitchAPI.type import VideoType from twitchAPI.type import VideoType
SECRETS = None import package.twitch.config as config
TWITCH = None from package.config import DB as DB
USER = None
GAME_CACHE = {} # Local cache dictionary to store game_id -> game_name mapping GAME_CACHE = {} # Local cache dictionary to store game_id -> game_name mapping
CHANNEL_NAME = "teampgp"
async def get_game_id_by_name(game_name: str) -> str: async def get_game_id_by_name(game_name: str) -> str:
if SECRETS is None: if config.SECRETS is None:
await get_twitch() await config.get_twitch()
# Query the 'get_games' endpoint using the names parameter # Query the 'get_games' endpoint using the names parameter
# The API expects a list, even for a single game name # The API expects a list, even for a single game name
async for game in TWITCH.get_games(names=[game_name]): async for game in config.TWITCH.get_games(names=[game_name]):
print(f"Game Name: {game.name}") print(f"Game Name: {game.name}")
print(f"Game ID: {game.id}") print(f"Game ID: {game.id}")
print(f"IGDB ID: {game.igdb_id}") print(f"IGDB ID: {game.igdb_id}")
@@ -28,18 +24,6 @@ async def get_game_id_by_name(game_name: str) -> str:
print(f"No game found with the exact name: '{game_name}'") print(f"No game found with the exact name: '{game_name}'")
return None return None
async def get_twitch():
global SECRETS, TWITCH, USER
if SECRETS is None:
with open('twitch_secrets.json', 'r') as f:
SECRETS = json.load(f)
if TWITCH is None:
TWITCH = await Twitch(SECRETS['client_id'], SECRETS['client_secret'])
if USER is None:
USER = await first(TWITCH.get_users(logins=[CHANNEL_NAME]))
if not USER:
print("User not found.")
async def get_game_name_by_id(game_id: str) -> str: async def get_game_name_by_id(game_id: str) -> str:
"""Helper function to fetch game names and cache them locally.""" """Helper function to fetch game names and cache them locally."""
if not game_id: if not game_id:
@@ -47,7 +31,7 @@ async def get_game_name_by_id(game_id: str) -> str:
if game_id in GAME_CACHE: if game_id in GAME_CACHE:
return GAME_CACHE[game_id] return GAME_CACHE[game_id]
try: try:
game_generator = TWITCH.get_games(game_ids=[game_id]) game_generator = config.TWITCH.get_games(game_ids=[game_id])
game = await first(game_generator) game = await first(game_generator)
if game: if game:
GAME_CACHE[game_id] = game.name GAME_CACHE[game_id] = game.name
@@ -100,10 +84,10 @@ async def get_vod_game_name(vod_id: str):
return game_id, game_name return game_id, game_name
async def get_streamer_vods(): async def get_streamer_vods():
await get_twitch() await config.get_twitch()
print(f"Starting VOD extraction for {USER.display_name}...") print(f"Starting VOD extraction for {config.USER.display_name}...")
vod_generator = TWITCH.get_videos(user_id=USER.id, first=100, video_type=VideoType.ALL) vod_generator = config.TWITCH.get_videos(user_id=config.USER.id, first=100, video_type=VideoType.ALL)
all_vods = [] all_vods = []
@@ -128,7 +112,7 @@ async def get_streamer_vods():
"game_id": clean_game_id, "game_id": clean_game_id,
"game_name": game_name, "game_name": game_name,
"stream_id": str(v.stream_id) if v.stream_id else "0", "stream_id": str(v.stream_id) if v.stream_id else "0",
"creator_name": CHANNEL_NAME, "creator_name": config.CHANNEL_NAME,
"clip_is": False, "clip_is": False,
} }
all_vods.append(vod_data) all_vods.append(vod_data)
@@ -138,10 +122,10 @@ async def get_streamer_vods():
return all_vods return all_vods
async def get_streamer_clips(): async def get_streamer_clips():
await get_twitch() await config.get_twitch()
print(f"Starting clip extraction for {USER.display_name}...") print(f"Starting clip extraction for {config.USER.display_name}...")
clip_generator = TWITCH.get_clips(broadcaster_id=USER.id, first=100) clip_generator = config.TWITCH.get_clips(broadcaster_id=config.USER.id, first=100)
all_clips = [] all_clips = []
async for c in clip_generator: async for c in clip_generator:
@@ -170,11 +154,10 @@ async def get_streamer_clips():
async def main(): async def main():
print("--- Script Started ---") print("--- Script Started ---")
db = database.Database()
vods_list = await get_streamer_vods() vods_list = await get_streamer_vods()
for v in vods_list: for v in vods_list:
db.insert_video_record( DB.insert_video_record(
v['id'], v['title'], v['created_at'], v['view_count'], v['duration'], v['id'], v['title'], v['created_at'], v['view_count'], v['duration'],
v['url'], v['thumbnail_url'], v['game_id'], v['game_name'], v['url'], v['thumbnail_url'], v['game_id'], v['game_name'],
v['stream_id'], v['creator_name'], v['clip_is'] v['stream_id'], v['creator_name'], v['clip_is']
@@ -186,7 +169,7 @@ async def main():
clips_list = await get_streamer_clips() clips_list = await get_streamer_clips()
for v in clips_list: for v in clips_list:
db.insert_video_record( DB.insert_video_record(
v['id'], v['title'], v['created_at'], v['view_count'], v['duration'], v['id'], v['title'], v['created_at'], v['view_count'], v['duration'],
v['url'], v['thumbnail_url'], v['game_id'], v['game_name'], v['url'], v['thumbnail_url'], v['game_id'], v['game_name'],
v['stream_id'], v['creator_name'], v['clip_is'] v['stream_id'], v['creator_name'], v['clip_is']
View File
File renamed without changes.
+24 -86
View File
@@ -1,109 +1,47 @@
aiohappyeyeballs==2.7.1 aiohappyeyeballs==2.7.1
aiohttp==3.14.2 aiohttp==3.14.3
aiosignal==1.4.0 aiosignal==1.4.0
anyio==4.14.2 anyio==4.15.1
attrs==26.1.0 attrs==26.1.0
beautifulsoup4==4.15.0 av==18.1.0
certifi==2026.7.22 certifi==2026.7.22
cffi==2.1.0 charset-normalizer==3.5.1
charset-normalizer==3.4.9 click==8.5.0
chat-downloader==0.2.8 ctranslate2==4.8.2
click==8.4.2
colorlog==6.12.0
cryptography==49.0.0
cuda-bindings==13.3.1
cuda-pathfinder==1.6.0
cuda-toolkit==13.0.3.0
decorator==5.3.1 decorator==5.3.1
defusedxml==0.7.1
docstring_parser==0.18.0
enum-tools==0.13.0 enum-tools==0.13.0
filelock==3.32.0 faster-whisper==1.2.1
filelock==3.32.6
flatbuffers==25.12.19
frozenlist==1.8.0 frozenlist==1.8.0
fsspec==2026.6.0 fsspec==2026.7.0
git-filter-repo==2.47.0
google==3.0.0
google-api-core==2.32.0
google-api-python-client==2.198.0
google-auth==2.56.2
google-auth-httplib2==0.4.0
google-auth-oauthlib==1.4.0
googleapis-common-protos==1.75.0
h11==0.16.0 h11==0.16.0
hf-xet==1.6.0
httpcore==1.0.9 httpcore==1.0.9
httplib2==0.32.0
httpx==0.28.1 httpx==0.28.1
idna==3.18 huggingface_hub==1.31.0
idna==3.19
ImageIO==2.37.4 ImageIO==2.37.4
imageio-ffmpeg==0.6.0 imageio-ffmpeg==0.6.0
isodate==0.7.2
Jinja2==3.1.6
joblib==1.5.3
llvmlite==0.48.0
lxml==6.1.1
MarkupSafe==3.0.3
more-itertools==11.1.0
moviepy==2.2.1 moviepy==2.2.1
mpmath==1.3.0 multidict==6.8.0
multidict==6.7.1 numpy==2.5.3
networkx==3.6.1 onnxruntime==1.30.0
nltk==3.10.0 opencv-python==5.0.0.93
numba==0.66.0 packaging==26.3
numpy==2.4.6
nvidia-cublas==13.1.1.3
nvidia-cuda-cupti==13.0.85
nvidia-cuda-nvrtc==13.0.88
nvidia-cuda-runtime==13.0.96
nvidia-cudnn-cu13==9.20.0.48
nvidia-cufft==12.0.0.61
nvidia-cufile==1.15.1.6
nvidia-curand==10.4.0.35
nvidia-cusolver==12.0.4.66
nvidia-cusparse==12.6.3.3
nvidia-cusparselt-cu13==0.8.1
nvidia-nccl-cu13==2.29.7
nvidia-nvjitlink==13.3.33
nvidia-nvshmem-cu13==3.4.5
nvidia-nvtx==13.0.85
oauthlib==3.3.1
openai-whisper==20250625
outcome==1.3.0.post0
pillow==11.3.0 pillow==11.3.0
pip_system_certs==5.3
proglog==0.1.12 proglog==0.1.12
propcache==0.5.2 propcache==0.5.2
proto-plus==1.28.1 protobuf==7.36.1
protobuf==7.35.1 Pygments==2.21.0
pyasn1==0.6.4
pyasn1_modules==0.4.2
pycountry==26.2.16
pycparser==3.0
pycryptodome==3.23.0
Pygments==2.20.0
pyparsing==3.3.2
PySocks==1.7.1
python-dateutil==2.9.0.post0 python-dateutil==2.9.0.post0
python-dotenv==1.2.2 python-dotenv==1.2.3
regex==2026.7.19 PyYAML==6.0.3
requests==2.34.2 requests==2.34.2
requests-oauthlib==2.0.0
setuptools==83.0.0
six==1.17.0 six==1.17.0
sniffio==1.3.1 tokenizers==0.23.2
sortedcontainers==2.4.0 tqdm==4.70.1
soupsieve==2.9.1
streamlink==8.4.0
sympy==1.14.0
tiktoken==0.13.0
torch==2.13.0
tqdm==4.69.0
trio==0.33.0
trio-websocket==0.12.2
triton==3.7.1
twitchAPI==4.5.0 twitchAPI==4.5.0
typing_extensions==4.16.0 typing_extensions==4.16.0
uritemplate==4.2.0
urllib3==2.7.0 urllib3==2.7.0
websocket-client==1.9.0
wsproto==1.3.2
yarl==1.24.5 yarl==1.24.5
+2 -2
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import os import os
import json import json
import linux import package.utils as utils
import tempfile import tempfile
from pathlib import Path from pathlib import Path
from moviepy import VideoFileClip, ColorClip, CompositeVideoClip from moviepy import VideoFileClip, ColorClip, CompositeVideoClip
@@ -118,7 +118,7 @@ def fit_to_9_16_letterbox(input_path: str, top_text: str = "TOP TEXT", bottom_te
) )
try: try:
linux.run_command(ffmpeg_cmd) utils.run_command(ffmpeg_cmd)
print(f"🎉 High-speed processing complete! Video saved to: {output_path}") print(f"🎉 High-speed processing complete! Video saved to: {output_path}")
finally: finally:
# Clean up temporary PNG picture files safely # Clean up temporary PNG picture files safely