diff --git a/Universal/network/sftpservice.py b/Universal/network/sftpservice.py new file mode 100644 index 0000000..8c1d2af --- /dev/null +++ b/Universal/network/sftpservice.py @@ -0,0 +1,134 @@ +import time + +class SFTPService: + def __init__(self, logger, ioservice, universal): + self.logger = logger + self.ioservice = ioservice + self.universal = universal + self.report(2, "Initializing") + try: + import paramiko + self.enabled = True + self.paramiko = paramiko + self.report(2, "API Found") + except ImportError: + self.enabled = False + self.report(3, "Module 'paramiko' was not found") + self.report(3, "Disabling SFTP features") + self.connected = False + + def connectSFTPServer(self, host, port, username, password, key_file, key_type): + self.report(2, "connectSFTPServer") + self.host = host + self.port = int(port) + self.username = username + self.password = password + self.key_file = key_file + self.key_type = key_type + tmp_key = None + if key_file != None: + if key_file.lower().find("dsa") != -1: + tmp_key = self.paramiko.DSAKey.from_private_key_file(key_file) + elif key_file.lower().find("rsa") != -1: + tmp_key = self.paramiko.RSAKey.from_private_key_file(key_file) + try: + tmp = self.paramiko.Transport((host, port)) + tmp.connect(None, username, password, tmp_key) + except: + self.connected = False + try: + self.sftp_socket = self.paramiko.SFTPClient.from_transport(tmp) + self.connected = True + return True + except: + self.connected = False + return False + + def attemptReconnect(self, retries=1): + self.report(2, "attemptReconnect") + self.connected = False + if retries == 1: + self.report(1, "Lost connect to SFTP Server...") + if retries <= 5: + self.report(1, "Attempt #" + str(retries) + "... Attemping to reconnect in 15 seconds...") + self.closeConnection() + time.sleep(15) + if self.connectSFTPServer(self.host, self.port, self.username, self.password, self.key_file, self.key_type): + self.logger(0, "Successfully reconnected to SFTP Server") + return True + else: + return self.attemptReconnect(retries + 1) + else: + self.report(3, "Could not reconnect to SFTP Server...") + return False + + def closeConnection(self): + self.report(2, "closeConnection") + if self.sftp_socket is not None: + self.sftp_socket.close() + self.connected = False + + def getFileSize(self, path, retried=0): + self.report(2, "getFileSize") + try: + return str(self.sftp_socket.lstat(path)).split()[4] + except IOError: + return None + except: + if retried == 0: + if self.attemptReconnect(): + return self.getFileSize(path, 1) + else: + return None + + def doesFileExists(self, path): + self.report(2, "doesFileExists") + if self.getFileSize(path): + return True + else: + return False + + def createFolder(self, path): + self.report(2, "createFolder") + tmp_full_path = path.split("/") + tmp_path = tmp_full_path[0] + for current_path in tmp_full_path: + if tmp_path != current_path: + tmp_path = tmp_path + "/" + current_path + try: + self.sftp_socket.mkdir(tmp_path) + except: + pass + + def deleteFile(self, path): + self.report(2, "deleteFile") + try: + self.sftp_socket.remove(path) + return True + except: + self.report(3, "Failed to delete file") + + def uploadFile(self, input_path, output_path, retried=0): + self.report(2, "uploadFile") + try: + self.createFolder(output_path.replace(output_path.split("/")[-1], "")) + if self.doesFileExists(output_path): + self.deleteFile(output_path) + return self.sftp_socket.put(input_path, output_path) + except: + if retried == 0: + if self.attemptReconnect(): + return self.uploadFile(input_path, output_path, 1) + else: + return False + + def report(self, level, message): + match level: + case 0: + self.logger.infoReport("[SFTP] " + message) + case 1: + self.logger.warningReport("[SFTP] " + message) + case 2: + self.logger.debugReport("[SFTP] " + message) + case 3: + self.logger.errorReport("[SFTP] " + message) \ No newline at end of file diff --git a/Video/Services/tmdbservice.py b/Video/Services/tmdbservice.py index b99063b..7022809 100644 --- a/Video/Services/tmdbservice.py +++ b/Video/Services/tmdbservice.py @@ -1,18 +1,28 @@ class TMDBService: - def __init__(self, loggingservice): - self.logger = loggingservice + def __init__(self, loggingservice, ioservice): self.report(2, "Initializing") try: import tmdbsimple self.tmdb = tmdbsimple self.report(2, "API Found") + self.logger = loggingservice + self.ioservice = ioservice self.enabled = True + self.tmdb_key = None + self.addDefaultConfiguration() except ImportError: self.report(3, "Module 'tmdbsimple' was not found") self.report(3, "Disabling TMDB API") self.enabled = False self.connected = False + def addDefaultConfiguration(self): + self.ioservice.addConfiguration("TMDB Service", "TMDB API Key", "NONE") + + def updateConfiguration(self): + if self.tmdb_key == None: + self.tmdb_key = self.ioservice.getConfigurationStr("TMDB Service", "TMDB API Key") + def report(self, level, message): match level: case 0: @@ -24,12 +34,13 @@ class TMDBService: case 3: self.logger.errorReport("[TMDB] " + message) - def connectToTMDB(self, api_key): + def connectToTMDB(self): self.report(2, "connectToTMDB") if not self.connected: try: self.report(2, "Attempting to Login") - self.tmdb.API_KEY = api_key + self.updateConfiguration() + self.tmdb.API_KEY = self.tmdb_key self.connected = True self.report(2, "Connected") except self.tmdb.APIKeyError: diff --git a/Video/default.py b/Video/default.py index 5e06ec9..f10159d 100644 --- a/Video/default.py +++ b/Video/default.py @@ -6,14 +6,13 @@ def generateConfigs(): generateVideoConfig() def generateProcessorConfigs(): - ioservice.addConfiguration("Video Configuration", "TMDB API Key") ioservice.addConfiguration("Video Configuration", "FFProbe Path") ioservice.addConfiguration("Video Configuration", "Encoder Path") ioservice.addConfiguration("Video Configuration", "Sleep Timer (Seconds)", "100") ioservice.addConfiguration("Video Configuration", "Blacklist Words", "1080p, 720p, 480p, 360p, x265, x264") def generateServerConfig(): - ioservice.addConfiguration("Server 1", "Type (SFTP/NONE)", "NONE") + ioservice.addConfiguration("Server 1", "Type", "NONE") ioservice.addConfiguration("Server 1", "Host", "127.0.0.1") ioservice.addConfiguration("Server 1", "Port", "22") ioservice.addConfiguration("Server 1", "Username", "NONE") @@ -37,3 +36,55 @@ def generateVideoConfig(): ioservice.addConfiguration("Video Library 1", "Server", "None") ioservice.addConfiguration("Video Library 1", "Server Path", "/TV Shows/${NAME}/Season ${SEASON}/${NAME} S${SEASON}E${EPISODE}.${FORMAT}") ioservice.addConfiguration("Video Library 1", "Server Overwrite", "False") + +class VideoSettings: + def __init__(self): + self.settings = {} + self.library = {} + self.server = {} + + def updateEverything(self, num): + self.updateSettings() + self.updateLibrary(num) + + def updateSettings(self): + tmp_ffprobe = ioservice.getConfigurationStr("Video Configuration", "FFProbe Path") + tmp_encoder = ioservice.getConfigurationStr("Video Configuration", "Encoder Path") + tmp_timer = ioservice.getConfigurationStr("Video Configuration", "Sleep Timer (Seconds)") + tmp_blacklist = ioservice.getConfigurationStr("Video Configuration", "Blacklist Words") + self.settings = {"FFProbe": tmp_ffprobe, "Encoder": tmp_encoder, "Timer": tmp_timer, + "Blacklist": tmp_blacklist} + + def updateLibrary(self, num): + tmp_section = ("Video Library " + str(num)) + tmp_name = ioservice.getConfigurationStr(tmp_section, "Directory Name") + tmp_input = ioservice.getConfigurationStr(tmp_section, "Input") + tmp_output = ioservice.getConfigurationStr(tmp_section, "Output") + tmp_database = ioservice.getConfigurationStr(tmp_section, "Database Service") + tmp_type = ioservice.getConfigurationStr(tmp_section, "Media Type") + tmp_compress = ioservice.getConfigurationBool(tmp_section, "Compress Video") + tmp_out_format = ioservice.getConfigurationStr(tmp_section, "Output Format") + tmp_dir_format = ioservice.getConfigurationStr(tmp_section, "Directory Format") + tmp_command = ioservice.getConfigurationStr(tmp_section, "Command") + tmp_srt_command = ioservice.getConfigurationStr(tmp_section, "Subtitle Command") + tmp_del_input = ioservice.getConfigurationBool(tmp_section, "Delete Input") + tmp_server = ioservice.getConfigurationStr(tmp_section, "Server") + tmp_server_path = ioservice.getConfigurationStr(tmp_section, "Server Path") + tmp_server_overwrite = ioservice.getConfigurationBool(tmp_section, "Server Overwrite") + self.library = {"Name": tmp_name, "Input": tmp_input, "Output": tmp_output, "Database": tmp_database, + "Type": tmp_type, "Compress": tmp_compress, "Format": tmp_out_format, "Directory": tmp_dir_format, + "Command": tmp_command, "SRT Command": tmp_srt_command, "Delete Input": tmp_del_input, + "Server": tmp_server, "Server Path": tmp_server_path, "Server Overwrite": tmp_server_overwrite} + + def updateServer(self, num): + tmp_section = ("Server " + str(num)) + tmp_type = ioservice.getConfigurationStr(tmp_section, "Type") + tmp_host = ioservice.getConfigurationStr(tmp_section, "Host") + tmp_port = ioservice.getConfigurationStr(tmp_section, "Port") + tmp_username = ioservice.getConfigurationStr(tmp_section, "Username") + tmp_password = ioservice.getConfigurationStr(tmp_section, "Password") + tmp_keyfile = ioservice.getConfigurationStr(tmp_section, "Key File") + tmp_keytype = ioservice.getConfigurationStr(tmp_section, "Key Type (RSA/DSA)") + tmp_root = ioservice.getConfigurationStr(tmp_section, "Media Root") + self.server = {"Type": tmp_type, "Host": tmp_host, "Port": tmp_port, "Username": tmp_username, + "Password": tmp_password, "Key File": tmp_keyfile, "Key Type": tmp_keytype, "Root": tmp_root}