Skip to content

Instantly share code, notes, and snippets.

@zored
Last active July 25, 2025 18:31
Show Gist options
  • Save zored/affd83622ccba7c77e00c9b432dee417 to your computer and use it in GitHub Desktop.
Save zored/affd83622ccba7c77e00c9b432dee417 to your computer and use it in GitHub Desktop.
Video rename (with Deno) and convertion from h.265 to h.264 (with ffmpeg)

How I move files from iPhone to Google Drive

  • Preparation.
  • Copy files to computer using 3uTools.
  • Rename files with Deno:
deno run -A --unstable rename.ts save-renames
deno run -A --unstable rename.ts rename
  • Remove .WEBP files because they are trash.
  • Run ./heic.sh to convert HEIC to JPEG.
  • Move video files:
mkdir -p ./video
mv *.MP4 *.MOV ./video
  • Run ./convert.sh.
  • Wait for million years.
  • Check ./video_x264 and remove ./video.
  • Review media collection
    • Use Filter UI.
    • 2 seconds videos are live videos from photos. Review them separately if needed.
  • Send results to cloud storage.
#!/bin/bash
set -e
pushd video
mkdir -p ../video_x264
for f in *; do
ffmpeg -i "${f}" -c:v libx264 -crf 18 -c:a copy "../video_x264/${f}"
done
#!/bin/bash
# Create the dislike/heic directory if it doesn't exist
mkdir -p ./dislike/heic
# Loop through all HEIC files in the current directory
for file in *.HEIC *.heic; do
# Skip if no HEIC files are found
[ -e "$file" ] || continue
# Get filename without extension
filename="${file%.*}"
# Convert to high-quality JPG
magick "$file" -quality 100 "${filename}.jpg"
# Move original HEIC to dislike/heic
mv "$file" ./dislike/heic/
echo "Converted $file to ${filename}.jpg and moved original to ./dislike/heic/"
done
echo "Conversion complete. Originals moved to ./dislike/heic/"
import { walkSync } from "https://deno.land/[email protected]/fs/mod.ts";
const renamesFile = "renames.json";
let renames: [string, string][];
function fillId(id: ImageId | null, d: Date | null, p: string): null | ImageId {
if (!d) {
return id;
}
if (id == null) {
return null;
}
const zero = (v: number): string => (v < 10 ? "0" : "") + v;
const extensionMatches = p.match(/.*\.(?<ext>.*)$/i);
return {
path: p,
year: id?.year || d.getFullYear() + "",
month: id?.month || zero(d.getMonth() + 1),
date: id?.date || zero(d.getDate()),
hours: id?.hours || zero(d.getHours()),
minutes: id?.minutes || zero(d.getMinutes()),
version: id?.version || "0000",
extension: id?.extension || (extensionMatches?.groups?.ext ?? ""),
};
}
interface ImageId {
path: string;
year: string;
month: string;
date: string;
hours: string;
minutes: string;
version: string;
extension: string;
}
function getImageId(p: string): null | ImageId {
const patterns = [
// My iPhone:
/(?<year>\d{4})_(?<month>\d{2})_(?<date>\d{2})_(?<hours>\d{2})_(?<minutes>\d{2})_IMG_(?<version>\d{4})\.(?<ext>[^.]*)$/i,
// Others:
/(img|vid)_(?<year>\d{4})(?<month>\d{2})(?<date>\d{2})_(?<hours>\d{2})(?<minutes>\d{2})(?<version>\d{2}(_\d+)?)\.(?<ext>[^.]*)$/i,
/(img|vid)_(?<version>\d+)\.(?<ext>[^.]+)$/i,
];
const g = patterns.map((v) => p.match(v)).find((v) => !!v)?.groups;
if (!g) {
return null;
}
return {
path: p,
year: g.year || "",
month: g.month || "",
date: g.date || "",
hours: g.hours || "",
minutes: g.minutes || "",
version: g.version || "",
extension: g.extension || "",
};
}
switch (Deno.args[0]) {
case "save-renames":
renames = [...walkSync(".")]
.map((e) => e.path)
.map((p): null | ImageId =>
fillId(getImageId(p), Deno.statSync(p).birthtime, p)
)
.filter((id): id is ImageId => id !== null)
.map((
{ year, month, date, hours, minutes, version, extension, path },
) => [
path,
`${year}-${month}-${date} ${hours}-${minutes} ${version}.${extension.toUpperCase()}`,
]);
await Deno.writeTextFile(renamesFile, JSON.stringify(renames));
console.log(`Saved to ${renamesFile}.`);
break;
case "rename":
renames = JSON.parse(await Deno.readTextFile(renamesFile));
renames.forEach(([before, after]) => Deno.renameSync(before, after));
console.log(`Renamed ${renames.length} file(s).`);
break;
default:
console.log("?");
Deno.exit(1);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment