2019-08-25 00:40:39 +02:00
|
|
|
import logging
|
2016-03-22 22:36:39 +01:00
|
|
|
import os
|
2021-09-22 20:43:53 +02:00
|
|
|
import pathlib
|
2017-01-15 12:29:40 +01:00
|
|
|
import platform
|
2018-03-03 16:11:23 +01:00
|
|
|
import re
|
2021-09-22 20:43:53 +02:00
|
|
|
import sys
|
2019-08-25 00:40:39 +02:00
|
|
|
from json import dumps
|
|
|
|
from random import sample
|
|
|
|
from shutil import which
|
2016-03-22 22:36:39 +01:00
|
|
|
|
2019-08-25 00:40:39 +02:00
|
|
|
from requests import codes
|
|
|
|
from requests import post
|
|
|
|
from requests import Timeout
|
2018-05-13 01:44:21 +02:00
|
|
|
from svtplay_dl.utils.output import formatname
|
2018-06-24 23:17:02 +02:00
|
|
|
from svtplay_dl.utils.proc import run_program
|
2021-06-13 01:22:16 +02:00
|
|
|
from svtplay_dl.utils.stream import subtitle_filter
|
2016-03-22 22:36:39 +01:00
|
|
|
|
|
|
|
|
2019-08-25 00:33:51 +02:00
|
|
|
class postprocess:
|
2018-05-13 01:44:00 +02:00
|
|
|
def __init__(self, stream, config, subfixes=None):
|
2016-03-22 22:36:39 +01:00
|
|
|
self.stream = stream
|
2018-05-13 01:44:00 +02:00
|
|
|
self.config = config
|
2021-06-13 01:22:16 +02:00
|
|
|
self.subfixes = [x.subfix for x in subtitle_filter(subfixes)]
|
2016-03-30 18:18:43 +02:00
|
|
|
self.detect = None
|
2016-03-22 23:00:50 +01:00
|
|
|
for i in ["ffmpeg", "avconv"]:
|
|
|
|
self.detect = which(i)
|
|
|
|
if self.detect:
|
|
|
|
break
|
2021-09-22 20:43:53 +02:00
|
|
|
if self.detect is None and platform.system() == "Windows":
|
|
|
|
path = pathlib.Path(sys.executable).parent / "ffmpeg.exe"
|
2021-10-30 14:24:44 +02:00
|
|
|
if os.path.isfile(path):
|
2021-09-22 20:43:53 +02:00
|
|
|
self.detect = path
|
2016-03-22 23:00:50 +01:00
|
|
|
|
2016-03-26 21:38:31 +01:00
|
|
|
def merge(self):
|
2016-03-30 18:18:43 +02:00
|
|
|
if self.detect is None:
|
2018-11-18 12:47:19 +01:00
|
|
|
logging.error("Cant detect ffmpeg or avconv. Cant mux files without it.")
|
2016-03-26 21:38:31 +01:00
|
|
|
return
|
|
|
|
if self.stream.finished is False:
|
|
|
|
return
|
2016-06-20 18:33:42 +02:00
|
|
|
|
2021-05-03 01:43:37 +02:00
|
|
|
orig_filename = formatname(self.stream.output, self.config)
|
|
|
|
ext = orig_filename.suffix
|
2021-06-25 09:52:25 +02:00
|
|
|
new_name = orig_filename.with_suffix(f".{self.config.get('output_format')}")
|
2021-05-03 01:43:37 +02:00
|
|
|
|
2019-09-23 22:53:51 +02:00
|
|
|
if ext == ".ts":
|
2021-05-03 01:43:37 +02:00
|
|
|
audio_filename = orig_filename.with_suffix(".audio.ts")
|
2019-09-23 22:53:51 +02:00
|
|
|
else:
|
2021-05-03 01:43:37 +02:00
|
|
|
audio_filename = orig_filename.with_suffix(".m4a")
|
2019-09-23 22:53:51 +02:00
|
|
|
|
2020-12-06 18:56:52 +01:00
|
|
|
cmd = [self.detect]
|
|
|
|
if self.config.get("only_video") or not self.config.get("only_audio"):
|
2021-05-10 20:51:55 +02:00
|
|
|
cmd += ["-i", str(orig_filename)]
|
2021-06-13 01:22:16 +02:00
|
|
|
if self.stream.audio and self.config.get("only_audio") or not self.config.get("only_video"):
|
2021-05-10 20:51:55 +02:00
|
|
|
cmd += ["-i", str(audio_filename)]
|
2018-03-03 16:11:23 +01:00
|
|
|
_, stdout, stderr = run_program(cmd, False) # return 1 is good here.
|
2019-09-15 17:31:49 +02:00
|
|
|
streams = _streams(stderr)
|
|
|
|
videotrack, audiotrack = _checktracks(streams)
|
2018-03-03 16:11:23 +01:00
|
|
|
|
2018-05-13 01:44:00 +02:00
|
|
|
if self.config.get("merge_subtitle"):
|
2021-06-13 01:22:16 +02:00
|
|
|
logging.info(f"Merge audio, video and subtitle into {new_name.name}")
|
2016-06-20 18:33:42 +02:00
|
|
|
else:
|
2021-06-13 01:22:16 +02:00
|
|
|
logging.info(f"Merge audio and video into {new_name.name}")
|
2017-01-02 21:09:35 +01:00
|
|
|
|
2021-05-03 01:43:37 +02:00
|
|
|
tempfile = orig_filename.with_suffix(".temp")
|
2021-06-25 09:52:25 +02:00
|
|
|
arguments = ["-c:v", "copy", "-c:a", "copy", "-f", "matroska" if self.config.get("output_format") == "mkv" else "mp4"]
|
2018-03-06 21:48:37 +01:00
|
|
|
if ext == ".ts":
|
2019-09-15 17:31:49 +02:00
|
|
|
if audiotrack and "aac" in _getcodec(streams, audiotrack):
|
2019-09-14 14:17:45 +02:00
|
|
|
arguments += ["-bsf:a", "aac_adtstoasc"]
|
2021-06-13 01:22:16 +02:00
|
|
|
|
2020-12-06 18:56:52 +01:00
|
|
|
cmd = [self.detect]
|
|
|
|
if self.config.get("only_video") or not self.config.get("only_audio"):
|
2021-05-10 20:51:55 +02:00
|
|
|
cmd += ["-i", str(orig_filename)]
|
2021-06-13 01:22:16 +02:00
|
|
|
if (self.stream.audio and self.config.get("only_audio")) or (self.stream.audio and not self.config.get("only_video")):
|
2021-05-10 20:51:55 +02:00
|
|
|
cmd += ["-i", str(audio_filename)]
|
2019-09-14 14:17:45 +02:00
|
|
|
if videotrack:
|
2021-02-28 22:05:15 +01:00
|
|
|
arguments += ["-map", f"{videotrack}"]
|
2019-09-14 14:17:45 +02:00
|
|
|
if audiotrack:
|
2021-02-28 22:05:15 +01:00
|
|
|
arguments += ["-map", f"{audiotrack}"]
|
2018-05-13 01:44:00 +02:00
|
|
|
if self.config.get("merge_subtitle"):
|
2019-09-15 19:00:38 +02:00
|
|
|
langs = _sublanguage(self.stream, self.config, self.subfixes)
|
2019-09-14 22:44:44 +02:00
|
|
|
tracks = [x for x in [videotrack, audiotrack] if x]
|
2021-07-05 17:45:17 +02:00
|
|
|
subs_nr = 0
|
|
|
|
sub_start = 0
|
|
|
|
# find what sub track to start with. when a/v is in one file it start with 1
|
|
|
|
# if seperate it will start with 2
|
|
|
|
for i in tracks:
|
|
|
|
if int(i[0]) >= sub_start:
|
|
|
|
sub_start += 1
|
|
|
|
for stream_num, language in enumerate(langs, start=sub_start):
|
2019-08-25 00:27:31 +02:00
|
|
|
arguments += [
|
|
|
|
"-map",
|
2021-07-05 17:45:17 +02:00
|
|
|
f"{str(stream_num)}:0",
|
|
|
|
"-c:s:" + str(subs_nr),
|
2021-06-25 09:52:25 +02:00
|
|
|
"mov_text" if self.config.get("output_format") == "mp4" else "copy",
|
2021-07-05 17:45:17 +02:00
|
|
|
"-metadata:s:s:" + str(subs_nr),
|
2019-08-25 00:27:31 +02:00
|
|
|
"language=" + language,
|
|
|
|
]
|
2021-07-05 17:45:17 +02:00
|
|
|
subs_nr += 1
|
2021-06-13 01:22:16 +02:00
|
|
|
if self.subfixes and self.config.get("get_all_subtitles"):
|
2016-06-20 18:33:42 +02:00
|
|
|
for subfix in self.subfixes:
|
2021-05-09 21:51:48 +02:00
|
|
|
subfile = orig_filename.parent / (orig_filename.stem + "." + subfix + ".srt")
|
2021-05-10 20:51:55 +02:00
|
|
|
cmd += ["-i", str(subfile)]
|
2016-06-20 18:33:42 +02:00
|
|
|
else:
|
2021-05-03 01:43:37 +02:00
|
|
|
subfile = orig_filename.with_suffix(".srt")
|
2021-05-10 20:51:55 +02:00
|
|
|
cmd += ["-i", str(subfile)]
|
2017-02-15 23:15:50 +01:00
|
|
|
|
2021-05-10 20:51:55 +02:00
|
|
|
arguments += ["-y", str(tempfile)]
|
2016-03-26 21:38:31 +01:00
|
|
|
cmd += arguments
|
2018-03-03 16:11:23 +01:00
|
|
|
returncode, stdout, stderr = run_program(cmd)
|
2018-03-09 22:19:27 +01:00
|
|
|
if returncode != 0:
|
2016-03-26 21:38:31 +01:00
|
|
|
return
|
2016-07-01 00:30:55 +02:00
|
|
|
|
2020-01-02 20:53:23 +01:00
|
|
|
if self.config.get("keep_original") is True:
|
|
|
|
logging.info("Merging done, keeping original files.")
|
|
|
|
os.rename(tempfile, orig_filename)
|
|
|
|
return
|
|
|
|
|
2018-11-18 12:47:19 +01:00
|
|
|
logging.info("Merging done, removing old files.")
|
2020-12-06 18:56:52 +01:00
|
|
|
if self.config.get("only_video") or not self.config.get("only_audio"):
|
|
|
|
os.remove(orig_filename)
|
2021-06-13 01:22:16 +02:00
|
|
|
if (self.stream.audio and self.config.get("only_audio")) or (self.stream.audio and not self.config.get("only_video")):
|
2020-12-06 18:56:52 +01:00
|
|
|
os.remove(audio_filename)
|
|
|
|
|
2021-11-25 10:59:21 +01:00
|
|
|
# This if statement is for use cases where both -S and -M are specified to not only merge the subtitle but also store it separately.
|
2021-11-25 10:40:54 +01:00
|
|
|
if self.config.get("merge_subtitle") and not self.config.get("subtitle"):
|
2018-01-13 21:17:12 +01:00
|
|
|
if self.subfixes and len(self.subfixes) >= 2:
|
2016-06-20 18:33:42 +02:00
|
|
|
for subfix in self.subfixes:
|
2021-10-31 02:42:35 +02:00
|
|
|
subfile = orig_filename.parent / (orig_filename.stem + "." + subfix + ".srt")
|
2016-06-20 18:33:42 +02:00
|
|
|
os.remove(subfile)
|
2018-01-30 20:11:37 +01:00
|
|
|
else:
|
|
|
|
os.remove(subfile)
|
2021-05-09 21:50:41 +02:00
|
|
|
os.rename(tempfile, new_name)
|
2018-03-03 16:11:23 +01:00
|
|
|
|
|
|
|
|
2019-09-15 17:31:49 +02:00
|
|
|
def _streams(output):
|
|
|
|
return re.findall(r"Stream \#(\d:\d)([\[\(][^\[]+[\]\)])?([\(\)\w]+)?: (Video|Audio): (.*)", output)
|
|
|
|
|
|
|
|
|
|
|
|
def _getcodec(streams, number):
|
|
|
|
for stream in streams:
|
|
|
|
if stream[0] == number:
|
|
|
|
return stream[4]
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
|
|
def _checktracks(streams):
|
|
|
|
videotrack = None
|
|
|
|
audiotrack = None
|
|
|
|
for stream in streams:
|
|
|
|
if stream[3] == "Video":
|
|
|
|
videotrack = stream[0]
|
|
|
|
if stream[3] == "Audio":
|
|
|
|
if stream[4] == "mp3, 0 channels":
|
|
|
|
continue
|
|
|
|
audiotrack = stream[0]
|
|
|
|
|
|
|
|
return videotrack, audiotrack
|
2019-09-15 19:00:38 +02:00
|
|
|
|
|
|
|
|
|
|
|
def _sublanguage(stream, config, subfixes):
|
|
|
|
# parse() function partly borrowed from a guy on github. /thanks!
|
|
|
|
# https://github.com/riobard/srt.py/blob/master/srt.py
|
|
|
|
def parse(self):
|
|
|
|
def parse_block(block):
|
|
|
|
lines = block.strip("-").split("\n")
|
|
|
|
txt = "\r\n".join(lines[2:])
|
|
|
|
return txt
|
|
|
|
|
|
|
|
if platform.system() == "Windows":
|
|
|
|
fd = open(self, encoding="utf8")
|
|
|
|
else:
|
|
|
|
fd = open(self)
|
|
|
|
return list(map(parse_block, fd.read().strip().replace("\r", "").split("\n\n")))
|
|
|
|
|
|
|
|
def query(self):
|
|
|
|
_ = parse(self)
|
|
|
|
random_sentences = " ".join(sample(_, len(_) if len(_) < 8 else 8)).replace("\r\n", "")
|
|
|
|
url = "https://whatlanguage.herokuapp.com"
|
|
|
|
payload = {"query": random_sentences}
|
|
|
|
# Note: requests handles json from version 2.4.2 and onwards so i use json.dumps for now.
|
|
|
|
headers = {"content-type": "application/json"}
|
|
|
|
try:
|
|
|
|
# Note: reasonable timeout i guess? svtplay-dl is mainly used while multitasking i presume,
|
|
|
|
# and it is heroku after all (fast enough)
|
|
|
|
r = post(url, data=dumps(payload), headers=headers, timeout=30)
|
|
|
|
if r.status_code == codes.ok:
|
|
|
|
try:
|
|
|
|
response = r.json()
|
|
|
|
return response["language"]
|
|
|
|
except TypeError:
|
|
|
|
return "und"
|
|
|
|
else:
|
|
|
|
logging.error("Server error appeared. Setting language as undetermined.")
|
|
|
|
return "und"
|
|
|
|
except Timeout:
|
|
|
|
logging.error("30 seconds server timeout reached. Setting language as undetermined.")
|
|
|
|
return "und"
|
|
|
|
|
|
|
|
langs = []
|
|
|
|
exceptions = {"lulesamiska": "smj", "meankieli": "fit", "jiddisch": "yid"}
|
2021-06-13 01:22:16 +02:00
|
|
|
logging.info("Determining the language of the subtitle(s).")
|
2019-09-15 19:00:38 +02:00
|
|
|
if config.get("get_all_subtitles"):
|
|
|
|
for subfix in subfixes:
|
2021-06-24 23:21:15 +02:00
|
|
|
if [exceptions[key] for key in exceptions.keys() if re.match(key, subfix.strip("-"))]:
|
2019-09-15 19:00:38 +02:00
|
|
|
if "oversattning" in subfix.strip("-"):
|
|
|
|
subfix = subfix.strip("-").split(".")[0]
|
|
|
|
else:
|
|
|
|
subfix = subfix.strip("-")
|
|
|
|
langs += [exceptions[subfix]]
|
|
|
|
continue
|
2021-05-03 01:43:37 +02:00
|
|
|
sfile = formatname(stream.output, config)
|
|
|
|
subfile = sfile.parent / (sfile.stem + "." + subfix + ".srt")
|
2019-09-15 19:00:38 +02:00
|
|
|
langs += [query(subfile)]
|
|
|
|
else:
|
2021-05-03 01:43:37 +02:00
|
|
|
subfile = formatname(stream.output, config).with_suffix(".srt")
|
2019-09-15 19:00:38 +02:00
|
|
|
langs += [query(subfile)]
|
|
|
|
if len(langs) >= 2:
|
|
|
|
logging.info("Language codes: " + ", ".join(langs))
|
|
|
|
else:
|
|
|
|
logging.info("Language code: " + langs[0])
|
|
|
|
return langs
|