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 []
Exemple #4
0
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)
Exemple #7
0
def ready():
    try:
        up = connect()
        up.close()
        return True
    except Exception, e:
        plugin.log('ERROR: %s' % e)
        pass
Exemple #8
0
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()
Exemple #28
0
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 []
Exemple #30
0
# ############################################################################
# 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
Exemple #33
0
def connect(path='/'):
    url = getHostPort() + path
    plugin.log('connect to %s' % url)
    return urllib.urlopen(url)
Exemple #34
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 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))