new scripts and cleanup

main
oscar 1 month ago
parent a69468f555
commit 2a7cd821c1

@ -0,0 +1,65 @@
print("Importing modules...")
from funcs import group_videos, group_for_concatenation_simple
from video_funcs import concatenate_videos
import os, config, shutil
MOVE_FUCKED = False
sort_type = {"size": lambda x: sum([video['size'] for video in x]),"count": lambda x: len(x)}
def get_videos(cursor, username=None):
if username:
cursor.execute("SELECT * FROM videos WHERE username = %s AND status != 'missing' ORDER BY created_at DESC", (username,))
else:
cursor.execute("SELECT * FROM videos WHERE status != 'missing' ORDER BY created_at DESC")
return cursor.fetchall()
def organize_videos():
username = input("Enter username: ")
conn, cursor = config.get_local_db_connection()
videos = get_videos(cursor, username)
# process the videos
video_data = group_videos(videos, sort_by="size", order="asc")
# group all videos for concatation first.
grouped_videos = []
for user, videos in video_data.items():
grouped_videos.extend(group_for_concatenation_simple(videos))
sorted_processed_videos = sorted(grouped_videos, key=sort_type["size"], reverse=True)
# group the videos for concatenation
for video_list in sorted_processed_videos:
first_video = video_list[0]
video_id = os.path.splitext(os.path.basename(first_video['filepath']))[0]
videos_sum_size = sum([video['size'] for video in video_list])
print(100*"=")
print("\n"*2)
print(f"Group {video_id} has {len(video_list)} videos and total size of {videos_sum_size} MB")
print("\n"*2)
print(100*"=")
main_video = concatenate_videos(video_list)
if main_video:
print(f"Processed {len(video_list)} input videos into {main_video["filepath"]} output video.")
continue
if MOVE_FUCKED:
print(f"Videos are fucked.")
main_video = video_list[0]
video_name = main_video['videoID']
fucked_dir = os.path.join("concate_fucked", video_name)
os.makedirs(fucked_dir, exist_ok=True)
for video in video_list:
shutil.move(video['filepath'], os.path.join(fucked_dir, os.path.basename(video['filepath'])))
if __name__ == "__main__":
organize_videos()

@ -0,0 +1,201 @@
import ffmpeg
import subprocess
import json
from collections import Counter
import shutil
import os
def is_av1(filepath):
"""Check if a video file is already AV1-encoded."""
try:
probe = ffmpeg.probe(filepath)
for stream in probe['streams']:
if stream['codec_type'] == 'video' and 'codec_name' in stream:
if stream['codec_name'] == 'av1':
return True
except ffmpeg.Error as e:
print(f"Error probing {filepath}: {e}")
return False
def get_video_info(filepath):
"""
Returns (bitrate_in_kbps, (width, height)) for the specified video file.
If probing fails, returns (None, (None, None)).
"""
try:
probe = ffmpeg.probe(filepath)
format_info = probe['format']
video_stream = next(
(stream for stream in probe['streams'] if stream['codec_type'] == 'video'),
None
)
if video_stream:
# Convert from bits/sec to kbps
bitrate_kbps = int(format_info['bit_rate']) // 1000
width = video_stream['width']
height = video_stream['height']
return bitrate_kbps, (width, height)
except ffmpeg.Error as e:
print(f"Error getting video info for {filepath}: {e}")
return None, (None, None)
def get_fps(filepath):
"""Get the frames per second (FPS) of the input video using ffmpeg.probe."""
try:
probe = ffmpeg.probe(filepath)
video_stream = next((s for s in probe['streams'] if s['codec_type'] == 'video'), None)
if video_stream and 'r_frame_rate' in video_stream:
fps_str = video_stream['r_frame_rate'] # e.g. "30/1", "25/1"
num, den = map(int, fps_str.split('/'))
return num / den
except ffmpeg.Error as e:
print(f"Error getting FPS for {filepath}: {e}")
return None
def get_video_metadata(video_path):
"""Minimal example to get width/height from FFprobe directly via subprocess."""
cmd = [
"ffprobe", "-v", "error", "-select_streams", "v:0",
"-show_entries", "stream=width,height,bit_rate",
"-of", "json", video_path
]
result = subprocess.run(cmd, capture_output=True, text=True)
if result.returncode != 0:
return {"width": 0, "height": 0, "bit_rate": 0}
try:
data = json.loads(result.stdout)
streams = data.get("streams", [])
if not streams:
return {"width": 0, "height": 0, "bit_rate": 0}
stream = streams[0]
width = int(stream.get("width", 0))
height = int(stream.get("height", 0))
br = int(stream.get("bit_rate", 0)) # in bits per second
return {"width": width, "height": height, "bit_rate": br}
except json.JSONDecodeError:
return {"width": 0, "height": 0, "bit_rate": 0}
def get_target_resolution(group):
"""Collect the most common resolution from the group's videos."""
resolutions = []
for v in group:
meta = get_video_metadata(v["filepath"])
width, height = meta["width"], meta["height"]
if width > 0 and height > 0:
resolutions.append((width, height))
if not resolutions:
return (1280, 720)
counter = Counter(resolutions)
return counter.most_common(1)[0][0] # (width, height)
def get_target_bitrate(width, height):
"""Your existing function to choose a bitrate based on resolution."""
resolutions = {(854, 480): 1000,(1280, 720): 1500,(1920, 1080): 3000,(2560, 1440): 5000,(3840, 2160): 12000}
for res, bitrate in resolutions.items():
if width <= res[0] and height <= res[1]:
return bitrate
return 2500
def concatenate_videos(videos_list, reencode_concate = False):
"""
Concatenate pre-grouped videos, then re-encode them using AV1 (NVENC)
while forcing a unified resolution and frame rate on each input
before final concatenation in one ffmpeg command.
"""
if len(videos_list) <= 1:
return False
from concat_helper import copy_concatenate_videos
copy_concat = copy_concatenate_videos(videos_list)
if copy_concat:
return copy_concat
if not reencode_concate:
return False
main_video = videos_list[0]
video_path = main_video["filepath"]
os.makedirs("temp", exist_ok=True)
os.makedirs("concated", exist_ok=True)
temp_path = os.path.join("temp", os.path.basename(video_path))
output_path = os.path.join("concated", os.path.basename(video_path))
current_bitrate, (width, height) = get_video_info(videos_list[0]['filepath'])
target_width, target_height = get_target_resolution(videos_list)
target_bitrate_kbps = get_target_bitrate(target_width, target_height)
if target_bitrate_kbps > current_bitrate:
target_bitrate_kbps = current_bitrate
max_bitrate_kbps = int(1.5 * target_bitrate_kbps)
fps_float = get_fps(video_path)
if fps_float is None or fps_float <= 0:
print(f"Could not determine FPS for {video_path}. Using default keyframe interval of 30.")
fps_float = 30.0
keyframe_interval = int(fps_float)
print(f"Concatenating {len(videos_list)} videos into {temp_path}")
print(f" Mode Resolution: {target_width}x{target_height}")
print(f" Target Bitrate: {target_bitrate_kbps}k (max ~{max_bitrate_kbps}k)")
print(f" Keyframe Interval: {keyframe_interval}")
cmd = ["ffmpeg", "-y"] # Overwrite output if exists
for v in videos_list:
cmd.extend(["-i", v["filepath"]])
filter_statements = []
concat_streams = []
n = len(videos_list)
unified_fps = 30
for i in range(n):
filter_statements.append(
f"[{i}:v]fps={unified_fps},scale={target_width}:{target_height}[v{i}]"
)
concat_streams.append(f"[v{i}][{i}:a]")
# Example final: [v0][0:a][v1][1:a]concat=n=2:v=1:a=1[outv][outa]
concat_line = "".join(concat_streams) + f"concat=n={n}:v=1:a=1[outv][outa]"
filter_statements.append(concat_line)
filter_complex = ";".join(filter_statements)
cmd.extend([
"-filter_complex", filter_complex,
"-map", "[outv]",
"-map", "[outa]",
"-c:v", "av1_nvenc",
"-b:v", f"{target_bitrate_kbps}k",
"-maxrate", f"{max_bitrate_kbps}k",
"-bufsize", f"{max_bitrate_kbps}k",
"-preset", "p5",
"-g", str(keyframe_interval),
"-c:a", "aac",
"-b:a", "192k",
temp_path
])
try:
subprocess.run(cmd, check=True)
except:
return False
for video in videos_list:
os.remove(video["filepath"])
shutil.move(temp_path, output_path)
return main_video
def get_file_size_in_mb(file_path):
return os.path.getsize(file_path) / (1024 * 1024)
Loading…
Cancel
Save