-
Notifications
You must be signed in to change notification settings - Fork 0
/
magicrenamer.py
149 lines (120 loc) · 5.91 KB
/
magicrenamer.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
import os
import subprocess
import sys
import stat
import datetime
import re
from PyQt5.QtCore import QThread
def get_resource_path(relative_path):
""" Get absolute path to resource, works for dev and for PyInstaller """
try:
base_path = sys._MEIPASS
except Exception:
base_path = os.path.abspath(".")
if 'exiftool' in relative_path or 'ffmpeg' in relative_path:
return os.path.basename(relative_path)
# Add .exe extension if running on Windows
if sys.platform == "win32" and ('exiftool' in relative_path or 'ffmpeg' in relative_path):
relative_path += '.exe'
# For macOS and Linux, ensure 'exiftool' is in a subdirectory
elif 'exiftool' in relative_path and sys.platform != "win32":
relative_path = os.path.join('exiftool', relative_path)
full_path = os.path.join(base_path, relative_path)
if 'exiftool' in relative_path:
st = os.stat(full_path)
os.chmod(full_path, st.st_mode | stat.S_IEXEC)
return full_path
def get_metadata(file_path):
if sys.platform == "darwin": # If the host machine is macOS
exiftool_path = os.path.join(sys._MEIPASS, 'exiftool', 'exiftool') # Use the bundled exiftool
else:
exiftool_path = get_resource_path('exiftool')
create_date_command = [exiftool_path, '-CreateDate', '-s', '-s', '-s', file_path]
duration_command = [exiftool_path, '-Duration', '-s', '-s', '-s', file_path]
create_date_result = subprocess.run(create_date_command, capture_output=True, text=True, creationflags=(subprocess.CREATE_NO_WINDOW if sys.platform == "win32" else 0))
duration_result = subprocess.run(duration_command, capture_output=True, text=True, creationflags=(subprocess.CREATE_NO_WINDOW if sys.platform == "win32" else 0))
if create_date_result.returncode != 0 or duration_result.returncode != 0:
print(f"Error reading metadata for {file_path}")
return None, None
return create_date_result.stdout.strip(), duration_result.stdout.strip()
def calculate_new_timestamp(create_date, duration):
'''Calculates a new timestamp by subtracting the duration from the create date.'''
create_date_dt = datetime.datetime.strptime(create_date, "%Y:%m:%d %H:%M:%S")
# Check if duration is in the format of decimal seconds
if " s" in duration:
duration_seconds = float(duration.replace(" s", ""))
else:
# Assuming the duration is in the format "H:MM:SS"
hours, minutes, seconds = map(int, duration.split(":"))
duration_seconds = hours * 3600 + minutes * 60 + seconds
duration_td = datetime.timedelta(seconds=duration_seconds)
new_timestamp = create_date_dt - duration_td
return new_timestamp.strftime("%m-%d-%Y_%H-%M-%S")
def get_video_duration(file_path):
ffmpeg_path = get_resource_path("ffmpeg")
if sys.platform == "win32":
command = f'{ffmpeg_path} -i "{file_path}" 2>&1 | find "Duration"'
else:
command = f'{ffmpeg_path} -i "{file_path}" 2>&1 | grep "Duration"'
#result = subprocess.run(command, shell=True, capture_output=True, text=True)
result = subprocess.run(command, shell=True, capture_output=True, text=True, creationflags=(subprocess.CREATE_NO_WINDOW if sys.platform == "win32" else 0))
start = result.stdout.index("Duration: ")
duration = result.stdout[start+10:start+21]
h, m, s = duration.split(':')
return int(h) * 3600 + int(m) * 60 + float(s)
def cliporder_rename(directory):
# Regex pattern to match date and time in filename
pattern = re.compile(r"(\d{2}-\d{2}-\d{4}_\d{2}-\d{2}-\d{2})")
# List to store tuples of (datetime, filename)
files = []
for filename in os.listdir(directory):
match = pattern.search(filename)
if match:
dt = datetime.datetime.strptime(match.group(1), "%m-%d-%Y_%H-%M-%S")
files.append((dt, filename))
# Sort files by datetime
files.sort()
# Rename files
for i, (_, filename) in enumerate(files, start=1):
base, ext = os.path.splitext(filename)
new_filename = f"CLIP{i}_{base}{ext}"
os.rename(os.path.join(directory, filename), os.path.join(directory, new_filename))
class MagicRenamerThread(QThread):
def __init__(self, output_folder_path, parent=None):
super().__init__(parent)
self.directory = output_folder_path
def run(self):
process_files(self.directory)
def process_files(directory):
'''Renames .MOV files based on their CreateDate minus Duration, marks short .mp4 files and long .mp4 files, and then reorders all files.'''
if not directory:
return
# List to store tuples of (new_name, old_name)
files = []
for filename in os.listdir(directory):
file_path = os.path.join(directory, filename)
if filename.lower().endswith(".mov"):
create_date, duration = get_metadata(file_path)
if create_date and duration:
new_name = calculate_new_timestamp(create_date, duration) + '_COVERT.MOV'
files.append((new_name, filename))
elif filename.lower().endswith(".mp4"):
duration = get_video_duration(file_path)
base, ext = os.path.splitext(filename) # Get the filename without extension
# Remove existing clip number and tags from base name
base = re.sub(r'^CLIP\d+_', '', base)
base = re.sub(r'_INTEGRITY$', '', base)
base = re.sub(r'_CLAIMANT$', '', base)
if duration < 20:
new_name = base + "_INTEGRITY" + ext
files.append((new_name, filename))
elif duration >= 20:
new_name = base + "_CLAIMANT" + ext
files.append((new_name, filename))
# Sort files by new name
files.sort()
# Rename files
for new_name, old_name in files:
os.rename(os.path.join(directory, old_name), os.path.join(directory, new_name))
# Add clip order to file name
cliporder_rename(directory)