Skip to content

Instantly share code, notes, and snippets.

@iwalton3
Last active April 2, 2020 17:46
Show Gist options
  • Save iwalton3/a484879495aad3b81c42b4910fa88b15 to your computer and use it in GitHub Desktop.
Save iwalton3/a484879495aad3b81c42b4910fa88b15 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python3
import sys
import subprocess
from align_videos_by_soundtrack.align import SyncDetector, cli_common
remove = []
remove_specified = False
remove_all = False
add = []
add_specified = False
copy_subtitles = False
files = []
print_offset_only = False
for argument in sys.argv[1:]:
if argument == "-copy-subtitles":
copy_subtitles = True
elif argument == "-print-offset-only":
print_offset_only = True
elif argument.startswith("-"):
if argument == "-all":
remove_all = True
else:
remove_specified = True
remove = argument[1:].split(",")
elif argument.startswith("+"):
add_specified = True
add = argument[1:].split(",")
else:
files.append(argument)
if print_offset_only:
main_src, audio_src = files
destination = None
else:
main_src, audio_src, destination = files
cli_common.logger_config()
with SyncDetector() as det:
result = det.align([audio_src, main_src])
offset = 0
if result[0]["trim"] > 0:
offset = int(-result[0]["trim"]*1000)
else:
offset = int(result[0]["pad"]*1000)
arguments = ["mkvmerge","-o",destination,"-D","-B","-T"]
if not copy_subtitles:
arguments.extend(["-S","-M"])
if add_specified:
arguments.extend(["-a",",".join(add)])
arguments.extend(["-y", "-1:" + str(offset), audio_src])
if remove_specified:
arguments.extend(["-a","!"+(",".join(remove))])
elif remove_all:
arguments.append("-A")
arguments.append(main_src)
if print_offset_only:
print(offset)
else:
print("Sync: {0}".format(offset))
subprocess.check_call(arguments)
#!/usr/bin/env python3
import sys
import subprocess
import json
fname = sys.argv[1]
def sign_weight(text):
if not text:
return 0
lower_text = text.lower()
has_songs = "op/ed" in lower_text or "song" in lower_text or "lyric" in lower_text
has_signs = "sign" in lower_text
custom = "[" in lower_text or "(" in lower_text
vendor = "bd" in lower_text or "retail" in lower_text
weight = 900
if not (has_songs or has_signs):
return 0
if has_songs:
weight -= 200
if has_signs:
weight -= 300
if custom:
weight -= 100
if vendor:
weight += 50
return weight
metadata = json.loads(subprocess.check_output(["mkvmerge","-J",fname]).decode())
is_english = False
sign_track = None
sign_track_weight = 1000
forced_uid = None
for track in metadata["tracks"]:
props = track["properties"]
if track["type"] == "audio" and props["language"] == "eng":
is_english = True
if track["type"] == "subtitles":
if props.get("language") == "eng":
untagged = False
eng_subs = True
elif "english" in (props.get("track_name") or "").lower():
untagged = True
eng_subs = True
else:
untagged = False
eng_subs = False
weight = sign_weight(props.get("track_name"))
if weight and eng_subs:
if sign_track_weight > weight:
sign_track_weight = weight
sign_track = props["uid"]
if props["forced_track"]:
if forced_uid != None:
print("Fatal error",fname,"Multiple forced tracks!")
sys.exit(1)
forced_uid = props["uid"]
if not is_english:
print("Skipping file",fname,"Not in english!")
sys.exit(0)
if forced_uid != None and sign_track == forced_uid:
print("Skipping file",fname,"Already forced.")
sys.exit(0)
if sign_track == None:
print("Skipping file",fname,"No sign track.")
sys.exit(0)
if forced_uid != None:
print("Remove forced",fname,forced_uid)
subprocess.Popen(["mkvpropedit",fname,"--edit","track:="+str(forced_uid),"--set","flag-forced=false"])
print("Set forced",fname,sign_track)
subprocess.Popen(["mkvpropedit",fname,"--edit","track:="+str(sign_track),"--set","flag-forced=true"])
#!/usr/bin/env python3
import sys
import subprocess
import json
import shutil
import os.path
import os
import random
fname = sys.argv[1]
metadata = json.loads(subprocess.check_output(["mkvmerge","-J",fname]).decode())
permitted_locales = {None, 'und', 'eng', 'jpn', 'mis', 'mul', 'zxx'}
saved_audio_tracks = []
saved_subtitle_tracks = []
has_bad_tracks = False
for track in metadata["tracks"]:
props = track["properties"]
if track["type"] == "audio":
if props["language"] in permitted_locales:
saved_audio_tracks.append(str(track["id"]))
else:
has_bad_tracks = True
print("Discard audio: #{0} {1} ({2})".format(track["id"], props.get("track_name"), props.get("language")))
elif track["type"] == "subtitles":
if props["language"] in permitted_locales:
saved_subtitle_tracks.append(str(track["id"]))
else:
has_bad_tracks = True
print("Discard subtitle: #{0} {1} ({2})".format(track["id"], props.get("track_name"), props.get("language")))
if has_bad_tracks:
if len(saved_audio_tracks) == 0:
print("File {0} would have no audio tracks!".format(fname))
sys.exit(1)
tempfile = "_temp_{0}.mkv".format(random.randint(0,1000000))
options = ["mkvmerge","-o",tempfile,
"-a",",".join(saved_audio_tracks)]
if len(saved_subtitle_tracks) == 0:
options.append("-S")
else:
options.extend(["-s", ",".join(saved_subtitle_tracks)])
options.append(fname)
subprocess.check_call(options)
orig_size = os.path.getsize(fname)
new_size = os.path.getsize(tempfile)
if orig_size * 0.75 > new_size:
print("File {0} is too small after conversion.".format(fname))
os.remove(tempfile)
sys.exit(1)
print("Moving file {0}...".format(fname))
shutil.move(fname, fname+".bak")
try:
shutil.move(tempfile, fname)
except Exception:
print("File {0} could not be moved.".format(fname))
shutil.move(fname+".bak", fname)
if os.path.isfile(fname+".bak"):
os.remove(fname+".bak")
print("Size reduced {0} MiB ({1:n}%)".format((orig_size-new_size)//(1024**2), 100-(new_size*100//orig_size)))
else:
print("File {0} is already minified!".format(fname))
#!/usr/bin/env python3
from plexapi.myplex import MyPlexAccount
import sys
account = MyPlexAccount('USERNAME', 'PASSWORD')
print("Connecting...")
plex = account.resource('SERVERNAME').connect()
shows = None
for library in plex.library.sections():
if library.type == "show":
if shows == None:
shows = library
else:
print("Multiple show libraries. Please hardcode it with plex.library.sectionByID.")
sys.exit(1)
if len(sys.argv) < 2:
print("Usage: [series] [subbed/dubbed]")
sys.exit(1)
series = sys.argv[1]
mode = sys.argv[2]
search = shows.search(series)
if len(search) == 1:
show = search[0]
elif len(search) == 0:
print("No show found.")
sys.exit(1)
else:
for i, show in enumerate(search):
print("%s: %s" % (i, show.title))
index = int(input("# "))
show = search[index]
def check_subtitles_full(subtitles, retry_flag=False):
for subtitle in subtitles:
if subtitle.languageCode != "eng":
continue
title = (subtitle.title or "").lower()
if "sign" in title or "commentary" in title:
continue
if "Forced" in subtitle._data.get("displayTitle"):
continue
return subtitle
return None
def check_subtitles_forced(subtitles):
selected_subtitles = None
for subtitle in subtitles:
if subtitle.languageCode != "eng":
continue
if not "Forced" in subtitle._data.get("displayTitle"):
continue
return subtitle
return None
def process_media(part, debug_name, mode):
is_english = False
english_audio = None
japanese_audio = None
for audio in part.audioStreams():
if audio.languageCode == "eng" and english_audio == None:
is_english = True
english_audio = audio
elif audio.languageCode == "jpn" and japanese_audio == None:
japanese_audio = audio
if not is_english:
print("Skipping: %s is not in English." % debug_name)
return
if mode == "dubbed":
subtitles = check_subtitles_forced(part.subtitleStreams())
if subtitles != None:
sid = subtitles.id
else:
sid = 0
print("Set dubbed: %s" % debug_name)
plex.query('/library/parts/%s?audioStreamID=%s&allParts=1' % (part.id, english_audio.id),method=plex._session.put)
plex.query('/library/parts/%s?subtitleStreamID=%s&allParts=1' % (part.id, sid),method=plex._session.put)
elif mode == "subbed":
if japanese_audio == None:
print("Skipping: %s is English only." % debug_name)
return
subtitles = check_subtitles_full(part.subtitleStreams())
if subtitles == None:
print("Skipping: %s has no subtitles." % debug_name)
return
sid = subtitles.id
print("Set subbed: %s (%s)" % (debug_name,subtitles.title))
plex.query('/library/parts/%s?audioStreamID=%s&allParts=1' % (part.id, japanese_audio.id),method=plex._session.put)
plex.query('/library/parts/%s?subtitleStreamID=%s&allParts=1' % (part.id, sid),method=plex._session.put)
for season in show.seasons():
for episode in season.episodes():
debug_name = "S%02iE%02i" % (season.index, episode.index)
episode = episode.reload()
medias = episode.media
if len(medias) > 1:
print("Warning: %s has multiple media files." % debug_name)
for media in medias:
parts = media.parts
if len(parts) > 1:
print("Warning: %s has multiple media parts." % debug_name)
for part in parts:
process_media(part, debug_name, mode)
#!/bin/bash
i=0
paste <(ls subtitle) <(ls video) | column -ts $'\t'
read -p "Please confirm the numbering is correct. [y/N] " verify
if [[ ! "$verify" =~ [yY] ]]
then
echo "Aborted!"
exit 1
fi
paste <(ls subtitle) <(ls video) | while IFS=$'\t' read -r s v
do
((i++))
out="$(sed -e 's/\.[^.]\+$/.mkv/g' <<< "$s")"
if [[ ! -e "$out" ]]
then
if [[ -e "$i.txt" ]]
then
rm "CHECKME_$out"
offset=$(cat "$i.txt")
else
ffmpeg -loglevel quiet -nostdin -y -i subtitle/"$s" subtmp.srt < /dev/null
offset=$(subsync video/"$v" -i subtmp.srt 2>&1 1>/dev/null | grep 'offset seconds' | sed 's/.*: /1000*/g' | bc | sed 's/\..*//g')
echo "Sync: $offset"
rm subtmp.srt
if [[ "${offset#-}" -gt "20000" ]]
then
echo "Sync using subtitles failed. Trying audio sync..."
offset=$(audio-transfer.py -print-offset-only video/"$v" subtitle/"$s")
echo "Sync: $offset"
if [[ "${offset#-}" -gt "20000" ]] || [[ "$offset" == "" ]]
then
echo "Sync failure!"
echo "Please write $i.txt"
echo "$i" >> failed.txt
out="CHECKME_$out"
offset=0
fi
fi
fi
mkvmerge -o "$out" -A -D -B -T -y "-1:$offset" subtitle/"$s" video/"$v"
fi
done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment