Skip to content

Instantly share code, notes, and snippets.

@warmwaffles
Created October 26, 2020 17:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save warmwaffles/b2d39d52fb7f936c490b8bfe8268e737 to your computer and use it in GitHub Desktop.
Save warmwaffles/b2d39d52fb7f936c490b8bfe8268e737 to your computer and use it in GitHub Desktop.
Organize GoPro Hero7 files.
"""
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