158 lines
5.9 KiB
Python
158 lines
5.9 KiB
Python
#!/usr/bin/env python
|
|
# -*- coding: utf-8 -*-
|
|
from __future__ import absolute_import, division, unicode_literals
|
|
from threading import Lock
|
|
|
|
from .. import db, path_ops
|
|
|
|
KODIDB_LOCK = Lock()
|
|
# Names of tables we generally leave untouched and e.g. don't wipe
|
|
UNTOUCHED_TABLES = ('version', 'versiontagscan')
|
|
|
|
|
|
class KodiDBBase(object):
|
|
"""
|
|
Kodi database methods used for all types of items
|
|
"""
|
|
def __init__(self, texture_db=False, kodiconn=None, artconn=None,
|
|
lock=True, wal_mode=True):
|
|
"""
|
|
Allows direct use with a cursor instead of context mgr
|
|
Pass wal_mode=False if you want the standard sqlite journal_mode, e.g.
|
|
when wiping entire tables
|
|
"""
|
|
self._texture_db = texture_db
|
|
self.lock = lock
|
|
self.kodiconn = kodiconn
|
|
self.cursor = self.kodiconn.cursor() if self.kodiconn else None
|
|
self.artconn = artconn
|
|
self.artcursor = self.artconn.cursor() if self.artconn else None
|
|
self.wal_mode = wal_mode
|
|
|
|
def __enter__(self):
|
|
if self.lock:
|
|
KODIDB_LOCK.acquire()
|
|
self.kodiconn = db.connect(self.db_kind, self.wal_mode)
|
|
self.cursor = self.kodiconn.cursor()
|
|
self.artconn = db.connect('texture', self.wal_mode) if self._texture_db \
|
|
else None
|
|
self.artcursor = self.artconn.cursor() if self._texture_db else None
|
|
return self
|
|
|
|
def __exit__(self, e_typ, e_val, trcbak):
|
|
try:
|
|
if e_typ:
|
|
# re-raise any exception
|
|
return False
|
|
self.kodiconn.commit()
|
|
if self.artconn:
|
|
self.artconn.commit()
|
|
finally:
|
|
self.kodiconn.close()
|
|
if self.artconn:
|
|
self.artconn.close()
|
|
if self.lock:
|
|
KODIDB_LOCK.release()
|
|
|
|
def art_urls(self, kodi_id, kodi_type):
|
|
return (x[0] for x in
|
|
self.cursor.execute('SELECT url FROM art WHERE media_id = ? AND media_type = ?',
|
|
(kodi_id, kodi_type)))
|
|
|
|
def artwork_generator(self, kodi_type, limit, offset):
|
|
query = 'SELECT url FROM art WHERE type == ? LIMIT ? OFFSET ?'
|
|
return (x[0] for x in
|
|
self.cursor.execute(query, (kodi_type, limit, offset)))
|
|
|
|
def add_artwork(self, artworks, kodi_id, kodi_type):
|
|
"""
|
|
Pass in an artworks dict (see PlexAPI) to set an items artwork.
|
|
"""
|
|
for kodi_art, url in artworks.iteritems():
|
|
self.add_art(url, kodi_id, kodi_type, kodi_art)
|
|
|
|
@db.catch_operationalerrors
|
|
def add_art(self, url, kodi_id, kodi_type, kodi_art):
|
|
"""
|
|
Adds or modifies the artwork of kind kodi_art (e.g. 'poster') in the
|
|
Kodi art table for item kodi_id/kodi_type. Will also cache everything
|
|
except actor portraits.
|
|
"""
|
|
self.cursor.execute('''
|
|
INSERT INTO art(media_id, media_type, type, url)
|
|
VALUES (?, ?, ?, ?)
|
|
''', (kodi_id, kodi_type, kodi_art, url))
|
|
|
|
def modify_artwork(self, artworks, kodi_id, kodi_type):
|
|
"""
|
|
Pass in an artworks dict (see PlexAPI) to set an items artwork.
|
|
"""
|
|
for kodi_art, url in artworks.iteritems():
|
|
self.modify_art(url, kodi_id, kodi_type, kodi_art)
|
|
|
|
@db.catch_operationalerrors
|
|
def modify_art(self, url, kodi_id, kodi_type, kodi_art):
|
|
"""
|
|
Adds or modifies the artwork of kind kodi_art (e.g. 'poster') in the
|
|
Kodi art table for item kodi_id/kodi_type. Will also cache everything
|
|
except actor portraits.
|
|
"""
|
|
self.cursor.execute('''
|
|
SELECT url FROM art
|
|
WHERE media_id = ? AND media_type = ? AND type = ?
|
|
LIMIT 1
|
|
''', (kodi_id, kodi_type, kodi_art,))
|
|
try:
|
|
# Update the artwork
|
|
old_url = self.cursor.fetchone()[0]
|
|
except TypeError:
|
|
# Add the artwork
|
|
self.cursor.execute('''
|
|
INSERT INTO art(media_id, media_type, type, url)
|
|
VALUES (?, ?, ?, ?)
|
|
''', (kodi_id, kodi_type, kodi_art, url))
|
|
else:
|
|
if url == old_url:
|
|
# Only cache artwork if it changed
|
|
return
|
|
self.delete_cached_artwork(old_url)
|
|
self.cursor.execute('''
|
|
UPDATE art SET url = ?
|
|
WHERE media_id = ? AND media_type = ? AND type = ?
|
|
''', (url, kodi_id, kodi_type, kodi_art))
|
|
|
|
def delete_artwork(self, kodi_id, kodi_type):
|
|
self.cursor.execute('SELECT url FROM art WHERE media_id = ? AND media_type = ?',
|
|
(kodi_id, kodi_type, ))
|
|
for row in self.cursor.fetchall():
|
|
self.delete_cached_artwork(row[0])
|
|
|
|
@db.catch_operationalerrors
|
|
def delete_cached_artwork(self, url):
|
|
try:
|
|
self.artcursor.execute("SELECT cachedurl FROM texture WHERE url = ? LIMIT 1",
|
|
(url, ))
|
|
cachedurl = self.artcursor.fetchone()[0]
|
|
except TypeError:
|
|
# Could not find cached url
|
|
pass
|
|
else:
|
|
# Delete thumbnail as well as the entry
|
|
path = path_ops.translate_path("special://thumbnails/%s"
|
|
% cachedurl)
|
|
if path_ops.exists(path):
|
|
path_ops.rmtree(path, ignore_errors=True)
|
|
self.artcursor.execute("DELETE FROM texture WHERE url = ?", (url, ))
|
|
|
|
@db.catch_operationalerrors
|
|
def wipe(self):
|
|
"""
|
|
Completely wipes the corresponding Kodi database
|
|
"""
|
|
self.cursor.execute("SELECT name FROM sqlite_master WHERE type = 'table'")
|
|
tables = [i[0] for i in self.cursor.fetchall()]
|
|
for table in UNTOUCHED_TABLES:
|
|
if table in tables:
|
|
tables.remove(table)
|
|
for table in tables:
|
|
self.cursor.execute('DELETE FROM %s' % table)
|