|
|
|
|
@ -1,5 +1,5 @@
|
|
|
|
|
from datetime import datetime, timedelta, timezone
|
|
|
|
|
from VideoManager import get_duration
|
|
|
|
|
from video_manager import get_duration
|
|
|
|
|
import os, json, subprocess, shutil
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -34,14 +34,13 @@ def update_video_data(dataPath, data):
|
|
|
|
|
if existing_data == data:
|
|
|
|
|
return # No update needed if data hasn't changed.
|
|
|
|
|
|
|
|
|
|
data["updatedAt"] = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
|
|
|
data["updated_at"] = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
|
|
|
|
|
|
|
|
with open(dataPath, "w") as f:
|
|
|
|
|
json.dump(data, f) # Write to file if new or if data has changed.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def is_recent(updated_at_str, minutes=30):
|
|
|
|
|
updated_at = format_datetime(updated_at_str)
|
|
|
|
|
def is_recent(updated_at, minutes=30):
|
|
|
|
|
updated_at = updated_at.replace(tzinfo=timezone.utc)
|
|
|
|
|
now = datetime.now(timezone.utc)
|
|
|
|
|
return now - updated_at < timedelta(minutes=minutes)
|
|
|
|
|
@ -104,7 +103,7 @@ def group_videos(video_list, sort_by="count", order="desc"):
|
|
|
|
|
|
|
|
|
|
# Ensure videos for each user and site are sorted by creation date
|
|
|
|
|
for key in video_data:
|
|
|
|
|
video_data[key].sort(key=lambda x: format_datetime(x["createdAt"]))
|
|
|
|
|
video_data[key].sort(key=lambda x: (x["created_at"]))
|
|
|
|
|
|
|
|
|
|
# Further sort groups if required based on size or count
|
|
|
|
|
if sort_by == "size":
|
|
|
|
|
@ -124,8 +123,8 @@ def process_videos(video_data):
|
|
|
|
|
video_path = video["filepath"]
|
|
|
|
|
data_path = video["jsonpath"]
|
|
|
|
|
|
|
|
|
|
if 'size' not in video:
|
|
|
|
|
filesize = get_file_size_in_mb(video_path)
|
|
|
|
|
filesize = get_file_size_in_mb(video_path)
|
|
|
|
|
if 'size' not in video or video['size'] != filesize:
|
|
|
|
|
video['size'] = filesize
|
|
|
|
|
is_updated = True
|
|
|
|
|
|
|
|
|
|
@ -135,8 +134,8 @@ def process_videos(video_data):
|
|
|
|
|
|
|
|
|
|
# Move corrupted videos to the failed folder
|
|
|
|
|
if video['duration'] == 0:
|
|
|
|
|
print(f"{video['videoID']} is corrupted, moving to failed folder")
|
|
|
|
|
failed_video_path = os.path.join(failed_directory, video["videoID"] + ".mp4")
|
|
|
|
|
print(f"{video['video_id']} is corrupted, moving to failed folder")
|
|
|
|
|
failed_video_path = os.path.join(failed_directory, video["video_id"] + ".mp4")
|
|
|
|
|
failed_data_path = failed_video_path.replace(".mp4", ".json")
|
|
|
|
|
|
|
|
|
|
shutil.move(video_path, failed_video_path)
|
|
|
|
|
@ -166,7 +165,7 @@ def group_for_concatenation(videos, time_limit=30):
|
|
|
|
|
reference_params = None # We'll store the 'ffprobe' params for the first video in each group
|
|
|
|
|
|
|
|
|
|
for video in videos:
|
|
|
|
|
video_start = format_datetime(video['createdAt'])
|
|
|
|
|
video_start = (video['created_at'])
|
|
|
|
|
video_end = video_start + timedelta(seconds=video['duration'])
|
|
|
|
|
|
|
|
|
|
# Probe the video to get parameters
|
|
|
|
|
@ -218,7 +217,7 @@ def group_for_concatenation(videos, time_limit=30):
|
|
|
|
|
if concatenated_video_groups:
|
|
|
|
|
last_group = concatenated_video_groups[-1]
|
|
|
|
|
last_video = last_group[-1]
|
|
|
|
|
last_updated_at = datetime.strptime(last_video['createdAt'], "%Y-%m-%d %H:%M:%S")
|
|
|
|
|
last_updated_at = datetime.strptime(last_video['created_at'], "%Y-%m-%d %H:%M:%S")
|
|
|
|
|
if datetime.now() - last_updated_at <= timedelta(minutes=time_limit):
|
|
|
|
|
print(f"Last group is not ready for upload. Removing from final groups.")
|
|
|
|
|
concatenated_video_groups.pop()
|
|
|
|
|
@ -287,10 +286,10 @@ def get_video_params(video_path):
|
|
|
|
|
|
|
|
|
|
def generate_list_file(videos):
|
|
|
|
|
directory = os.path.dirname(videos[0]["filepath"])
|
|
|
|
|
list_filename = os.path.join(directory, f"{videos[0]['videoID']}.txt")
|
|
|
|
|
list_filename = os.path.join(directory, f"{videos[0]['video_id']}.txt")
|
|
|
|
|
with open(list_filename, "w") as list_file:
|
|
|
|
|
for video in videos:
|
|
|
|
|
list_file.write(f"file '{video['videoID']}.mp4'\n")
|
|
|
|
|
list_file.write(f"file '{video['video_id']}.mp4'\n")
|
|
|
|
|
return list_filename
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -398,4 +397,54 @@ def calculate_file_hash(file_path):
|
|
|
|
|
import hashlib
|
|
|
|
|
with open(file_path, 'rb') as f:
|
|
|
|
|
data = f.read()
|
|
|
|
|
return hashlib.sha256(data).hexdigest()
|
|
|
|
|
return hashlib.sha256(data).hexdigest()
|
|
|
|
|
|
|
|
|
|
def group_for_concatenation_simple(videos, time_limit=60):
|
|
|
|
|
"""
|
|
|
|
|
Groups videos into lists where:
|
|
|
|
|
- total group size <= 9GB (9216 MB),
|
|
|
|
|
- time gap between consecutive videos <= time_limit minutes,
|
|
|
|
|
- AND all have the same resolution/fps/codecs for no-reencode concat.
|
|
|
|
|
"""
|
|
|
|
|
concatenated_video_groups = []
|
|
|
|
|
current_group = []
|
|
|
|
|
current_size_mb = 0
|
|
|
|
|
last_video_end = None
|
|
|
|
|
|
|
|
|
|
for video in videos:
|
|
|
|
|
video_start = video['created_at']
|
|
|
|
|
video_end = video_start + timedelta(seconds=video['duration'])
|
|
|
|
|
|
|
|
|
|
if current_group:
|
|
|
|
|
# Check if adding this video breaks the size limit
|
|
|
|
|
time_difference = (video_start - last_video_end).total_seconds() / 60
|
|
|
|
|
size_exceeded = (current_size_mb + video['size'] > 9216)
|
|
|
|
|
time_exceeded = (time_difference > time_limit)
|
|
|
|
|
|
|
|
|
|
# If we exceed size, exceed time gap, or mismatch in parameters => start new group
|
|
|
|
|
if size_exceeded or time_exceeded:
|
|
|
|
|
concatenated_video_groups.append(current_group)
|
|
|
|
|
current_group = []
|
|
|
|
|
current_size_mb = 0
|
|
|
|
|
|
|
|
|
|
# Add the current video to the group
|
|
|
|
|
current_group.append(video)
|
|
|
|
|
current_size_mb += video['size']
|
|
|
|
|
last_video_end = video_end
|
|
|
|
|
|
|
|
|
|
# Add the last group if not empty
|
|
|
|
|
if current_group:
|
|
|
|
|
concatenated_video_groups.append(current_group)
|
|
|
|
|
|
|
|
|
|
# Optional: Ensure the last group is "ready" for upload based on time difference
|
|
|
|
|
if concatenated_video_groups:
|
|
|
|
|
last_group = concatenated_video_groups[-1]
|
|
|
|
|
last_video = last_group[-1]
|
|
|
|
|
last_updated_at = last_video['created_at']
|
|
|
|
|
if datetime.now() - last_updated_at <= timedelta(minutes=time_limit):
|
|
|
|
|
print(f"Last group is not ready for upload. Removing from final groups.")
|
|
|
|
|
concatenated_video_groups.pop()
|
|
|
|
|
|
|
|
|
|
concatenated_video_groups = [group for group in concatenated_video_groups if len(group) > 1]
|
|
|
|
|
|
|
|
|
|
return concatenated_video_groups
|