Media-Manager/Video/videoservice.py

364 lines
22 KiB
Python
Raw Normal View History

2022-10-07 11:03:06 -05:00
import os
import re
2022-10-06 06:02:31 -05:00
import time
2022-10-07 11:03:06 -05:00
import subprocess
from Video import default
from Universal import tools
2022-10-06 06:02:31 -05:00
from Universal import ioservice
from Universal import loggingservice
2022-10-07 11:03:06 -05:00
from Video.Services import tmdbservice
from Universal.network import sftpservice
2022-10-06 06:02:31 -05:00
class VideoService:
def __init__(self):
self.logger = loggingservice.Output(True, False)
self.video_settings = default.VideoSettings()
# Movie/TV Show Database
self.tmdbservice = tmdbservice.TMDBService(self.logger)
# Network Service
self.sftpservice = sftpservice.SFTPService(self.logger)
self.failedFiles = []
2022-10-06 06:02:31 -05:00
self.video_settings.updateSettings()
def startNewProcess(self, num=1):
self.logger.debugReport("[Video] startNewProcess")
self.current_library = num
self.total_processed = 0
self.is_processing = True
self.video_settings.updateLibrary(self.current_library)
if self.video_settings.library["Server"].lower().find("none") == -1:
self.video_settings.updateServer(self.video_settings.library["Server"])
while self.is_processing:
self.processLibraries()
self.startNewProcess(self.current_library)
2022-10-06 06:02:31 -05:00
def processLibraries(self, refreshLib=True):
2022-10-06 06:02:31 -05:00
self.logger.debugReport("[Video] processLibraries")
tmp_library_time = time.time()
if self.video_settings.library is not None:
if self.video_settings.library["Input"] is not None:
if refreshLib:
self.total_processed = 0
time.sleep(2)
2022-10-06 06:02:31 -05:00
self.logger.infoReport("[Video] Current Library: " + self.video_settings.library["Name"])
self.current_library_list = ioservice.listAllFiles(self.video_settings.library["Input"])
if self.current_library_list is not None:
self.current_library_list = sorted(self.current_library_list)
if self.current_library_list is not None:
if refreshLib:
self.srt_list = []
for item_search in self.current_library_list:
if item_search.lower().find(".srt") != -1:
self.srt_list.append(item_search)
if self.srt_list is not None:
for item_search in self.srt_list:
self.current_library_list.remove(item_search)
if len(self.current_library_list) == 0:
self.is_processing = False
else:
self.logger.infoReport("[Video] Found a total of " + str(len(self.current_library_list)) + " files")
2022-10-06 06:02:31 -05:00
for self.current_file in self.current_library_list:
if self.total_processed != 0:
self.logger.infoReport("[Video] Total file remaining: " + str(len(self.current_library_list) - self.total_processed))
self.processVideo()
else:
self.logger.infoReport("[Video] Folder is empty")
ioservice.deleteEmptyFolders(self.video_settings.library["Input"])
else:
self.is_processing = False
else:
self.is_processing = False
self.logger.infoReport("[Video] Current Library: " + self.video_settings.library["Name"] + " Time Elapsed: " + time.strftime("%H:%M:%S", time.gmtime(time.time() - tmp_library_time)))
self.current_library += 1
def processVideo(self):
self.logger.debugReport("[Video] processVideo")
self.logger.infoReport("[Video] Current File: " + self.current_file)
2022-10-07 11:03:06 -05:00
tmp_isDeleted = False
tmp_isSuccess = True
tmp_serverPath = None
2022-10-07 11:03:06 -05:00
if not ioservice.checkSizeChange(self.current_file):
if ioservice.getFileSize(self.current_file) == 0:
self.logger.infoReport("[Video] Assuming file has been deleted or moved... Skipping...")
tmp_isDeleted = True
else:
self.logger.infoReport("[Video] File size has changed")
self.processVideo()
else:
if not tmp_isDeleted:
tmp_currentFileDetails = self.extractVideoInformation(self.current_file)
self.constructOutputPath(tmp_currentFileDetails)
if tmp_currentFileDetails["Episode"] is None and tmp_currentFileDetails["Season"] is None:
self.logger.infoReport("[Video] " + tmp_currentFileDetails["Name"] + " " + str(tmp_currentFileDetails["Year"]))
else:
self.logger.infoReport("[Video] " + tmp_currentFileDetails["Name"] + " Season: " + str(tmp_currentFileDetails["Season"]) + " Episode: " + str(tmp_currentFileDetails["Episode"]))
self.findSRTs()
tmp_compress = False
if not self.video_settings.library["Server"].lower().find("none") != -1:
self.video_settings.updateServer(self.video_settings.library["Server"])
tmp_serverPath = self.constructServerPath()
if self.video_settings.server["Type"].lower().find("sftp") != -1:
if self.sftpservice.isEnabled():
if not self.sftpservice.isConnected():
self.sftpservice.connectSFTPServer(self.video_settings.server["Host"], self.video_settings.server["Port"], self.video_settings.server["Username"],
self.video_settings.server["Password"], self.video_settings.server["Key File"], self.video_settings.server["Key Type"])
if self.sftpservice.isConnected():
if not ioservice.doesFileExist(self.currentFileOutputPath):
if self.video_settings.library["Server Overwrite"]:
tmp_compress = True
else:
if not self.sftpservice.doesFileExists(tmp_serverPath):
tmp_compress = True
else:
if not ioservice.doesFileExist(self.currentFileOutputPath):
tmp_compress = True
if tmp_compress and not self.video_settings.library["Compress"]:
if self.video_settings.library["Delete Input"]:
self.logger.infoReport("[Video] Moving file")
self.is_processing = True
ioservice.moveFile(self.current_file, self.currentFileOutputPath)
i = 0
while i < len(self.srt_to_include):
ioservice.moveFile(self.srt_to_include[i], self.constructOutputPath(tmp_currentFileDetails, True, i))
i += 1
self.is_processing = False
tmp_isSuccess = True
self.logger.infoReport("[Video] Move complete")
else:
self.logger.infoReport("[Video] Copying file")
self.is_processing = True
ioservice.moveFile(self.current_file, self.currentFileOutputPath, True)
i = 0
while i < len(self.srt_to_include):
ioservice.moveFile(self.srt_to_include[i], self.constructOutputPath(tmp_currentFileDetails, True, i), True)
i += 1
self.is_processing = False
tmp_isSuccess = True
self.logger.infoReport("[Video] Copying complete")
elif tmp_compress and self.video_settings.library["Compress"]:
self.logger.infoReport("[Video] Compressing video")
self.startCompressing(self.current_file, self.currentFileOutputPath, self.srt_to_include)
tmp_isSuccess = True
self.logger.infoReport("[Video] Compressing completed")
if not self.video_settings.library["Server"].lower().find("none") != -1:
self.video_settings.updateServer(self.video_settings.library["Server"])
if self.video_settings.server["Type"].lower().find("sftp") != -1:
if self.sftpservice.isEnabled():
if not self.sftpservice.isConnected():
self.sftpservice.connectSFTPServer(self.video_settings.server["Host"], self.video_settings.server["Port"], self.video_settings.server["Username"],
self.video_settings.server["Password"], self.video_settings.server["Key File"], self.video_settings.server["Key Type"])
if self.sftpservice.isConnected():
if self.sftpservice.doesFileExists(tmp_serverPath):
if self.video_settings.library["Server Overwrite"]:
if self.sftpservice.getFileSize(tmp_serverPath) != ioservice.getFileSize(self.currentFileOutputPath):
if self.sftpservice.doesFileExist(tmp_serverPath):
self.sftpservice.deleteFile(tmp_serverPath)
if self.sftpservice.uploadFile(self.currentFileOutputPath, tmp_serverPath):
tmp_isSuccess = True
self.logger.infoReport("[Video] Upload Complete")
else:
tmp_isSuccess = False
else:
if self.sftpservice.uploadFile(self.currentFileOutputPath, tmp_serverPath):
tmp_isSuccess = True
self.logger.infoReport("[Video] Upload Complete")
else:
tmp_isSuccess = False
else:
if self.sftpservice.uploadFile(self.currentFileOutputPath, tmp_serverPath):
tmp_isSuccess = True
else:
tmp_isSuccess = False
if not tmp_isSuccess:
self.failedFiles = self.failedFiles + [self.current_file]
else:
self.total_processed += 1
2022-10-07 11:03:06 -05:00
def extractVideoInformation(self, file):
self.logger.debugReport("[Video] extractVideoInformation")
file = file.replace(self.video_settings.library["Input"], "").lstrip().replace("_", "")
for blacklist_item in self.video_settings.settings["Blacklist"].split(", "):
file = file.replace(blacklist_item, "")
tmp_input_format = file.rsplit(".", 1)[-1]
tmp_name = None
tmp_season = None
tmp_episode = None
tmp_episode_title = None
tmp_year = None
tmp_episode_year = None
tmp_length = self.getVideoLength()
tmp_folders, tmp_file = os.path.split(file)
for possible_years in re.findall(r'\d+', file):
if len(possible_years) == 4:
tmp_year = int(possible_years)
match len(tmp_folders.split(ioservice.getPathSeperator())):
case 1:
tmp_name = tmp_folders.split(ioservice.getPathSeperator())[0]
if not tmp_name:
tmp_name = tmp_file.replace(str(tmp_year), "").replace("." + tmp_input_format, "").strip()
case 2:
tmp_name = tmp_folders.split(ioservice.getPathSeperator())[0]
case 3:
tmp_name = tmp_folders.split(ioservice.getPathSeperator())[0]
case _:
tmp_name = tmp_file.replace("." + tmp_input_format, "")
if self.video_settings.library["Type"].lower().find("show") != -1:
if tmp_season is None or tmp_episode is None:
match len(tmp_folders.split(ioservice.getPathSeperator())):
case 2:
tmp_season = re.findall(r'\d+', tmp_folders.replace(tmp_name, ""))[0]
tmp_episode = re.findall(r'([0-9]*[0-9])', tmp_file.replace("." + tmp_input_format, "").replace(tmp_name, ""))[-1]
if tmp_file.lower().find(tmp_episode + "a") != -1:
tmp_episode = tmp_episode + " - Part 1"
elif tmp_file.lower().find(tmp_episode + "b") != -1:
tmp_episode = tmp_episode + " - Part 2"
case 3:
tmp_season = re.findall(r'\d+', tmp_folders.replace(tmp_name, ""))[0]
tmp_episode = re.findall(r'([0-9]*[0-9])', tmp_folders.replace("." + tmp_input_format, "").replace(tmp_name, ""))[-1]
if tmp_file.lower().find(tmp_episode + "a") != -1:
tmp_episode = tmp_episode + " - Part 1"
elif tmp_file.lower().find(tmp_episode + "b") != -1:
tmp_episode = tmp_episode + " - Part 2"
case _:
tmp_episode = re.findall(r'\d+', tmp_file.replace("." + tmp_input_format, "").replace(tmp_name, ""))[-1]
try:
tmp_season = re.findall(r'\d+', tmp_file.replace("." + tmp_input_format, "").replace(tmp_name, ""))[0]
except:
tmp_episode = re.findall(r'\d+', tmp_file.replace("." + tmp_input_format, ""))[-1]
if tmp_season != "0" and tmp_season:
tmp_season = tmp_season.lstrip("0")
if tmp_episode != "0" and tmp_episode:
tmp_episode = tmp_episode.lstrip("0")
match self.video_settings.library["Database"].lower():
case "tmdb":
if self.tmdbservice.isEnabled():
self.tmdbservice.connectToTMDB()
if self.video_settings.library["Type"].lower().find("movie") != -1:
tmp_name = tmp_name.replace(str(tmp_year), "").replace("(", "").replace(")", "")
if tmp_length is not None or tmp_year is not None:
tmp_data = self.tmdbservice.getBestMovie(tmp_name, tmp_length, tmp_year)
if tmp_data:
tmp_name = tmp_data[0]
tmp_year = tmp_data[2]
else:
tmp_data = self.tmdbservice.searchMovies(tmp_name)
tmp_name = tmp_data[0][0]
tmp_year = tmp_data[0][1]
elif self.video_settings.library["Type"].lower().find("show") != -1:
tmp_data = self.tmdbservice.getShowName(tmp_name)
tmp_name = tmp_data["name"]
tmp_year = tmp_data["first_air_date"][:4]
case "tvdb":
#TODO: Implement
2022-10-07 11:03:06 -05:00
pass
case _:
#TODO: Implement
2022-10-07 11:03:06 -05:00
pass
tmp_name = tmp_name.replace(":", "")
if tmp_episode_title:
tmp_episode_title = tmp_episode_title.replace(":", "")
return {"Name": tmp_name, "Year": tmp_year, "Season": tmp_season, "Episode": tmp_episode, "Episode Title": tmp_episode_title, "Episode Year": tmp_episode_year, "Format": tmp_input_format}
2022-10-07 11:03:06 -05:00
def constructOutputPath(self, file_info, subtitles=False, num=0):
2022-10-07 11:03:06 -05:00
self.logger.debugReport("[Video] constructOutputPath")
self.currentFileOutputPath = self.video_settings.library["Output"] + self.video_settings.library["Directory"]
self.currentFileOutputPath = tools.replace(self.currentFileOutputPath, "${NAME}", file_info["Name"])
self.currentFileOutputPath = tools.replace(self.currentFileOutputPath, "${YEAR}", file_info["Year"])
self.currentFileOutputPath = tools.replace(self.currentFileOutputPath, "${SEASON}", file_info["Season"])
if isinstance(file_info["Episode"], list):
tmp_episodes = None
for eps in file_info["Episode"]:
if eps != file_info["Episode"][-1]:
if not tmp_episodes:
tmp_episodes = str(eps) + "-"
else:
tmp_episodes = tmp_episodes + str(eps) + "-"
else:
if not tmp_episodes:
tmp_episodes = str(eps)
else:
tmp_episodes = tmp_episodes + str(eps)
self.currentFileOutputPath = tools.replace(self.currentFileOutputPath, "${EPISODE}", tmp_episodes)
else:
self.currentFileOutputPath = tools.replace(self.currentFileOutputPath, "${EPISODE}", file_info["Episode"])
self.currentFileOutputPath = tools.replace(self.currentFileOutputPath, "${EPISODE_YEAR}", file_info["Episode Year"])
self.currentFileOutputPath = tools.replace(self.currentFileOutputPath, "${EPISODE_NAME}", file_info["Episode Title"])
if not subtitles:
if self.currentFileOutputPath[self.currentFileOutputPath.index("${FORMAT}") - 1] != ".":
if file_info["Format"].startswith("."):
self.currentFileOutputPath = tools.replace(self.currentFileOutputPath, "${FORMAT}", file_info["Format"])
else:
self.currentFileOutputPath = tools.replace(self.currentFileOutputPath, "${FORMAT}", "." + file_info["Format"])
else:
if file_info["Format"].startswith("."):
self.currentFileOutputPath = tools.replace(self.currentFileOutputPath, ".${FORMAT}", file_info["Format"])
else:
self.currentFileOutputPath = tools.replace(self.currentFileOutputPath, ".${FORMAT}", "." + file_info["Format"])
else:
if self.currentFileOutputPath[self.currentFileOutputPath.index("${FORMAT}") - 1] != ".":
self.currentFileOutputPath = tools.replace(self.currentFileOutputPath, "${FORMAT}", " - " + self.srt_language[num] + ".srt")
elif self.currentFileOutputPath[self.currentFileOutputPath.index("${FORMAT}" - 1)] == ".":
self.currentFileOutputPath = tools.replace(self.currentFileOutputPath, ".${FORMAT}", " - " + self.srt_language[num] + ".srt")
self.logger.debugReport("[Video] Output Path: " + self.currentFileOutputPath)
return self.currentFileOutputPath
def startCompressing(input_path, output_path, srt_list):
#TODO: Implement
pass
def constructServerPath(self):
#TODO: Implement
pass
def findSRTs(self):
self.logger.debugReport("[Video] findSRTs")
tmp_srt_lang = ["aar", "abk", "afr", "aka", "alb", "amh", "ara", "arg", "arm", "asm", "ava", "ave", "aym", "aze", "bak", "bam", "baq",
"bel", "ben", "bih", "bis", "bos", "bre", "bul", "bur", "cat", "cha", "che", "chi", "chu", "chv", "cor", "cos", "cre",
"cze", "dan", "div", "dut", "dzo", "eng", "epo", "est", "ewe", "fao", "fij", "fin", "fre", "fry", "ful", "geo", "ger",
"gla", "gle", "glg", "glv", "gre", "grn", "guj", "hat", "hau", "heb", "her", "hin", "hmo", "hrv", "hun", "ibo", "ice",
"ido", "iii", "iku", "ile", "ina", "ind", "ipk", "ita", "jav", "jpn", "kal", "kan", "kas", "kau", "kaz", "khm", "kik",
"kin", "kir", "kom", "kon", "kor", "kua", "kur", "lao", "lat", "lav", "lim", "lin", "lit", "ltz", "lub", "lug", "mac",
"mah", "mal", "mao", "mar", "may", "mlg", "mlt", "mon", "nau", "nav", "nbl", "nde", "ndo", "nep", "nno", "nob", "nor",
"nya", "oci", "oji", "ori", "orm", "oss", "pan", "per", "pli", "pol", "por", "pus", "que", "roh", "rum", "run", "rus",
"sag", "san", "sin", "slo", "slv", "sme", "smo", "sna", "snd", "som", "sot", "spa", "srd", "srp", "ssw", "sun", "swa",
"swe", "tah", "tam", "tat", "tel", "tgk", "tgl", "tha", "tib", "tir", "ton", "tsn", "tso", "tuk", "tur", "twi", "uig",
"ukr", "urd", "uzb", "ven", "vie", "vol", "wel", "wln", "wol", "xho", "yid", "yor", "zha", "zul"]
self.srt_to_include = []
self.srt_language = []
tmp_srt = self.current_file.replace(self.current_file.rsplit(".")[-1], "srt").lower()
if (ioservice.doesFileExist(tmp_srt)):
self.srt_to_include.append(tmp_srt)
self.srt_language.append("eng")
else:
for possible_srt in tmp_srt_lang:
tmp_srt = self.current_file.replace(self.current_file.rsplit(".")[-1], "")[:-1].lower()
tmp_srt = tmp_srt + "-" + possible_srt + ".srt"
if (ioservice.doesFileExist(tmp_srt)):
self.srt_to_include.append(tmp_srt)
self.srt_language.append(possible_srt)
2022-10-07 11:03:06 -05:00
def getVideoLength(self):
self.logger.debugReport("[Video] getVideoLength")
tmp_time = None
try:
tmp_time = subprocess.check_output([self.video_settings.settings["FFProbe"], '-i', self.current_file, '-show_entries', 'format=duration', '-v', 'quiet', '-of', 'csv=%s' % ("p=0")])
tmp_time = str(tmp_time)
if not tmp_time.find("N/A") != -1:
tmp_hours = time.strftime("%H", time.gmtime(round(float(re.findall('\d+', tmp_time)[0])))).lstrip("0")
tmp_minutes = time.strftime("%M", time.gmtime(round(float(re.findall('\d+', tmp_time)[0])))).lstrip("0")
try:
tmp_hours = int(tmp_hours) * 60
except:
tmp_hours = 0
try:
tmp_length = tmp_hours + int(tmp_minutes)
except:
tmp_length = tmp_hours
else:
self.logger.errorReport("[Video] FFProbe could not get video content length")
tmp_length = None
return tmp_length
except:
self.logger.errorReport("[Video] There was a problem getting the length of video content")
return None