Created
October 26, 2020 17:34
-
-
Save warmwaffles/b2d39d52fb7f936c490b8bfe8268e737 to your computer and use it in GitHub Desktop.
Organize GoPro Hero7 files.
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
""" | |
Works primarily only with GoPro Hero 7 at the moment. | |
GoPro has a really weird naming scheme and terrible pattern for timelapse and | |
videos. This tool helps move files into a usable / navigable directory. | |
""" | |
import argparse | |
import os | |
import re | |
import sys | |
from pathlib import Path | |
FORMATS = { | |
"hero7": { | |
"timelapse": re.compile(r"(G(\d{3})(\d{4}))\.(\w{3})"), | |
"video": re.compile(r"(GH(\d{2})(\d{4}))\.(\w{3})"), | |
}, | |
} | |
def str_to_bool(v): | |
if isinstance(v, bool): | |
return v | |
if v.lower() in ('yes', 'true', 't', 'y', '1'): | |
return True | |
elif v.lower() in ('no', 'false', 'f', 'n', '0'): | |
return False | |
else: | |
raise argparse.ArgumentTypeError('Boolean value expected.') | |
parser = argparse.ArgumentParser(description="Organizes go pro files") | |
parser.add_argument("working_dir", type=str, help="the directory that needs files to be organized", default=".") | |
parser.add_argument("--timelapse-dir", type=str, help="the directory to store timelapse files", default="./timelapse") | |
parser.add_argument("--video-dir", type=str, help="the directory to store video files", default="./videos") | |
parser.add_argument("--dry-run", type=str_to_bool, help="don't modify files, only show modifications", nargs='?', const=True, default=False,) | |
parser.add_argument("--model", type=str, help="the model of go pro used", default="hero7") | |
args = parser.parse_args() | |
working_dir = Path(args.working_dir).resolve() | |
video_dir = Path(args.video_dir).resolve() | |
timelapse_dir = Path(args.timelapse_dir).resolve() | |
if not FORMATS.get(args.model): | |
sys.exit(f"Unsupported go pro model \"{model}\"") | |
print(f"model: {args.model}") | |
print(f"working dir: {working_dir}") | |
print(f"video dir: {video_dir}") | |
print(f"timelapse dir: {timelapse_dir}") | |
# ------------------------------------------------------------------------------ | |
# Organize Videos | |
# ------------------------------------------------------------------------------ | |
if not args.dry_run: | |
video_dir.mkdir(exist_ok=True) | |
for path in list(working_dir.glob("*GOPRO/*.MP4")): | |
regex = FORMATS[args.model]["video"] | |
match = regex.match(path.name) | |
if not match: | |
continue | |
filename = match.group(1) | |
chapter = match.group(2) | |
number = match.group(3) | |
ext = match.group(4) | |
new_path = Path(video_dir, f"{number} {chapter}.{ext}") | |
print(f"Rename {path} => {new_path}") | |
if not args.dry_run: | |
path.rename(new_path) | |
for path in list(working_dir.glob("*GOPRO/*.LRV")): | |
print(f"Remove {path}") | |
if not args.dry_run: | |
path.unlink(missing_ok=True) | |
for path in list(working_dir.glob("*GOPRO/*.THM")): | |
print(f"Remove {path}") | |
if not args.dry_run: | |
path.unlink(missing_ok=True) | |
# ------------------------------------------------------------------------------ | |
# Organize Timelapse | |
# ------------------------------------------------------------------------------ | |
if not args.dry_run: | |
timelapse_dir.mkdir(exist_ok=True) | |
timelapse_files = {} | |
for path in list(working_dir.glob("*GOPRO/*.JPG")): | |
regex = FORMATS[args.model]["timelapse"] | |
match = regex.match(path.name) | |
if not match: | |
continue | |
group_number = match.group(2) | |
file_number = match.group(3) | |
ext = match.group(4) | |
group_dir = Path(timelapse_dir, group_number) | |
new_path = Path(group_dir, f"{file_number}.{ext}") | |
if not group_dir.exists(): | |
print(f"Create {group_dir}") | |
print(f"Rename {path} => {new_path}") | |
if not args.dry_run: | |
group_dir.mkdir(exist_ok=True) | |
path.rename(Path(group_dir, path.name)) | |
for path in list(working_dir.glob("*GOPRO")): | |
if not path.is_dir(): | |
continue | |
if len([f for f in path.iterdir()]) == 0: | |
print(f"Remove {path}") | |
if not args.dry_run: | |
path.rmdir() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment