Exemplo n.º 1
0
def do_edit(options):
    """Downloadliste anzeigen und editieren"""

    # Liste lesen
    rows = options.filmDB.read_downloads()
    if not rows:
        Msg.msg("INFO", "Keine vorgemerkten Filme vorhanden")
        return

    # Liste aufbereiten
    select_liste = []
    for row in rows:
        status = row['STATUS']
        datum_status = row['DATUMSTATUS'].strftime("%d.%m.%y")
        sender = row['SENDER']
        thema = row['THEMA']
        titel = row['TITEL']
        dauer = row['DAUER']
        datum = row['DATUM'].strftime("%d.%m.%y")

        select_liste.append(
            DLL_FORMAT.format(status, datum_status, sender, thema, datum,
                              dauer, titel))
    selected = pick(select_liste, DLL_TITEL, multi_select=True)

    # IDs extrahieren und Daten löschen
    deletes = []
    for sel_text, sel_index in selected:
        row = rows[sel_index]
        deletes.append((row['_ID'], ))
    if len(deletes):
        changes = options.filmDB.delete_downloads(deletes)
    else:
        changes = 0
    Msg.msg("INFO", "%d vorgemerkte Filme gelöscht" % changes)
Exemplo n.º 2
0
def suche():
    # Auslesen Request-Parameter
    such_args = []
    token = bottle.request.forms.get('global')
    if token:
        such_args.append(token)
    for arg in ['sender', 'thema', 'datum', 'titel', 'bechreibung']:
        token = bottle.request.forms.get(arg)
        if token:
            such_args.append(arg + ':' + token)
    Msg.msg("DEBUG", "Suchbegriffe: " + str(such_args))

    # Film-DB abfragen
    statement = options.filmDB.get_query(such_args)
    rows = options.filmDB.execute_query(statement)

    # Ergebnis aufbereiten
    result = []
    for row in rows:
        item = {}
        item['DATUM'] = row['DATUM'].strftime("%d.%m.%y")
        for key in [
                'SENDER', 'THEMA', 'TITEL', 'DAUER', 'BESCHREIBUNG', '_ID'
        ]:
            item[key] = row[key]
        result.append(item)

    Msg.msg("DEBUG", "Anzahl Treffer: %d" % len(result))
    bottle.response.content_type = 'application/json'
    return json.dumps(result)
Exemplo n.º 3
0
def get_datei():
  """ Datei herunterladen """

  # get name-parameter
  dateiname = bottle.request.query.getunicode('name')
  Msg.msg("DEBUG", "Downloadanforderung (Dateiname: %s)" % dateiname)

  bottle.response.content_type = 'application/json'

  if dateiname is None:
    msg = '"kein Dateiname angegeben"'
    bottle.response.status       = 400                 # bad request
    return '{"msg": ' + msg +'}'

  # Überprüfen, ob Dateiname in Film-DB existiert
  rows = options.filmDB.read_recs(dateiname)
  if not rows:
    Msg.msg("WARN", "Dateiname %s nicht in Film-DB" % dateiname)
    msg = '"Ungültiger Dateiname"'
    bottle.response.status       = 400                 # bad request
    return '{"msg": ' + msg +'}'

  if not os.path.exists(dateiname):
    msg = '"Dateiname existiert nicht"'
    bottle.response.status       = 404                # not found
    return '{"msg": ' + msg +'}'

  # Datei roh herunterladen
  bottle.response.content_type = 'application/mp4'
  f = '"'+os.path.basename(dateiname)+'"'
  bottle.response.set_header('Content-Disposition','attachment; filename=%s' % f)
  return subprocess.check_output(['cat',dateiname])
Exemplo n.º 4
0
def download_film(options, film):
    """Download eines einzelnen Films"""

    # Infos zusammensuchen
    _id = film._id
    size, url = film.get_url(options.config["QUALITAET"])
    film.thema = film.thema.replace('/', '_')
    film.titel = film.titel.replace('/', '_')
    ziel = options.config["ZIEL_DOWNLOADS"].format(ext=url.split(".")[-1],
                                                   **film.asDict())
    cmd = options.config["CMD_DOWNLOADS"].format(ziel=ziel, url=url)

    # Zielverzeichnis erstellen
    ziel_dir = os.path.dirname(ziel)
    if not os.path.exists(ziel_dir):
        os.mkdirs(ziel_dir)

    # Download ausführen
    options.filmDB.update_downloads(_id, 'A')
    Msg.msg("INFO", "Start Download (%s) %s" % (size, film.titel[0:50]))
    p = subprocess.Popen(shlex.split(cmd), stdout=DEVNULL, stderr=STDOUT)
    p.wait()
    rc = p.returncode
    Msg.msg(
        "INFO", "Ende  Download (%s) %s (Return-Code: %d)" %
        (size, film.titel[0:50], rc))
    if rc == 0:
        options.filmDB.update_downloads(_id, 'K')
    else:
        options.filmDB.update_downloads(_id, 'F')

    return rc
Exemplo n.º 5
0
def del_datei():
  """ Datei löschen """

  # get name-parameter
  dateiname = bottle.request.forms.getunicode('name')
  Msg.msg("DEBUG", "Löschanforderung (Dateiname: %s)" % dateiname)

  bottle.response.content_type = 'application/json'

  if dateiname is None:
    msg = '"kein Dateiname angegeben"'
    bottle.response.status       = 400                 # bad request
    return '{"msg": ' + msg +'}'

  # Datei in der Aufname-DB suchen und dann löschen
  rows = options.filmDB.read_recs(dateiname)
  if not rows:
    Msg.msg("WARN", "Dateiname %s nicht in Film-DB" % dateiname)
    msg = '"Ungültiger Dateiname"'
    bottle.response.status = 400                 # bad request
  elif os.path.exists(dateiname):
    os.unlink(dateiname)
    options.filmDB.delete_recs([(dateiname,)])
    msg = '"Datei erfolgreich gelöscht"'
    bottle.response.status = 200                 # OK
    Msg.msg("INFO", "Dateiname %s gelöscht" % dateiname)
  else:
    msg = '"Datei existiert nicht"'
    bottle.response.status = 400                 # bad request
    Msg.msg("WARN", "Dateiname %s existiert nicht" % dateiname)

  return '{"msg": ' + msg +'}'
Exemplo n.º 6
0
def dateien():
  # Film-DB abfragen
  rows = options.filmDB.read_recs()
  if not rows:
    Msg.msg("DEBUG","Keine Dateien gefunden")
    return "{[]}"

  # Liste aufbereiten
  result = []
  deleted = []
  for row in rows:
    dateiname = row['DATEINAME']
    if not os.path.exists(dateiname):
      Msg.msg("WARN","Datei %s existiert nicht" % dateiname)
      deleted.append((dateiname,))
      continue
      
    item = {}
    item['DATEI']       = os.path.basename(dateiname)
    item['DATUMFILM']   = row['DATUMFILM'].strftime("%d.%m.%y")
    item['DATUMDATEI']  = row['DATUMDATEI'].strftime("%d.%m.%y")
    for key in ['SENDER','TITEL','BESCHREIBUNG','DATEINAME']:
      item[key] = row[key]
    result.append(item)

  # Löschen nicht mehr vorhandener Dateien
  if deleted:
    Msg.msg("DEBUG","Lösche %d Einträge in Aufnahmelisteliste" % len(deleted))
    options.filmDB.delete_recs(deleted)

  # Ergebnis ausliefern
  Msg.msg("DEBUG","Anzahl Einträge in Dateilisteliste: %d" % len(result))
  bottle.response.content_type = 'application/json'
  return json.dumps(result)
Exemplo n.º 7
0
def do_later(options):
    """Filmliste anzeigen, Auswahl für späteren Download speichern"""
    rows = filme_suchen(options)
    if rows:
        if options.doBatch:
            selected = [('dummy', i) for i in range(len(rows))]
        else:
            selected = zeige_liste(rows)
        changes = save_selected(options.filmDB, rows, selected, "V")
        Msg.msg(
            "INFO", "%d von %d Filme vorgemerkt für den Download" %
            (changes, len(selected)))
    else:
        Msg.msg("INFO", "Keine Suchtreffer")
Exemplo n.º 8
0
  def delete_downloads(self,rows):
    """Downloads löschen"""
    DEL_STMT = "DELETE FROM downloads where _id=?"

    Msg.msg("DEBUG","rows: " + str(rows))

    # Ein Lock ist hier nicht nötig, da Downloads immer in
    # einem eigene Aufruf von mtv_cli stattfinden

    cursor = self.open()
    cursor.executemany(DEL_STMT,rows)
    changes = self.db.total_changes
    self.commit()
    self.close()
    return changes
Exemplo n.º 9
0
def loeschen():
    # Auslesen Request-Parameter
    ids = bottle.request.forms.get('ids').split(" ")
    Msg.msg("DEBUG", "IDs: " + str(ids))

    if len(ids):
        # delete_downloads braucht Array von Tuplen
        changes = options.filmDB.delete_downloads([(id, ) for id in ids])
    else:
        changes = 0
    Msg.msg("INFO", "%d vorgemerkte Filme gelöscht" % changes)

    bottle.response.content_type = 'application/json'
    msg = '"%d vorgemerkte Filme gelöscht"' % changes
    return '{"msg": ' + msg + '}'
Exemplo n.º 10
0
    def delete_recs(self, rows):
        """ Aufnahme löschen.
        rows ist Array von Tuplen: [(name,),(name,), ...]"""
        DEL_STMT = "DELETE FROM recordings where Dateiname=?"

        Msg.msg("DEBUG", "rows: " + str(rows))

        # Ein Lock ist hier nicht nötig, da Downloads immer in
        # einem eigene Aufruf von mtv_cli stattfinden

        cursor = self.open()
        cursor.executemany(DEL_STMT, rows)
        changes = self.db.total_changes
        self.commit()
        self.close()
        return changes
Exemplo n.º 11
0
def status():
    result = {"_akt": "00.00.0000", "_anzahl": "0"}
    try:
        rows = options.filmDB.read_status(['_akt', '_anzahl'])
        for row in rows:
            key = row['key']
            if key == "_akt":
                tstamp = row['Zeit'].strftime("%d.%m.%Y %H:%M:%S")
                result[key] = tstamp
            else:
                text = row['text']
                result[key] = text
    except:
        pass
    Msg.msg("DEBUG", "Status: " + str(result))
    bottle.response.content_type = 'application/json'
    return json.dumps(result)
Exemplo n.º 12
0
  def read_status(self,keys):
    """Status aus Status-Tabelle auslesen"""

    SEL_STMT = "SELECT * FROM status WHERE key in %s" % str(tuple(keys))
    rows = None
    try:
      self.lock.acquire()
      cursor = self.open()
      cursor.execute(SEL_STMT)
      rows = cursor.fetchall()
      self.close()
    except sqlite3.OperationalError as e:
      Msg.msg("DEBUG","SQL-Fehler: %s" % e)
      rows = None
    finally:
      self.lock.release()
      return rows
Exemplo n.º 13
0
def do_now(options):
    """Filmliste anzeigen, sofortiger Download nach Auswahl"""
    rows = filme_suchen(options)
    if rows:
        if options.doBatch:
            selected = [('dummy', i) for i in range(len(rows))]
        else:
            selected = zeige_liste(rows)
        changes = save_selected(options.filmDB, rows, selected, "S")
        Msg.msg(
            "INFO", "%d von %d Filme vorgemerkt für Sofort-Download" %
            (changes, len(selected)))

        # Anstoß Downlaod
        if changes > 0:
            do_download(options)
    else:
        Msg.msg("INFO", "Keine Suchtreffer")
Exemplo n.º 14
0
def do_update(options):
    """Update der Filmliste"""

    if options.upd_src == "auto":
        src = random.choice(URL_FILMLISTE)
    elif options.upd_src == "json":
        # existierende Filmliste verwenden
        src = os.path.join(MTV_CLI_HOME, "filme.json")
    else:
        src = options.upd_src

    Msg.msg("INFO", "Erzeuge %s aus %s" % (options.dbfile, src))
    try:
        if src.startswith("http"):
            fpin = get_lzma_fp(get_url_fp(src))
        else:
            fpin = open(src, "r", encoding='utf-8')
        split_content(fpin, options.filmDB)
    finally:
        fpin.close()
Exemplo n.º 15
0
def downloads():
    # Film-DB abfragen
    rows = options.filmDB.read_downloads()
    if not rows:
        Msg.msg("DEBUG", "Keine vorgemerkten Filme vorhanden")
        return "{}"

    # Liste aufbereiten
    result = []
    for row in rows:
        item = {}
        item['DATUM'] = row['DATUM'].strftime("%d.%m.%y")
        item['DATUMSTATUS'] = row['DATUMSTATUS'].strftime("%d.%m.%y")
        for key in ['STATUS', 'SENDER', 'THEMA', 'TITEL', 'DAUER', '_ID']:
            item[key] = row[key]
        result.append(item)

    Msg.msg("DEBUG", "Anzahl Einträge in Downloadliste: %d" % len(result))
    bottle.response.content_type = 'application/json'
    return json.dumps(result)
Exemplo n.º 16
0
  def read_downloads(self,ui=True,status="'V','S','A','F','K'"):
    """Downloads auslesen. Falls ui=True, Subset für Anzeige.
       Bedeutung der Status-Codes:
       V - Vorgemerkt
       S - Sofort
       A - Aktiv
       F - Fehler
       K - Komplett
    """

    # SQL-Teile
    if ui:
      SEL_STMT = """SELECT d.status      as status,
                           d.DatumStatus as DatumStatus,
                           d._id         as _id,
                           f.sender      as sender,
                           f.thema       as thema,
                           f.titel       as titel,
                           f.dauer       as dauer,
                           f.datum       as datum
                      FROM filme as f, downloads as d
                        WHERE f._id = d._id AND d.status in (%s)
                        ORDER BY DatumStatus DESC""" % status
    else:
      SEL_STMT = """SELECT f.*
                      FROM filme as f, downloads as d
                        WHERE f._id = d._id AND d.status in (%s)""" % status

    Msg.msg("DEBUG","SQL-Query: %s" % SEL_STMT)
    cursor = self.open()
    try:
      cursor.execute(SEL_STMT)
      rows = cursor.fetchall()
    except sqlite3.OperationalError as e:
      Msg.msg("DEBUG","SQL-Fehler: %s" % e)
      rows = None
    self.close()
    if ui:
      return rows
    else:
      return [FilmInfo(*row) for row in rows]
Exemplo n.º 17
0
    def read_recs(self, Dateiname=None):
        """Aufnahmen auslesen. """

        if Dateiname:
            SEL_STMT = "SELECT * from recordings where Dateiname=?"
        else:
            SEL_STMT = "SELECT * from recordings"

        Msg.msg("DEBUG", "SQL-Query: %s" % SEL_STMT)
        cursor = self.open()
        try:
            if Dateiname:
                cursor.execute(SEL_STMT, (Dateiname, ))
            else:
                cursor.execute(SEL_STMT)
            rows = cursor.fetchall()
        except sqlite3.OperationalError as e:
            Msg.msg("DEBUG", "SQL-Fehler: %s" % e)
            rows = None
        self.close()
        return rows
Exemplo n.º 18
0
def download_filme(options,status="'V','F','A'"):
  # Filme lesen
  filme = options.filmDB.read_downloads(ui=False,status=status)

  if not filme:
    Msg.msg("INFO","Keine vorgemerkten Filme vorhanden")
    return

  if options.config["NUM_DOWNLOADS"] == 1:
    # Spezialbehandlung (erleichtert Debugging)
    for film in filme:
      download_film(options,film)
  else:
    with ThreadPool(options.config["NUM_DOWNLOADS"]) as pool:
      results = []
      for film in filme:
        pool.apply_async(download_film,(options,film))
      pool.close()
      pool.join()

  options.filmDB.save_status('_download')
Exemplo n.º 19
0
def download_film(options,film):
  """Download eines einzelnen Films"""

  # Infos zusammensuchen
  _id = film._id
  size,url = film.get_url(options.config["QUALITAET"])
  film.thema = film.thema.replace('/','_')
  film.titel = film.titel.replace('/','_')
  ext        = url.split(".")[-1].lower()

  # Kommando bei Playlisten anpassen. Die Extension der gespeicherten Datei
  # wird auf mp4 geändert
  if ext.startswith('m3u'):
    cmd   = options.config["CMD_DOWNLOADS_M3U"]
    ext   = 'mp4'
    isM3U = True
  else:
    cmd = options.config["CMD_DOWNLOADS"]
    isM3U = False

  ziel = options.config["ZIEL_DOWNLOADS"].format(ext=ext, **film.asDict())
  cmd = cmd.format(ziel=ziel,url=url)

  # Zielverzeichnis erstellen
  ziel_dir = os.path.dirname(ziel)
  if not os.path.exists(ziel_dir):
    os.mkdirs(ziel_dir)

  # Download ausführen
  options.filmDB.update_downloads(_id,'A')
  Msg.msg("INFO","Start Download (%s) %s" % (size,film.titel[0:50]))
  if isM3U:
    Msg.msg("DEBUG","Kommando: %s" % cmd)
    p = subprocess.Popen(cmd,shell=True,stdout=DEVNULL, stderr=STDOUT)
  else:
    Msg.msg("DEBUG","Kommando: %r" % shlex.split(cmd))
    p = subprocess.Popen(shlex.split(cmd),stdout=DEVNULL, stderr=STDOUT)
  p.wait()
  rc = p.returncode
  Msg.msg("INFO",
      "Ende  Download (%s) %s (Return-Code: %d)" % (size,film.titel[0:50],rc))
  if rc==0:
    options.filmDB.update_downloads(_id,'K')
    options.filmDB.save_recs(_id,ziel)
  else:
    options.filmDB.update_downloads(_id,'F')

  return rc
Exemplo n.º 20
0
def vormerken():
    # Auslesen Request-Parameter
    ids = bottle.request.forms.get('ids').split(" ")
    dates = bottle.request.forms.get('dates').split(" ")
    Msg.msg("DEBUG", "IDs: " + str(ids))
    Msg.msg("DEBUG", "Datum: " + str(dates))

    inserts = []
    i = 0
    for id in ids:
        inserts.append((id, dates[i], 'V'))
        i += 1
    Msg.msg("DEBUG", "inserts: " + str(inserts))
    changes = options.filmDB.save_downloads(inserts)
    Msg.msg("DEBUG", "changes: " + str(changes))

    bottle.response.content_type = 'application/json'
    msg = '"%d von %d Filme vorgemerkt für den Download"' % (changes, len(ids))
    return '{"msg": ' + msg + '}'
Exemplo n.º 21
0
    if options.doVersionInfo:
        print("Version: %s" % VERSION)
        sys.exit(0)

    # Message-Klasse konfigurieren
    if options.level:
        Msg.level = options.level
    else:
        Msg.level = config["MSG_LEVEL"]

    # Verzeichnis HOME/.mediathek3 anlegen
    if not os.path.exists(MTV_CLI_HOME):
        os.mkdir(MTV_CLI_HOME)

    if not options.upd_src and not os.path.isfile(options.dbfile):
        Msg.msg("ERROR", "Datenbank %s existiert nicht!" % options.dbfile)
        sys.exit(3)

    # Lock anfordern
    if not get_lock(options.dbfile):
        Msg.msg("ERROR", "Datenbank %s ist gesperrt" % options.dbfile)
        sys.exit(3)

    # Globale Objekte anlegen
    options.config = config
    options.filmDB = FilmDB(options)

    if options.upd_src:
        do_update(options)
    elif options.doEdit:
        do_edit(options)
Exemplo n.º 22
0
    # Optionen lesen
    opt_parser = get_parser()
    options = opt_parser.parse_args(namespace=Options)

    # Message-Klasse konfigurieren
    if options.level:
        Msg.level = options.level
    else:
        Msg.level = config["MSG_LEVEL"]

    # Globale Objekte anlegen
    options.upd_src = "auto"
    options.config = config
    options.filmDB = FilmDB(options)

    # Server starten
    WEB_ROOT = get_webroot(__file__)
    Msg.msg("DEBUG", "Web-Root Verzeichnis: %s" % WEB_ROOT)
    if Msg.level == "DEBUG":
        Msg.msg("DEBUG", "Starte den Webserver im Debug-Modus")
        bottle.run(host='localhost',
                   port=config["PORT"],
                   debug=True,
                   reloader=True)
    else:
        bottle.run(host=config["HOST"],
                   port=config["PORT"],
                   debug=False,
                   reloader=False)
Exemplo n.º 23
0
  def get_query(self,suche):
    """Aus Suchbegriff eine SQL-Query erzeugen"""
    #Basisausdruck
    select_clause = "select * from Filme where "

    if not len(suche):
      return select_clause[0:-7]                 # remove " where "
    elif suche[0].lower().startswith("select"):
      # Suchausdruck ist fertige Query
      return ' '.join(suche)

    where_clause = ""
    op = ""
    for token in suche:
      if token in ["(","und","oder","and","or",")"]:
        if op:
          where_clause = where_clause + op
        op = " %s " % token
        continue
      if ':' in token:
        # Suche per Schlüsselwort
        key,value = token.split(":")
        if where_clause:
          where_clause = where_clause +  (op if op else " and ")
        if key.upper() == "DATUM":
          # Sonderbehandlung Datum:
          if (">" in value) or ("<" in value) or ("=" in value):
            # datum:=xxx, datum:>xxx, datum:>=xxx usw.
            if value[1] in ["<",">","="]:
              date_op = value[0:2]
              value = value[2:]
            else:
              date_op = value[0]
              value = value[1:]
            where_clause = where_clause + "(%s %s '%s')" % \
                           (key,date_op,self.iso_date(value))
          elif "-" in value:
            # datum:start-end
            limits = value.split("-")
            where_clause = where_clause + (
              "(%s >= '%s' and %s <= '%s')" % (key,self.iso_date(limits[0])
                                           ,key,self.iso_date(limits[1])))
          else:
            # datum:xxx (identisch zu datum:=xxx)
            where_clause = where_clause + "(%s='%s')" % (key,self.iso_date(value))
        else:
          where_clause = where_clause + "(%s like '%%%s%%')" % (key,value)
      else:
        # Volltextsuche
        if where_clause:
          where_clause = where_clause + (op if op else " or ")
        where_clause = where_clause + (
          """(Sender       like '%%%s%%' or
          Thema        like '%%%s%%' or
          Titel        like '%%%s%%' or
          Beschreibung like '%%%s%%')""" % (token,token,token,token))
      op = ""

    # falls noch ein Operator übrig ist:
    if op:
      where_clause = where_clause + op
    Msg.msg("DEBUG","SQL-Where: %s" % where_clause)
    return select_clause + where_clause
Exemplo n.º 24
0
def split_content(fpin, filmDB):
    """Inhalt aufteilen"""

    have_header = False
    last_rec = ""

    filmDB.create_filmtable()
    filmDB.isolation_level = None
    filmDB.cursor.execute("BEGIN;")

    total = 0
    buf_count = 0
    regex = re.compile(',\n? *"X" ?: ?')
    while True:
        # Buffer neu lesen
        buffer = fpin.read(BUFSIZE)
        buf_count = buf_count + 1
        if not buf_count % 100:
            Msg.msg("INFO", '.', False)

        # Verarbeitung Dateiende (verbliebenen Satz schreiben)
        if len(buffer) == 0:
            if len(last_rec):
                total = total + 1
                filmDB.insert_film(last_rec[0:-1])
                break

        # Sätze aufspalten
        records = regex.split(last_rec + str(buffer))
        Msg.msg("DEBUG", "Anzahl Sätze: %d" % len(records))

        # Sätze ausgeben. Der letzte Satz ist entweder leer,
        # oder er ist eigentlich ein Satzanfang und wird aufgehoben
        last_rec = records[-1]
        for record in records[0:-1]:
            Msg.msg("TRACE", record)
            if not have_header:
                have_header = True
                continue
            total = total + 1
            filmDB.insert_film(record)

    # Datensätze speichern und Datenbank schließen
    filmDB.commit()
    filmDB.save_filmtable()

    Msg.msg("INFO", "\n", False)
    Msg.msg("INFO", "Anzahl Buffer:              %d" % buf_count)
    Msg.msg("INFO", "Anzahl Sätze (gesamt):      %d" % total)
    Msg.msg("INFO", "Anzahl Sätze (gespeichert): %d" % filmDB.get_count())
Exemplo n.º 25
0
    def save_recs(self, id, Dateiname):
        """Aufnahme sichern."""

        Msg.msg("INFO", "Sichere Aufnahmen: %s,%s" % (id, Dateiname))
        CREATE_STMT = """CREATE TABLE IF NOT EXISTS recordings (
                     Sender       text,
                     Titel        text,
                     Beschreibung text,
                     DatumFilm    date,
                     Dateiname    text primary key,
                     DatumDatei   date)"""
        INSERT_STMT = """INSERT OR IGNORE INTO recordings Values (?,?,?,?,?,?)"""
        SEL_STMT = """SELECT sender,
                            titel,
                            beschreibung,
                            datum
                      FROM filme
                        WHERE _id = ?"""

        # ausgewählte Felder aus Film-DB lesen
        cursor = self.open()
        try:
            Msg.msg("DEBUG", "SQL-Query: %s" % SEL_STMT)
            cursor.execute(SEL_STMT, (id, ))
            row = cursor.fetchone()
        except sqlite3.OperationalError as e:
            Msg.msg("DEBUG", "SQL-Fehler: %s" % e)
            row = None

        for r in row:
            Msg.msg("INFO", "row: %r" % r)
        if not row:
            self.close()
            return

        # Tabelle bei Bedarf erstellen
        Msg.msg("DEBUG", "SQL-Create: %s" % CREATE_STMT)
        cursor.execute(CREATE_STMT)
        self.commit()

        # ohne Lock, da Insert mit neuem Schlüssel
        try:
            self.lock.acquire()
            Msg.msg("DEBUG", "SQL-Insert: %s" % INSERT_STMT)
            cursor.execute(
                INSERT_STMT,
                tuple(row[i] for i in range(len(row))) +
                (Dateiname, datetime.date.today()))
            self.commit()
        except sqlite3.OperationalError as e:
            Msg.msg("DEBUG", "SQL-Fehler: %s" % e)
        finally:
            self.lock.release()
        self.close()