Skip to content

Commit 89e5792

Browse files
Merge pull request #975 from StepaniaH/master
Add a new script of rename-videos-pictures.py
2 parents 789b2f9 + 80a19a9 commit 89e5792

File tree

1 file changed

+127
-0
lines changed

1 file changed

+127
-0
lines changed
+127
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
#!/usr/bin/env python3
2+
3+
# Required parameters:
4+
# @raycast.schemaVersion 1
5+
# @raycast.title Rename Video
6+
# @raycast.mode fullOutput
7+
8+
# Optional parameters:
9+
# @raycast.icon 📂
10+
# @raycast.argument1 { "type": "text", "placeholder": "Directory's absolute path", "optional": false }
11+
# @raycast.argument2 { "type": "text", "placeholder": "Type (video/image/all)", "optional": true }
12+
# @raycast.argument3 { "type": "text", "placeholder": "Dry Run (true/false)", "optional": true }
13+
14+
# Documentation:
15+
# @raycast.description This is a simple Python script for recursively renaming video and picture files within a directory. Type the root directory's absolute path, and it will scan all the video and picture files in it and rename them according to the folder where they are located as the format `<folder_name>-<current_date (MMDD)>-<incremental_number>`.
16+
# @raycast.author StepaniaH
17+
# @raycast.authorURL https://github.com/StepaniaH
18+
19+
import os
20+
import sys
21+
import datetime
22+
import argparse
23+
import re
24+
25+
class RenameFilesAsDate:
26+
def __init__(self, root_directory):
27+
self.root_directory = os.path.expanduser(root_directory)
28+
self.error_files = {}
29+
self.video_extensions = ('.mp4', '.avi', '.mov', '.mkv', '.wmv', '.flv', '.webm', '.m4v', '.3gp')
30+
self.image_extensions = ('.jpg', '.jpeg', '.png', '.gif', '.webp', '.bmp', '.tiff', '.svg', '.heic')
31+
32+
def rename_files(self, file_type='all', dry_run=False):
33+
current_date = datetime.datetime.now().strftime("%m%d")
34+
self._process_directory(self.root_directory, current_date, file_type, dry_run)
35+
36+
if self.error_files:
37+
print("\nThe following files could not be renamed:")
38+
for original_path, error in self.error_files.items():
39+
print(f"{original_path}: {error}")
40+
41+
def _is_already_renamed(self, filename, current_date):
42+
"""Check if the file has been named according to the target format"""
43+
base_name = os.path.splitext(filename)[0]
44+
pattern = re.compile(f'^.*-{current_date}-\\d+$')
45+
return bool(pattern.match(base_name))
46+
47+
def _get_max_sequence_number(self, directory, current_date):
48+
"""Get the largest serial number existing in the current directory"""
49+
max_seq = 0
50+
pattern = re.compile(f'^.*-{current_date}-(\\d+)$')
51+
52+
for entry in os.listdir(directory):
53+
match = pattern.match(os.path.splitext(entry)[0])
54+
if match:
55+
seq_num = int(match.group(1))
56+
max_seq = max(max_seq, seq_num)
57+
return max_seq
58+
59+
def _process_directory(self, directory, current_date, file_type, dry_run):
60+
folder_name = os.path.basename(directory)
61+
supported_extensions = self._get_supported_extensions(file_type)
62+
63+
# First collect the files that need to be renamed
64+
files_to_rename = []
65+
for entry in os.listdir(directory):
66+
entry_path = os.path.join(directory, entry)
67+
68+
if os.path.isfile(entry_path):
69+
if entry.lower().endswith(supported_extensions):
70+
if not self._is_already_renamed(entry, current_date):
71+
files_to_rename.append(entry)
72+
elif os.path.isdir(entry_path):
73+
self._process_directory(entry_path, current_date, file_type, dry_run)
74+
75+
if files_to_rename:
76+
# Get the largest serial number existing in the current directory
77+
count = self._get_max_sequence_number(directory, current_date) + 1
78+
total_files = len(files_to_rename)
79+
num_digits = len(str(total_files + count - 1))
80+
81+
# Rename collected files
82+
for entry in sorted(files_to_rename): # Sort to ensure consistent rename order
83+
entry_path = os.path.join(directory, entry)
84+
new_name = f"{folder_name}-{current_date}-{count:0{num_digits}d}{os.path.splitext(entry)[1].lower()}"
85+
new_path = os.path.join(directory, new_name)
86+
87+
if dry_run:
88+
print(f"Would rename: {entry} -> {new_name}")
89+
else:
90+
try:
91+
os.rename(entry_path, new_path)
92+
print(f"Renamed: {entry} -> {new_name}")
93+
except OSError as e:
94+
self.error_files[entry_path] = f"Rename failed: {str(e)}"
95+
continue
96+
count += 1
97+
98+
def _get_supported_extensions(self, file_type):
99+
if file_type == 'video':
100+
return self.video_extensions
101+
elif file_type == 'image':
102+
return self.image_extensions
103+
return self.video_extensions + self.image_extensions
104+
105+
def main():
106+
args = sys.argv[1:]
107+
108+
directory = None
109+
file_type = 'all'
110+
dry_run = False
111+
112+
if len(args) >= 1:
113+
directory = args[0]
114+
if len(args) >= 2 and args[1]:
115+
file_type = args[1]
116+
if len(args) >= 3 and args[2]:
117+
dry_run = args[2].lower() == 'true'
118+
119+
if not directory:
120+
print("Error: Directory argument is required.")
121+
sys.exit(1)
122+
123+
renamer = RenameFilesAsDate(directory)
124+
renamer.rename_files(file_type, dry_run)
125+
126+
if __name__ == '__main__':
127+
main()

0 commit comments

Comments
 (0)