From 2de2c461e2a69ff42c52c3d5c6cb45440b5d1be9 Mon Sep 17 00:00:00 2001 From: SumGuyV5 Date: Fri, 11 Sep 2026 20:08:26 +0000 Subject: [PATCH] rearange files and updateing files --- .../twitch_down_uploader.py | 6 +- .../twitch_download_clips.py | 2 +- .../twitch_download_vod.py | 0 vod_clip.py => delete/vod_clip.py | 0 void_ID.py => delete/void_ID.py | 0 auth_twitch.py => helper_files/auth_twitch.py | 0 helper_files/datetime_fix.py | 63 ++++++++++ helper_files/fix_download.py | 52 +++++++++ import_vod.py => helper_files/import_vod.py | 6 +- .../migrate_sql1.py | 0 move_vod.py => helper_files/move_vod.py | 2 +- .../redownload_clips.py | 2 +- .../remove_uneed_files.py | 2 +- main.py | 16 +-- package/__init__.py | 35 ++++++ build_videos.py => package/build_videos.py | 12 +- package/config.py | 6 + database.py => package/database.py | 7 ++ .../transcribe_video.py | 1 - package/twitch/__init__.py | 15 +++ .../twitch/chat_vod.py | 12 +- package/twitch/config.py | 24 ++++ .../twitch/download_thumbnails.py | 32 ++--- .../twitch/download_videos.py | 13 +-- .../twitch/video_info.py | 51 +++----- linux.py => package/utils.py | 0 requirements.txt | 110 ++++-------------- youtube_short.py | 4 +- 28 files changed, 285 insertions(+), 188 deletions(-) rename twitch_down_uploader.py => delete/twitch_down_uploader.py (99%) rename twitch_download_clips.py => delete/twitch_download_clips.py (99%) mode change 100755 => 100644 rename twitch_download_vod.py => delete/twitch_download_vod.py (100%) rename vod_clip.py => delete/vod_clip.py (100%) rename void_ID.py => delete/void_ID.py (100%) rename auth_twitch.py => helper_files/auth_twitch.py (100%) create mode 100644 helper_files/datetime_fix.py create mode 100644 helper_files/fix_download.py rename import_vod.py => helper_files/import_vod.py (95%) rename migrate_sql1.py => helper_files/migrate_sql1.py (100%) rename move_vod.py => helper_files/move_vod.py (97%) rename redownload_clips.py => helper_files/redownload_clips.py (94%) rename remove_uneed_files.py => helper_files/remove_uneed_files.py (98%) create mode 100644 package/__init__.py rename build_videos.py => package/build_videos.py (93%) create mode 100644 package/config.py rename database.py => package/database.py (95%) rename transcribe_video.py => package/transcribe_video.py (99%) create mode 100644 package/twitch/__init__.py rename twitch_chat_vod.py => package/twitch/chat_vod.py (94%) create mode 100644 package/twitch/config.py rename twitch_download_thumbnails.py => package/twitch/download_thumbnails.py (86%) rename twitch_download_videos.py => package/twitch/download_videos.py (93%) rename twitch_video_info.py => package/twitch/video_info.py (82%) rename linux.py => package/utils.py (100%) diff --git a/twitch_down_uploader.py b/delete/twitch_down_uploader.py similarity index 99% rename from twitch_down_uploader.py rename to delete/twitch_down_uploader.py index e6b6e6b..5ccd47f 100755 --- a/twitch_down_uploader.py +++ b/delete/twitch_down_uploader.py @@ -1,16 +1,16 @@ #!/usr/bin/env python3 import requests import os -import linux +import package.linux as linux import time -from database import Database +from package.database import Database import uploader from uploader import CategoryId import youtube_hashtags -import transcribe_video +import package.transcribe_video as transcribe_video CHANNEL_NAME = 'teampgp' # Replace with the streamer's username DB = None diff --git a/twitch_download_clips.py b/delete/twitch_download_clips.py old mode 100755 new mode 100644 similarity index 99% rename from twitch_download_clips.py rename to delete/twitch_download_clips.py index 4514655..96339a7 --- a/twitch_download_clips.py +++ b/delete/twitch_download_clips.py @@ -3,7 +3,7 @@ import requests import subprocess from datetime import datetime -from database import Database +from package.database import Database import uploader from uploader import CategoryId diff --git a/twitch_download_vod.py b/delete/twitch_download_vod.py similarity index 100% rename from twitch_download_vod.py rename to delete/twitch_download_vod.py diff --git a/vod_clip.py b/delete/vod_clip.py similarity index 100% rename from vod_clip.py rename to delete/vod_clip.py diff --git a/void_ID.py b/delete/void_ID.py similarity index 100% rename from void_ID.py rename to delete/void_ID.py diff --git a/auth_twitch.py b/helper_files/auth_twitch.py similarity index 100% rename from auth_twitch.py rename to helper_files/auth_twitch.py diff --git a/helper_files/datetime_fix.py b/helper_files/datetime_fix.py new file mode 100644 index 0000000..1b1df86 --- /dev/null +++ b/helper_files/datetime_fix.py @@ -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() \ No newline at end of file diff --git a/helper_files/fix_download.py b/helper_files/fix_download.py new file mode 100644 index 0000000..0b0ea3c --- /dev/null +++ b/helper_files/fix_download.py @@ -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() \ No newline at end of file diff --git a/import_vod.py b/helper_files/import_vod.py similarity index 95% rename from import_vod.py rename to helper_files/import_vod.py index a65768c..304aae3 100644 --- a/import_vod.py +++ b/helper_files/import_vod.py @@ -4,8 +4,8 @@ import json import asyncio from pathlib import Path -import database -import twitch_video_info +import package.database as database +import package.twitch.video_info as video_info DB = None def format_to_hms(total_seconds): @@ -44,7 +44,7 @@ def read_json(file_path: str): 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( video_id, diff --git a/migrate_sql1.py b/helper_files/migrate_sql1.py similarity index 100% rename from migrate_sql1.py rename to helper_files/migrate_sql1.py diff --git a/move_vod.py b/helper_files/move_vod.py similarity index 97% rename from move_vod.py rename to helper_files/move_vod.py index f4cb0a5..f1c165b 100644 --- a/move_vod.py +++ b/helper_files/move_vod.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -import database +import package.database as database from pathlib import Path DB = None diff --git a/redownload_clips.py b/helper_files/redownload_clips.py similarity index 94% rename from redownload_clips.py rename to helper_files/redownload_clips.py index 65f0aad..ae9b782 100644 --- a/redownload_clips.py +++ b/helper_files/redownload_clips.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -import database +import package.database as database DB = None diff --git a/remove_uneed_files.py b/helper_files/remove_uneed_files.py similarity index 98% rename from remove_uneed_files.py rename to helper_files/remove_uneed_files.py index 4f0cc6a..02a4f6a 100644 --- a/remove_uneed_files.py +++ b/helper_files/remove_uneed_files.py @@ -1,6 +1,6 @@ import os -import database +import package.database as database DB = None diff --git a/main.py b/main.py index 32bc6f2..7c46cda 100644 --- a/main.py +++ b/main.py @@ -1,23 +1,23 @@ #!/usr/bin/env python3 import asyncio -import twitch_video_info -import twitch_download_videos -import twitch_download_thumbnails +import package.twitch.video_info as video_info +import package.twitch.download_videos as download_videos +import package.twitch.download_thumbnails as download_thumbnails -import build_videos +import package.build_videos as build_videos if __name__ == "__main__": # Get Twitch Video Info - asyncio.run(twitch_video_info.main()) + asyncio.run(video_info()) # Download Twitch Videos - twitch_download_videos.main() + download_videos() - twitch_download_thumbnails.main() + download_thumbnails() #Build - build_videos.main() + build_videos() print("====================================================") print(f"✅ Done.") diff --git a/package/__init__.py b/package/__init__.py new file mode 100644 index 0000000..5979208 --- /dev/null +++ b/package/__init__.py @@ -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", +] diff --git a/build_videos.py b/package/build_videos.py similarity index 93% rename from build_videos.py rename to package/build_videos.py index 7a195de..3b17f18 100644 --- a/build_videos.py +++ b/package/build_videos.py @@ -1,10 +1,8 @@ #!/usr/bin/env python3 -import database import youtube_short -import transcribe_video -import twitch_chat_vod - -DB = None +import package.transcribe_video as transcribe_video +import package.twitch.chat_vod as chat_vod +from package.config import DB as DB def build_chat_video(): chats = DB.get_unuploaded_chats() @@ -33,7 +31,7 @@ def build_chat_video(): print(f"🚀 Chat Video: {title}") 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(f"✅ Processing: Chat Video Done.") @@ -117,8 +115,6 @@ def build_shorts(): print("====================================================") def main(): - global DB - DB = database.Database() build_shorts() build_transcribe() build_chat_video() diff --git a/package/config.py b/package/config.py new file mode 100644 index 0000000..12214d3 --- /dev/null +++ b/package/config.py @@ -0,0 +1,6 @@ +#!/usr/bin/env python3 +import package.database as database + +CHANNEL_NAME = "teampgp" + +DB = database.Database() \ No newline at end of file diff --git a/database.py b/package/database.py similarity index 95% rename from database.py rename to package/database.py index 96abb45..fb7c308 100755 --- a/database.py +++ b/package/database.py @@ -80,6 +80,13 @@ class Database: """Flags a specific row record to 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]: """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}") diff --git a/transcribe_video.py b/package/transcribe_video.py similarity index 99% rename from transcribe_video.py rename to package/transcribe_video.py index 5a5b6f5..829acd2 100755 --- a/transcribe_video.py +++ b/package/transcribe_video.py @@ -1,6 +1,5 @@ #!/usr/bin/env python3 import os -import sys import shutil import subprocess from pathlib import Path diff --git a/package/twitch/__init__.py b/package/twitch/__init__.py new file mode 100644 index 0000000..93975c7 --- /dev/null +++ b/package/twitch/__init__.py @@ -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", +] diff --git a/twitch_chat_vod.py b/package/twitch/chat_vod.py similarity index 94% rename from twitch_chat_vod.py rename to package/twitch/chat_vod.py index 450a1aa..752b386 100644 --- a/twitch_chat_vod.py +++ b/package/twitch/chat_vod.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 import os import cv2 -import linux +import package.utils as utils def get_video_height(video_path: str) -> int: # Open the video file @@ -86,13 +86,15 @@ def combine_twitch_vod_and_chat(vod_path: str, layout: str = "side-by-side", for chat_cmd = (f"{chat_cmd} --generate-mask ") 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: print("✅ Success: TwitchDownloaderCLI render chat video.") else: print("❌ Error: TwitchDownloaderCLI failed to render chat video.") - os.remove(temp_chat) - os.remove(mask_path) + if os.path.exists(temp_chat): + os.remove(temp_chat) + if os.path.exists(mask_path): + os.remove(mask_path) return False # Step 3: Combine Video and Chat using FFmpeg @@ -119,7 +121,7 @@ def combine_twitch_vod_and_chat(vod_path: str, layout: str = "side-by-side", for else: 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 if ffmpeg_success and os.path.exists(temp_with_chat): diff --git a/package/twitch/config.py b/package/twitch/config.py new file mode 100644 index 0000000..5cd3bd8 --- /dev/null +++ b/package/twitch/config.py @@ -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.") \ No newline at end of file diff --git a/twitch_download_thumbnails.py b/package/twitch/download_thumbnails.py similarity index 86% rename from twitch_download_thumbnails.py rename to package/twitch/download_thumbnails.py index 65a5bbb..8787f1f 100644 --- a/twitch_download_thumbnails.py +++ b/package/twitch/download_thumbnails.py @@ -1,30 +1,12 @@ +#!/usr/bin/env python3 import os -import json import asyncio import requests -from twitchAPI.twitch import Twitch + from twitchAPI.helper import first -import 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.") - +import package.config as config +import package.database as database 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.""" @@ -100,12 +82,12 @@ def save_image(url: str, filename: str, stream: bool = True): async def main(): # Initialize connection & automatically authorize the App token - await get_twitch() - twitch = TWITCH # Twitch(APP_ID, APP_SECRET) + await config.get_twitch() + twitch = config.TWITCH # Twitch(APP_ID, APP_SECRET) # --- OPTION A: Download Live Thumbnail --- # 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) # --- OPTION B: Download Past Broadcast VOD Thumbnail --- diff --git a/twitch_download_videos.py b/package/twitch/download_videos.py similarity index 93% rename from twitch_download_videos.py rename to package/twitch/download_videos.py index db48d3c..7db60ab 100755 --- a/twitch_download_videos.py +++ b/package/twitch/download_videos.py @@ -3,11 +3,8 @@ import csv import subprocess from datetime import datetime, timedelta, timezone -import linux -from database import Database - -CHANNEL_NAME = 'teampgp' -DB = None +import package.utils as utils +from package.config import DB as DB def write_csv(data, file_name): # Open file with newline='' to prevent extra blank rows across platforms @@ -78,8 +75,8 @@ def download(): csv_file = f"{target_dir}/{id}.csv" # 3. FIXED: Use the live streaming function to prevent Out-Of-Memory crashes - output = linux.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]"]) + output = utils.run_command(cmd, 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: # Only write CSV and update database if download actually completed @@ -100,8 +97,6 @@ def download(): print("Finished Downloading Pipeline.") def main(): - global DB - DB = Database() download() if __name__ == "__main__": diff --git a/twitch_video_info.py b/package/twitch/video_info.py similarity index 82% rename from twitch_video_info.py rename to package/twitch/video_info.py index 1964973..4b9df06 100755 --- a/twitch_video_info.py +++ b/package/twitch/video_info.py @@ -1,25 +1,21 @@ #!/usr/bin/env python3 import asyncio -import json import httpx # Switched from requests to prevent async loop freezing -import database -from twitchAPI.twitch import Twitch + from twitchAPI.helper import first from twitchAPI.type import VideoType -SECRETS = None -TWITCH = None -USER = None +import package.twitch.config as config +from package.config import DB as DB + 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: - if SECRETS is None: - await get_twitch() + if config.SECRETS is None: + await config.get_twitch() # Query the 'get_games' endpoint using the names parameter # 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 ID: {game.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}'") 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: """Helper function to fetch game names and cache them locally.""" 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: return GAME_CACHE[game_id] 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) if game: GAME_CACHE[game_id] = game.name @@ -100,10 +84,10 @@ async def get_vod_game_name(vod_id: str): return game_id, game_name async def get_streamer_vods(): - await get_twitch() + await config.get_twitch() - print(f"Starting VOD extraction for {USER.display_name}...") - vod_generator = TWITCH.get_videos(user_id=USER.id, first=100, video_type=VideoType.ALL) + print(f"Starting VOD extraction for {config.USER.display_name}...") + vod_generator = config.TWITCH.get_videos(user_id=config.USER.id, first=100, video_type=VideoType.ALL) all_vods = [] @@ -128,7 +112,7 @@ async def get_streamer_vods(): "game_id": clean_game_id, "game_name": game_name, "stream_id": str(v.stream_id) if v.stream_id else "0", - "creator_name": CHANNEL_NAME, + "creator_name": config.CHANNEL_NAME, "clip_is": False, } all_vods.append(vod_data) @@ -138,10 +122,10 @@ async def get_streamer_vods(): return all_vods async def get_streamer_clips(): - await get_twitch() + await config.get_twitch() - print(f"Starting clip extraction for {USER.display_name}...") - clip_generator = TWITCH.get_clips(broadcaster_id=USER.id, first=100) + print(f"Starting clip extraction for {config.USER.display_name}...") + clip_generator = config.TWITCH.get_clips(broadcaster_id=config.USER.id, first=100) all_clips = [] async for c in clip_generator: @@ -170,11 +154,10 @@ async def get_streamer_clips(): async def main(): print("--- Script Started ---") - db = database.Database() vods_list = await get_streamer_vods() 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['url'], v['thumbnail_url'], v['game_id'], v['game_name'], v['stream_id'], v['creator_name'], v['clip_is'] @@ -186,7 +169,7 @@ async def main(): clips_list = await get_streamer_clips() 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['url'], v['thumbnail_url'], v['game_id'], v['game_name'], v['stream_id'], v['creator_name'], v['clip_is'] diff --git a/linux.py b/package/utils.py similarity index 100% rename from linux.py rename to package/utils.py diff --git a/requirements.txt b/requirements.txt index 6798acf..7578def 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,109 +1,47 @@ aiohappyeyeballs==2.7.1 -aiohttp==3.14.2 +aiohttp==3.14.3 aiosignal==1.4.0 -anyio==4.14.2 +anyio==4.15.1 attrs==26.1.0 -beautifulsoup4==4.15.0 +av==18.1.0 certifi==2026.7.22 -cffi==2.1.0 -charset-normalizer==3.4.9 -chat-downloader==0.2.8 -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 +charset-normalizer==3.5.1 +click==8.5.0 +ctranslate2==4.8.2 decorator==5.3.1 -defusedxml==0.7.1 -docstring_parser==0.18.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 -fsspec==2026.6.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 +fsspec==2026.7.0 h11==0.16.0 +hf-xet==1.6.0 httpcore==1.0.9 -httplib2==0.32.0 httpx==0.28.1 -idna==3.18 +huggingface_hub==1.31.0 +idna==3.19 ImageIO==2.37.4 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 -mpmath==1.3.0 -multidict==6.7.1 -networkx==3.6.1 -nltk==3.10.0 -numba==0.66.0 -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 +multidict==6.8.0 +numpy==2.5.3 +onnxruntime==1.30.0 +opencv-python==5.0.0.93 +packaging==26.3 pillow==11.3.0 -pip_system_certs==5.3 proglog==0.1.12 propcache==0.5.2 -proto-plus==1.28.1 -protobuf==7.35.1 -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 +protobuf==7.36.1 +Pygments==2.21.0 python-dateutil==2.9.0.post0 -python-dotenv==1.2.2 -regex==2026.7.19 +python-dotenv==1.2.3 +PyYAML==6.0.3 requests==2.34.2 -requests-oauthlib==2.0.0 -setuptools==83.0.0 six==1.17.0 -sniffio==1.3.1 -sortedcontainers==2.4.0 -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 +tokenizers==0.23.2 +tqdm==4.70.1 twitchAPI==4.5.0 typing_extensions==4.16.0 -uritemplate==4.2.0 urllib3==2.7.0 -websocket-client==1.9.0 -wsproto==1.3.2 yarl==1.24.5 diff --git a/youtube_short.py b/youtube_short.py index 2d9d241..9f9d957 100755 --- a/youtube_short.py +++ b/youtube_short.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 import os import json -import linux +import package.utils as utils import tempfile from pathlib import Path 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: - linux.run_command(ffmpeg_cmd) + utils.run_command(ffmpeg_cmd) print(f"🎉 High-speed processing complete! Video saved to: {output_path}") finally: # Clean up temporary PNG picture files safely