Last active
August 25, 2023 11:53
-
-
Save Deathproof76/fdc283c77d9e4f1d532bfe71314df0d2 to your computer and use it in GitHub Desktop.
Find all defective video files (mp4/mkv/avi) with ffprobe in directory and subfoldes with "moov atom not found" in error_output or "Invalid data found when processing input" and print full path to txt file
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import os | |
import subprocess | |
import time | |
import sys | |
import select | |
# Detailed introductory message | |
print("DESCRIPTION:") | |
print("------------") | |
print("This script will recursively search the current directory and its subdirectories for video files with extensions .mp4, .mkv, and .avi.") | |
print("Each video file will be checked using 'ffprobe', a tool from the FFmpeg suite, to determine its integrity.") | |
print("The script deems a video file as 'defective' if 'ffprobe' returns an error containing 'moov atom not found' or 'Invalid data found when processing input'.") | |
print("Defective files will have their full system path written immediately to 'defect_files.txt' in the directory where the script was executed.") | |
print("All unique ffprobe errors will be logged to 'ffprobe_errors.txt'.") | |
print("\nStarting in:") | |
# 15-second countdown | |
def countdown(seconds): | |
for i in range(seconds, 0, -1): | |
# Check if there's input on stdin (i.e., a keypress) | |
i, o, e = select.select([sys.stdin], [], [], 1) | |
if i: | |
sys.stdin.readline() # Clear the input buffer | |
break | |
print(f"{i} seconds...") | |
time.sleep(1) | |
countdown(15) | |
# Get a list of all video files in the current directory and subdirectories | |
video_extensions = ['.mp4', '.mkv', '.avi'] | |
video_files = [os.path.join(root, file) | |
for root, dirs, files in os.walk('.') | |
for file in files if os.path.splitext(file)[1] in video_extensions] | |
defective_files = [] | |
unique_errors = set() | |
# Check each video file with ffprobe | |
for index, video_file in enumerate(video_files, start=1): | |
print(f"Checking file {index}/{len(video_files)}: {video_file}") | |
try: | |
subprocess.run(['ffprobe', video_file], stderr=subprocess.PIPE, stdout=subprocess.PIPE, check=True) | |
except subprocess.CalledProcessError as e: | |
error_output = e.stderr.decode('utf-8') | |
unique_errors.add(error_output.strip()) # Add error message to the set of unique errors | |
if "moov atom not found" in error_output or "Invalid data found when processing input" in error_output: | |
defective_files.append(os.path.abspath(video_file)) | |
# Write unique ffprobe errors to a log file | |
with open('ffprobe_errors.txt', 'w') as f: | |
for error in unique_errors: | |
f.write(error + '\n\n') | |
# Write all defective file paths to defect_files.txt, each on a new line | |
with open('defect_files.txt', 'w') as f: | |
for file in defective_files: | |
f.write(file + '\n') | |
# Write all defective file paths to defect_files_one_line.txt in a single line | |
with open('defect_files_one_line.txt', 'w') as f: | |
f.write(' '.join(defective_files)) | |
print(f"Finished checking. Found {len(defective_files)} defective files.") | |
print(f"Check 'defect_files.txt' and 'defect_files_one_line.txt' for lists of defective files, and 'ffprobe_errors.txt' for a log of unique errors.") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Google Takeout broke a lot of videos in my case, found out late. This helped me identify them. Just put the check_videos.py script in relevant folder make executable. Have ffprobe on path, do "python check_videos.py" and it checks all files in the folder and subfolders and it will output three txt files with the full filepath of affected files. One with only full path of files with errors regarding "moov atom not found" in ffprobe error_output or "Invalid data found when processing input", another with the same but in a single line and one with the full ffprobe error output (to doublecheck).