def kill (): MAKEMKVCON = None plugin.log('killing makemkvcon') cmd = [ 'killall', '-KILL', 'makemkvcon' ] call(cmd) cmd[2] = cmd[2] + '.bin' call(cmd)
def check_connection(self): try: self.lock.acquire(True) self.DBH.ping(reconnect=True, attempts=1, delay=0) except Exception, e: plugin.log("Failed Test") plugin.log(e)
def query_assoc(self, SQL, data=None, force_double_array=False, silent=False): try: self.lock.acquire(True) self.DBH.row_factory = self.dict_factory cur = self.DBH.cursor() if data: cur.execute(SQL, data) else: cur.execute(SQL) rows = cur.fetchall() cur.close() if (len(rows) == 1 and not force_double_array): return rows[0] else: return rows except Exception, e: if 'no such table: version' not in str(e).lower(): plugin.raise_error("Database error", e) plugin.log("Database query error: %s" % e) plugin.log("Database query error: %s" % SQL) return []
def kill(): MAKEMKVCON = None plugin.log('killing makemkvcon') cmd = ['killall', '-KILL', 'makemkvcon'] call(cmd) cmd[2] = cmd[2] + '.bin' call(cmd)
def ready (): try: up = connect() up.close() return True except Exception, e: plugin.log('ERROR: %s' % e) pass
def kill(job, signal='-KILL'): pid = str(job['pid']) plugin.log(plugin.lang(50019) % (job['dev'], signal)) #killing makemkvcon job on %s with signal %s cmd = ['kill', signal, pid] subprocess.call(cmd) if signal == '-KILL': if job['tmp_dir'] is not None: cleanup(job)
def ready(): try: up = connect() up.close() return True except Exception, e: plugin.log('ERROR: %s' % e) pass
def installed(): path = plugin.get('makemkvcon_path', 'makemkvcon') plugin.log('makemkvcon_path = %s' % path) try: p = Popen(path, stdout=PIPE, stderr=PIPE) p = None return True except Exception, e: plugin.log('error = %s' % e)
def installed(): path = plugin.get('makemkvcon_path', 'makemkvcon') plugin.log('makemkvcon_path = %s' % path) try: p = subprocess.Popen(path, stdout=subprocess.PIPE, stderr=subprocess.PIPE) p = None return True except Exception, e: plugin.log(plugin.lang(50017) % e.strerror) #makemkvcon.installed() ERROR: %s
def installed (): path = plugin.get('makemkvcon_path', 'makemkvcon') plugin.log('makemkvcon_path = %s' % path) try: p = Popen(path, stdout=PIPE, stderr=PIPE) p = None return True except Exception, e: plugin.log('error = %s' % e)
def ready (): global MAKEMKVCON, MAKEMKVCONPID if not MAKEMKVCON and not MAKEMKVCONPID: return False try: up = connect() up.close() return True except Exception, e: plugin.log('ERROR: %s' % e) pass
def execute_many(self, SQL, data, silent=False): if SQL.startswith('REPLACE INTO'): SQL = 'INSERT OR ' + SQL try: self.lock.acquire(True) self.DBC.executemany(SQL, data) except Exception, e: if IGNORE_UNIQUE_ERRORS and re.match(self._unique_str, str(e)): if silent is False: plugin.raise_error("Database error", e) plugin.log("Database execute error: %s" % e) plugin.log("Database execute error: %s" % SQL)
def execute_many(self, SQL, data, silent=False): self.check_connection() try: self.lock.acquire(True) SQL = SQL.replace('?', '%s') self.DBC.executemany(SQL, data) except Exception, e: if IGNORE_UNIQUE_ERRORS and re.match(self._unique_str, str(e)): if silent is False: plugin.raise_error("Database error", e) plugin.log("Database execute error: %s" % e) plugin.log("Database execute error: %s" % SQL)
def commit(self, quiet=False): if self.db_type == 'sqlite' and quiet is False: plugin.log("Commiting to %s" % self.db_file, LOG_LEVEL.VERBOSE) elif quiet is False: plugin.log("Commiting to %s on %s" % (self.dbname, self.host), LOG_LEVEL.VERBOSE) try: self.lock.acquire(True) self.DBH.commit() except: pass finally: self.lock.release()
def start (): global MAKEMKVCON, MAKEMKVCONPID if MAKEMKVCON or MAKEMKVCONPID: return # Find existing for d in os.listdir('/proc'): p = os.path.join('/proc', d, 'cmdline') if os.path.isfile(p): try: if 'makemkvcon' in open(p).read(): MAKEMKVCONPID = int(d) plugin.log('existing makemkvcon pid %d' % MAKEMKVCONPID) return except Exception, e: plugin.log('ERROR: %s' % e)
def start(job): job['tmp_dir'] = tempfile.mkdtemp(suffix='.mkvripper', dir=job['dest_writepath']) ripsize_min = plugin.get('ripsize_min', '600') cmd = plugin.get('makemkvcon_path', 'makemkvcon') cmd = [cmd, '-r', '--progress=-stdout', '--minlength=%s' % ripsize_min, 'mkv', 'dev:%s' % job['dev'], 'all', job['tmp_dir']] job['cmd'] = cmd job['output'] = subprocess.Popen(job['cmd'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True) job['pid'] = job['output'].pid plugin.log(plugin.lang(50021) % job['cmd']) #started new makemkvcon with command %s return job
def updateLicense(): # Fetch latest key key = getBeta() # Nothing to update if not key: return False # Already up to date cur = get(APP_KEY) if cur == key: return False # Write tmpfile plugin.log('updating license key %s' % key) set(APP_KEY, key) return True
def query(self, SQL, data=None, force_double_array=False, silent=False): try: self.lock.acquire(True) if data: self.DBC.execute(SQL, data) else: self.DBC.execute(SQL) rows = self.DBC.fetchall() if (len(rows) == 1 and not force_double_array): return rows[0] else: return rows except Exception, e: if 'no such table: version' not in str(e).lower(): plugin.raise_error("Database error", e) plugin.log("Database query error: %s" % e) plugin.log("Database query error: %s" % SQL) return []
def updateLicense(): # Fetch latest key key = getBeta() # Nothing to update if not key: return False # Already up to date cur = get(APP_KEY) if cur == key: return False # Write tmpfile plugin.log("updating license key %s" % key) set(APP_KEY, key) return True
def _connect(self, quiet=False): try: import mysql.connector as database if not self.quiet and not quiet: plugin.log("%s loading mysql.connector as DB engine" % ADDON_NAME) dsn = { "database": self.dbname, "host": self.host, "port": int(self.port), "user": str(self.username), "password": str(self.password), "buffered": True } self.DBH = database.connect(**dsn) except Exception, e: plugin.log('****** %s SQL ERROR: %s' % (ADDON_NAME, e)) plugin.raise_error("MySQL Error", e) sys.exit()
def set(key, val): # Create directories dirp = os.path.dirname(CONFPATH) if not os.path.exists(dirp): os.makedirs(dirp) # Create tmp file plugin.log('update makemkv config %s = %s' % (key, val)) fp = open(CONFPATH + '.tmp', 'w') if os.path.exists(CONFPATH): for l in open(CONFPATH): if l.startswith(key): continue fp.write(l) fp.write('%s = "%s"\n' % (key, val)) fp.close() # Replace if os.path.exists(CONFPATH): os.unlink(CONFPATH) os.rename(CONFPATH + '.tmp', CONFPATH)
def query_assoc(self, SQL, data=None, force_double_array=False, silent=False): self.check_connection() try: self.lock.acquire(True) if data: SQL = SQL.replace('?', '%s') self.DBC.execute(SQL, data) else: self.DBC.execute(SQL) rows = self.DBC.fetchall() if (len(rows) == 1 and not force_double_array): d = {} for idx, col in enumerate(self.DBC.column_names): d[col] = rows[0][idx] return d else: set = [] for row in rows: d = {} for idx, col in enumerate(self.DBC.column_names): d[col] = row[idx] set.append(d) return set except Exception, e: error_msg = "Database query error: %s" % e if silent is False: plugin.raise_error("Database error", e) plugin.log(error_msg) plugin.log("Database query error: %s" % SQL) plugin.log(data) return []
def set(key, val): # Create directories dirp = os.path.dirname(CONFPATH) if not os.path.exists(dirp): os.makedirs(dirp) # Create tmp file plugin.log("update makemkv config %s = %s" % (key, val)) fp = open(CONFPATH + ".tmp", "w") if os.path.exists(CONFPATH): for l in open(CONFPATH): if l.startswith(key): continue fp.write(l) fp.write('%s = "%s"\n' % (key, val)) fp.close() # Replace if os.path.exists(CONFPATH): os.unlink(CONFPATH) os.rename(CONFPATH + ".tmp", CONFPATH)
def save(job): if not running(): l = os.listdir(job['tmp_dir']) if l == []: cleanup(job) raise TmpDirEmpty('temporary directory empty!') for i in l: src = os.path.join(job['tmp_dir'], i) if len(l) >= 2: dest = os.path.join(job['dest_writepath'], job['dest_savename'] + i[-6:]) #save as numbered .mkv file if there is more than one file to be saved else: dest = os.path.join(job['dest_writepath'], job['dest_savename'] + i[-4:]) #save without numbered suffix if only one .mkv file to be saved try: shutil.move(src, dest) except Exception, e: plugin.log(plugin.lang(50022) % e.strerror) #makemkvcon.save() ERROR: %s cleanup(job) raise cleanup(job)
def getBeta(): plugin.log('fetching beta key from %s' % BETAURL) for l in urllib.urlopen(BETAURL): res = BETAEXP.search(l) if res: plugin.log('latest beta key %s' % res.group(1)) return res.group(1) plugin.log('no beta key found') return None
def getBeta(): plugin.log("fetching beta key from %s" % BETAURL) for l in urllib.urlopen(BETAURL): res = BETAEXP.search(l) if res: plugin.log("latest beta key %s" % res.group(1)) return res.group(1) plugin.log("no beta key found") return None
def _connect(self, quiet=False): vfs = VFSClass() if not self.quiet and not quiet: plugin.log("Connecting to " + self.db_file, LOG_LEVEL.VERBOSE) try: from sqlite3 import dbapi2 as database if not self.quiet and not quiet: plugin.log("%s loading sqlite3 as DB engine" % ADDON_NAME) except: from pysqlite2 import dbapi2 as database if not self.quiet and not quiet: plugin.log("%s loading pysqlite2 as DB engine" % ADDON_NAME) if not self.quiet and not quiet: plugin.log("Connecting to SQLite on: " + self.db_file) directory = os.path.dirname(self.db_file) if not vfs.exists(directory): vfs.mkdir(directory) self.DBH = database.connect(self.db_file, check_same_thread=False) try: self.DBC = self.DBH.cursor() except Exception, e: plugin.raise_error("SqlLite Error", e) sys.exit()
def start(): global MAKEMKVCON if running(): plugin.log('makemkvcon already running') return # Find existing for d in os.listdir('/proc'): p = os.path.join('/proc', d, 'cmdline') if os.path.isfile(p): try: if 'makemkvcon' in open(p).read(): MAKEMKVCONPID = int(d) plugin.log('existing makemkvcon pid %d' % MAKEMKVCONPID) return except Exception, e: plugin.log('ERROR: %s' % e)
def query(self, SQL, data=None, force_double_array=False, silent=False): self.check_connection() try: self.lock.acquire(True) if data: SQL = SQL.replace('?', '%s') self.DBC.execute(SQL, data) else: self.DBC.execute(SQL) rows = self.DBC.fetchall() if (len(rows) == 1 and not force_double_array): return rows[0] else: return rows except Exception, e: error_msg = "Database query error: %s" % e if silent is False: plugin.raise_error("Database error", e) plugin.log(error_msg) plugin.log("Database query error: %s" % SQL) plugin.log(data) return []
# ############################################################################ # Module Setup/Info # ############################################################################ # Global imports import os, sys, time import xbmc, xbmcaddon # Addon info __addon__ = xbmcaddon.Addon() __cwd__ = __addon__.getAddonInfo('path') sys.path.append(xbmc.translatePath(os.path.join(__cwd__, 'lib'))) # Local imports import plugin, makemkv, makemkvcon plugin.log('starting service') # Settings BDDIR = 'BDMV' # Check for makemkvcon if not makemkvcon.installed(): plugin.notify(plugin.lang(50001)) # Config for k in [ 'license_key', 'license_beta_auto', 'license_beta_period', 'disc_autoload', 'disc_autostart', 'disc_timeout' ]: v = plugin.get(k) plugin.log('config %s => %s' % (k, v)) # Service loop key_checked = 0
for d in os.listdir('/proc'): p = os.path.join('/proc', d, 'cmdline') if os.path.isfile(p): try: if 'makemkvcon' in open(p).read(): MAKEMKVCONPID = int(d) plugin.log('existing makemkvcon pid %d' % MAKEMKVCONPID) return except Exception, e: plugin.log('ERROR: %s' % e) # Start new cmd = plugin.get('makemkvcon_path', 'makemkvcon') cmd = [ cmd, '-r', '--cache=128', 'stream', 'disc:0' ] MAKEMKVCON = Popen(cmd, stdout=PIPE, stderr=PIPE) plugin.log('started new makemkvcon') return # # Get remote address # def getHostPort (): host = plugin.get('makemkv_host', 'localhost') port = int(plugin.get('makemkv_port', 51000)) return 'http://%s:%d' % (host, port) # # Connect # def connect ( path = '/' ): url = getHostPort() + path
def __init__(self): global MAKEMKVCON dialog = xbmcgui.Dialog() if not makemkvcon.installed(): plugin.log(plugin.lang(50008)) #makemkvcon binary not found if dialog.ok(plugin.lang(50015), plugin.lang(50008)): #makemkvcon binary not found. Install MakeMKV or adjust makemkvcon binary path setting. self.close() return job = {} job['dev'] = plugin.get('disc_number', '/dev/sr0') #configurable in settings starting = dialog.yesno(__addonname__, plugin.lang(50011) % job['dev']) #Rip media from disc on <disc>? if starting: #is cdrom Device? info = open('/proc/sys/dev/cdrom/info').read() dev = job['dev'].split('/')[-1] if dev not in info: if dialog.ok(plugin.lang(50015), plugin.lang(50002)): #Disc drive device file not reported as CDROM device. Adjust disc drive device file setting. self.close() return job_running = makemkvcon.running(job['dev']) if job_running: if dialog.yesno(__addonname__, plugin.lang(50012) % job['dev'], nolabel=plugin.lang(52001), yeslabel=plugin.lang(52002)): #Rip operation already running on <disc>. Cancel running operation and start over or exit? job['pid'] = job_running makemkvcon.kill(job) else: plugin.log(plugin.lang(50010)) #User did not select a disc rip operation. self.close() return while True: job['dest_writepath'] = dialog.browse(3, plugin.lang(51001), 'video', '', False, False, '') if job['dest_writepath'] == '': self.close() return kb = xbmc.Keyboard('', plugin.lang(51002)) kb.doModal() if kb.isConfirmed(): job['dest_savename'] = kb.getText() if job['dest_savename'] == '': job['dest_savename'] = plugin.lang(51003) #title.mkv for single file or titleXX.mkv for multiple files are default savenames break p_dialog = xbmcgui.DialogProgress() MAKEMKVCON = makemkvcon.start(job) p_dialog.create(__addonname__, plugin.lang(50005) % MAKEMKVCON['dev']) #Scanning media in <disc> pipe = MAKEMKVCON['output'] label = plugin.lang(50006) % MAKEMKVCON['dev'] #Ripping files from media in <disc> percent = 0 while True: line = pipe.stdout.readline() if not line: break if line.startswith('MSG:'): msg = line.split('"')[1] if line.startswith('MSG:5038'): #Disc space error; is a prompt. makemkvcon.kill(MAKEMKVCON, '-STOP') if dialog.yesno(__addonname__, msg): line = '' makemkvcon.kill(MAKEMKVCON, '-CONT') else: sys.stdout.flush() makemkvcon.kill(MAKEMKVCON) MAKEMKVCON = None self.close() return if line.startswith('MSG:5010'): #Failed to open disc error. Can stem from a number of things such as tray status and inserted media type. makemkvcon.kill(MAKEMKVCON, '-STOP') msg = 'makemkvcon: %s %s' % (msg, plugin.lang(50004)) #Failed to open disc, ensure correct media inserted and device tray closed. if dialog.ok(plugin.lang(50015), msg): sys.stdout.flush() makemkvcon.kill(MAKEMKVCON) MAKEMKVCON = None self.close() return if msg.startswith('Error'): #Kind of a lame way to catch an error, but reading makemkvcon's output works for HDD space issues as well as tray issues. makemkvcon.kill(MAKEMKVCON, '-STOP') msg = 'makemkvcon: %s' % msg if dialog.ok(plugin.lang(50015), msg): sys.stdout.flush() makemkvcon.kill(MAKEMKVCON) MAKEMKVCON = None self.close() return if line.startswith('PRGV:'): #Monitor rip progress for progress bar line = line.split(',') n = float(line[1]) d = float(line[2]) percent = int(n / d * 100) if p_dialog.iscanceled(): makemkvcon.kill(MAKEMKVCON, '-STOP') if dialog.yesno(__addonname__, plugin.lang(50003) % MAKEMKVCON['dev']): #Cancel rip operation on <disc>? makemkvcon.kill(MAKEMKVCON) MAKEMKVCON = None p_dialog.close() self.close() return else: makemkvcon.kill(MAKEMKVCON, '-CONT') p_dialog.create(__addonname__, plugin.lang(50005) % MAKEMKVCON['dev']) #Scanning media in <disc> p_dialog.update(percent, label, msg) sys.stdout.flush() p_dialog.update(100, plugin.lang(50016) % MAKEMKVCON['dest_writepath']) #Moving titles from temporary directory to <savedir> try: makemkvcon.save(MAKEMKVCON) except makemkvcon.TmpDirEmpty: #Is temporary directory empty after rip has completed successfully? if dialog.ok(plugin.lang(50015), plugin.lang(50023)): #Plugin detected that makemkvcon ripped no files but exited successfully. self.close() return except Exception, e: #some other error with shutil.move() if dialog.ok(plugin.lang(50015), e.strerror): self.close() return plugin.notify(plugin.lang(50013) % (MAKEMKVCON['dev'], MAKEMKVCON['dest_writepath']), timeout=10000) #Rip finished on <disc>. New files in <savedir> MAKEMKVCON = None
def connect(path='/'): url = getHostPort() + path plugin.log('connect to %s' % url) return urllib.urlopen(url)
for d in os.listdir('/proc'): p = os.path.join('/proc', d, 'cmdline') if os.path.isfile(p): try: if 'makemkvcon' in open(p).read(): MAKEMKVCONPID = int(d) plugin.log('existing makemkvcon pid %d' % MAKEMKVCONPID) return except Exception, e: plugin.log('ERROR: %s' % e) # Start new cmd = plugin.get('makemkvcon_path', 'makemkvcon') cmd = [cmd, '-r', '--cache=128', 'stream', 'disc:0'] MAKEMKVCON = Popen(cmd, stdout=PIPE, stderr=PIPE) plugin.log('started new makemkvcon') return # # Get remote address # def getHostPort(): host = plugin.get('makemkv_host', 'localhost') port = int(plugin.get('makemkv_port', 51000)) return 'http://%s:%d' % (host, port) # # Connect #
def playTitle(title): plugin.log('playing %s' % title['file0']) xbmc.executebuiltin('PlayMedia("%s")' % title['file0'])
def playTitle(title): plugin.log("playing %s" % title["file0"]) xbmc.executebuiltin('PlayMedia("%s")' % title["file0"])
# Parse query string def parseQuery (): ret = {} if sys.argv[2].startswith('?'): tmp = urlparse.parse_qs(sys.argv[2][1:]) for k in tmp: ret[k] = tmp[k][0] return ret # Play a title def playTitle ( title ): plugin.log('playing %s' % title['file0']) xbmc.executebuiltin('PlayMedia("%s")' % title['file0']) # Check installed plugin.log('checking makemkvcon installed') if not makemkvcon.installed(): plugin.notify(plugin.lang(50001)) sys.exit(1) # Start makemkvcon.start() # Check that service is running st = time.time() ok = False # TODO: dialog while not ok and (time.time() - st) < plugin.get_int('disc_timeout'): plugin.log('waiting for makemkvcon') ok = makemkvcon.ready() time.sleep(0.5)
def playTitle ( title ): plugin.log('playing %s' % title['file0']) xbmc.executebuiltin('PlayMedia("%s")' % title['file0'])
def connect ( path = '/' ): url = getHostPort() + path plugin.log('connect to %s' % url) return urllib.urlopen(url)
self.close() return else: makemkvcon.kill(MAKEMKVCON, '-CONT') p_dialog.create(__addonname__, plugin.lang(50005) % MAKEMKVCON['dev']) #Scanning media in <disc> p_dialog.update(percent, label, msg) sys.stdout.flush() p_dialog.update(100, plugin.lang(50016) % MAKEMKVCON['dest_writepath']) #Moving titles from temporary directory to <savedir> try: makemkvcon.save(MAKEMKVCON) except makemkvcon.TmpDirEmpty: #Is temporary directory empty after rip has completed successfully? if dialog.ok(plugin.lang(50015), plugin.lang(50023)): #Plugin detected that makemkvcon ripped no files but exited successfully. self.close() return except Exception, e: #some other error with shutil.move() if dialog.ok(plugin.lang(50015), e.strerror): self.close() return plugin.notify(plugin.lang(50013) % (MAKEMKVCON['dev'], MAKEMKVCON['dest_writepath']), timeout=10000) #Rip finished on <disc>. New files in <savedir> MAKEMKVCON = None else: plugin.log(plugin.lang(50010)) #User did not select a disc rip operation. self.close() def onAction(self, action): if action == ACTION_PREVIOUS_MENU or KEY_BUTTON_BACK: self.close()
ret = {} if sys.argv[2].startswith('?'): tmp = urlparse.parse_qs(sys.argv[2][1:]) for k in tmp: ret[k] = tmp[k][0] return ret # Play a title def playTitle(title): plugin.log('playing %s' % title['file0']) xbmc.executebuiltin('PlayMedia("%s")' % title['file0']) # Check installed plugin.log('checking makemkvcon installed') if not makemkvcon.installed(): plugin.notify(plugin.lang(50001)) sys.exit(1) # Start makemkvcon.start() # Check that service is running st = time.time() ok = False # TODO: dialog while not ok and (time.time() - st) < plugin.get_int('disc_timeout'): plugin.log('waiting for makemkvcon') ok = makemkvcon.ready() time.sleep(0.5)
def cleanup(job): tmp_dir = job['tmp_dir'] try: shutil.rmtree(tmp_dir) except Exception, e: plugin.log(plugin.lang(50018) % e.strerror) #makemkvcon.cleanup() ERROR: %s
# ############################################################################ # Module Setup/Info # ############################################################################ # Global imports import os, sys, time import xbmc, xbmcaddon # Addon info __addon__ = xbmcaddon.Addon() __cwd__ = __addon__.getAddonInfo('path') sys.path.append(xbmc.translatePath(os.path.join(__cwd__, 'resources', 'lib'))) # Local imports import plugin, makemkv, makemkvcon plugin.log('starting service') # Settings BDDIR = 'BDMV' # Check for makemkvcon if not makemkvcon.installed(): plugin.notify(plugin.lang(50001)) # Service loop key_checked = 0 disc_current = None disc_started = 0 disc_ready = False while not xbmc.abortRequested: plugin.log('run')
xbmc.executebuiltin('PlayMedia("%s")' % title["file0"]) # Check installed if not makemkvcon.installed(): plugin.notify(plugin.lang(50001)) sys.exit(1) # Start # if not plugin.get('disc_autoload'): makemkvcon.start() # Check that service is running st = time.time() ok = False plugin.log("waiting for makemkvcon") while not ok and (time.time() - st) < int(plugin.get("disc_timeout")): ok = makemkvcon.ready() xbmc.sleep(100) if not ok: plugin.notify(plugin.lang(50006)) sys.exit(1) plugin.log("makemkvcon ready") # Process params = parseQuery() # Get titles titles = makemkvcon.listTitles() if not titles: plugin.notify(plugin.lang(50007))