Rewire kodi database access
This commit is contained in:
parent
150229061b
commit
a16eae143a
22 changed files with 1078 additions and 934 deletions
|
@ -6,10 +6,10 @@ from urllib import quote_plus, unquote
|
|||
import requests
|
||||
import xbmc
|
||||
|
||||
from . import backgroundthread, path_ops, utils
|
||||
from .kodi_db import KodiVideoDB, KodiMusicDB, KodiTextureDB
|
||||
from . import backgroundthread, utils
|
||||
from . import state
|
||||
|
||||
###############################################################################
|
||||
LOG = getLogger('PLEX.artwork')
|
||||
|
||||
# Disable annoying requests warnings
|
||||
|
@ -26,8 +26,6 @@ IMAGE_CACHING_SUSPENDS = [
|
|||
if not utils.settings('imageSyncDuringPlayback') == 'true':
|
||||
IMAGE_CACHING_SUSPENDS.append(state.SUSPEND_SYNC)
|
||||
|
||||
###############################################################################
|
||||
|
||||
|
||||
def double_urlencode(text):
|
||||
return quote_plus(quote_plus(text))
|
||||
|
@ -53,18 +51,16 @@ class ImageCachingThread(backgroundthread.KillableThread):
|
|||
|
||||
@staticmethod
|
||||
def _art_url_generator():
|
||||
from . import kodidb_functions as kodidb
|
||||
for kind in ('video', 'music'):
|
||||
with kodidb.GetKodiDB(kind) as kodi_db:
|
||||
for kind in (KodiVideoDB, KodiMusicDB):
|
||||
with kind() as kodidb:
|
||||
for kodi_type in ('poster', 'fanart'):
|
||||
for url in kodi_db.artwork_generator(kodi_type):
|
||||
for url in kodidb.artwork_generator(kodi_type):
|
||||
yield url
|
||||
|
||||
def missing_art_cache_generator(self):
|
||||
from . import kodidb_functions as kodidb
|
||||
with kodidb.GetKodiDB('texture') as kodi_db:
|
||||
with KodiTextureDB() as kodidb:
|
||||
for url in self._art_url_generator():
|
||||
if kodi_db.url_not_yet_cached(url):
|
||||
if kodidb.url_not_yet_cached(url):
|
||||
yield url
|
||||
|
||||
def run(self):
|
||||
|
@ -126,74 +122,3 @@ def cache_url(url):
|
|||
break
|
||||
# We did not even get a timeout
|
||||
break
|
||||
|
||||
|
||||
def modify_artwork(artworks, kodi_id, kodi_type, cursor):
|
||||
"""
|
||||
Pass in an artworks dict (see PlexAPI) to set an items artwork.
|
||||
"""
|
||||
for kodi_art, url in artworks.iteritems():
|
||||
modify_art(url, kodi_id, kodi_type, kodi_art, cursor)
|
||||
|
||||
|
||||
def modify_art(url, kodi_id, kodi_type, kodi_art, cursor):
|
||||
"""
|
||||
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.
|
||||
"""
|
||||
query = '''
|
||||
SELECT url FROM art
|
||||
WHERE media_id = ? AND media_type = ? AND type = ?
|
||||
LIMIT 1
|
||||
'''
|
||||
cursor.execute(query, (kodi_id, kodi_type, kodi_art,))
|
||||
try:
|
||||
# Update the artwork
|
||||
old_url = cursor.fetchone()[0]
|
||||
except TypeError:
|
||||
# Add the artwork
|
||||
query = '''
|
||||
INSERT INTO art(media_id, media_type, type, url)
|
||||
VALUES (?, ?, ?, ?)
|
||||
'''
|
||||
cursor.execute(query, (kodi_id, kodi_type, kodi_art, url))
|
||||
else:
|
||||
if url == old_url:
|
||||
# Only cache artwork if it changed
|
||||
return
|
||||
delete_cached_artwork(old_url)
|
||||
query = '''
|
||||
UPDATE art SET url = ?
|
||||
WHERE media_id = ? AND media_type = ? AND type = ?
|
||||
'''
|
||||
cursor.execute(query, (url, kodi_id, kodi_type, kodi_art))
|
||||
|
||||
|
||||
def delete_artwork(kodiId, mediaType, cursor):
|
||||
cursor.execute('SELECT url FROM art WHERE media_id = ? AND media_type = ?',
|
||||
(kodiId, mediaType, ))
|
||||
for row in cursor.fetchall():
|
||||
delete_cached_artwork(row[0])
|
||||
|
||||
|
||||
def delete_cached_artwork(url):
|
||||
"""
|
||||
Deleted the cached artwork with path url (if it exists)
|
||||
"""
|
||||
from . import kodidb_functions as kodidb
|
||||
with kodidb.GetKodiDB('texture') as kodi_db:
|
||||
try:
|
||||
kodi_db.cursor.execute("SELECT cachedurl FROM texture WHERE url=? LIMIT 1",
|
||||
(url, ))
|
||||
cachedurl = kodi_db.cursor.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)
|
||||
kodi_db.cursor.execute("DELETE FROM texture WHERE url = ?", (url,))
|
||||
|
|
|
@ -6,8 +6,8 @@ from ntpath import dirname
|
|||
|
||||
from ..plex_api import API
|
||||
from ..plex_db import PlexDB
|
||||
from .. import kodidb_functions as kodidb
|
||||
from .. import artwork, utils
|
||||
from ..kodi_db import KodiVideoDB
|
||||
from .. import utils
|
||||
|
||||
LOG = getLogger('PLEX.itemtypes.common')
|
||||
|
||||
|
@ -39,14 +39,16 @@ class ItemBase(object):
|
|||
Input:
|
||||
kodiType: optional argument; e.g. 'video' or 'music'
|
||||
"""
|
||||
def __init__(self, last_sync, plexdb=None, kodi_db=None):
|
||||
def __init__(self, last_sync, plexdb=None, kodidb=None):
|
||||
self.last_sync = last_sync
|
||||
self.plexconn = None
|
||||
self.plexcursor = plexdb.cursor if plexdb else None
|
||||
self.kodiconn = None
|
||||
self.kodicursor = kodi_db.cursor if kodi_db else None
|
||||
self.kodicursor = kodidb.cursor if kodidb else None
|
||||
self.artconn = kodidb.artconn if kodidb else None
|
||||
self.artcursor = kodidb.artcursor if kodidb else None
|
||||
self.plexdb = plexdb
|
||||
self.kodi_db = kodi_db
|
||||
self.kodidb = kodidb
|
||||
|
||||
def __enter__(self):
|
||||
"""
|
||||
|
@ -56,8 +58,12 @@ class ItemBase(object):
|
|||
self.plexcursor = self.plexconn.cursor()
|
||||
self.kodiconn = utils.kodi_sql('video')
|
||||
self.kodicursor = self.kodiconn.cursor()
|
||||
self.artconn = utils.kodi_sql('texture')
|
||||
self.artcursor = self.artconn.cursor()
|
||||
self.plexdb = PlexDB(self.plexcursor)
|
||||
self.kodi_db = kodidb.KodiDBMethods(self.kodicursor)
|
||||
self.kodidb = KodiVideoDB(texture_db=True,
|
||||
cursor=self.kodicursor,
|
||||
artcursor=self.artcursor)
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||
|
@ -66,18 +72,19 @@ class ItemBase(object):
|
|||
"""
|
||||
self.plexconn.commit()
|
||||
self.kodiconn.commit()
|
||||
self.artconn.commit()
|
||||
self.plexconn.close()
|
||||
self.kodiconn.close()
|
||||
self.artconn.close()
|
||||
return self
|
||||
|
||||
def set_fanart(self, artworks, kodi_id, kodi_type):
|
||||
"""
|
||||
Writes artworks [dict containing only set artworks] to the Kodi art DB
|
||||
"""
|
||||
artwork.modify_artwork(artworks,
|
||||
kodi_id,
|
||||
kodi_type,
|
||||
self.kodicursor)
|
||||
self.kodidb.modify_artwork(artworks,
|
||||
kodi_id,
|
||||
kodi_type)
|
||||
|
||||
def update_userdata(self, xml_element, plex_type):
|
||||
"""
|
||||
|
@ -93,15 +100,15 @@ class ItemBase(object):
|
|||
# Grab the user's viewcount, resume points etc. from PMS' answer
|
||||
userdata = api.userdata()
|
||||
# Write to Kodi DB
|
||||
self.kodi_db.set_resume(db_item['kodi_fileid'],
|
||||
userdata['Resume'],
|
||||
userdata['Runtime'],
|
||||
userdata['PlayCount'],
|
||||
userdata['LastPlayedDate'],
|
||||
plex_type)
|
||||
self.kodi_db.update_userrating(db_item['kodi_id'],
|
||||
db_item['kodi_type'],
|
||||
userdata['UserRating'])
|
||||
self.kodidb.set_resume(db_item['kodi_fileid'],
|
||||
userdata['Resume'],
|
||||
userdata['Runtime'],
|
||||
userdata['PlayCount'],
|
||||
userdata['LastPlayedDate'],
|
||||
plex_type)
|
||||
self.kodidb.update_userrating(db_item['kodi_id'],
|
||||
db_item['kodi_type'],
|
||||
userdata['UserRating'])
|
||||
|
||||
def update_playstate(self, mark_played, view_count, resume, duration,
|
||||
kodi_fileid, lastViewedAt, plex_type):
|
||||
|
@ -118,9 +125,9 @@ class ItemBase(object):
|
|||
view_count = 1
|
||||
resume = 0
|
||||
# Do the actual update
|
||||
self.kodi_db.set_resume(kodi_fileid,
|
||||
resume,
|
||||
duration,
|
||||
view_count,
|
||||
utils.unix_date_to_kodi(lastViewedAt),
|
||||
plex_type)
|
||||
self.kodidb.set_resume(kodi_fileid,
|
||||
resume,
|
||||
duration,
|
||||
view_count,
|
||||
utils.unix_date_to_kodi(lastViewedAt),
|
||||
plex_type)
|
||||
|
|
|
@ -5,7 +5,7 @@ from logging import getLogger
|
|||
|
||||
from .common import ItemBase
|
||||
from ..plex_api import API
|
||||
from .. import artwork, state, variables as v, plex_functions as PF
|
||||
from .. import state, variables as v, plex_functions as PF
|
||||
|
||||
LOG = getLogger('PLEX.movies')
|
||||
|
||||
|
@ -20,32 +20,20 @@ class Movie(ItemBase):
|
|||
Process single movie
|
||||
"""
|
||||
api = API(xml)
|
||||
update_item = True
|
||||
plex_id = api.plex_id()
|
||||
# Cannot parse XML, abort
|
||||
if not plex_id:
|
||||
LOG.error('Cannot parse XML data for movie: %s', xml.attrib)
|
||||
return
|
||||
movie = self.plexdb.movie(plex_id)
|
||||
try:
|
||||
if movie:
|
||||
update_item = True
|
||||
kodi_id = movie['kodi_id']
|
||||
old_kodi_fileid = movie['kodi_fileid']
|
||||
kodi_pathid = movie['kodi_pathid']
|
||||
except TypeError:
|
||||
update_item = False
|
||||
self.kodicursor.execute('SELECT COALESCE(MAX(idMovie), 0) FROM movie')
|
||||
kodi_id = self.kodicursor.fetchone()[0] + 1
|
||||
else:
|
||||
# Verification the item is still in Kodi
|
||||
self.kodicursor.execute('SELECT idMovie FROM movie WHERE idMovie = ? LIMIT 1',
|
||||
(kodi_id, ))
|
||||
try:
|
||||
self.kodicursor.fetchone()[0]
|
||||
except TypeError:
|
||||
# item is not found, let's recreate it.
|
||||
update_item = False
|
||||
LOG.info("kodi_id: %s missing from Kodi, repairing the entry.",
|
||||
kodi_id)
|
||||
update_item = False
|
||||
kodi_id = self.kodidb.new_movie_id()
|
||||
|
||||
userdata = api.userdata()
|
||||
playcount = userdata['PlayCount']
|
||||
|
@ -80,9 +68,9 @@ class Movie(ItemBase):
|
|||
# Network share
|
||||
filename = playurl.rsplit("/", 1)[1]
|
||||
path = playurl.replace(filename, "")
|
||||
kodi_pathid = self.kodi_db.add_video_path(path,
|
||||
content='movies',
|
||||
scraper='metadata.local')
|
||||
kodi_pathid = self.kodidb.add_video_path(path,
|
||||
content='movies',
|
||||
scraper='metadata.local')
|
||||
if do_indirect:
|
||||
# Set plugin path and media flags using real filename
|
||||
filename = api.file_name(force_first_media=True)
|
||||
|
@ -90,94 +78,100 @@ class Movie(ItemBase):
|
|||
filename = ('%s?plex_id=%s&plex_type=%s&mode=play&filename=%s'
|
||||
% (path, plex_id, v.PLEX_TYPE_MOVIE, filename))
|
||||
playurl = filename
|
||||
kodi_pathid = self.kodi_db.get_path(path)
|
||||
kodi_pathid = self.kodidb.get_path(path)
|
||||
|
||||
file_id = self.kodi_db.add_file(filename,
|
||||
kodi_pathid,
|
||||
api.date_created())
|
||||
file_id = self.kodidb.add_file(filename,
|
||||
kodi_pathid,
|
||||
api.date_created())
|
||||
|
||||
if update_item:
|
||||
LOG.info('UPDATE movie plex_id: %s - %s', plex_id, api.title())
|
||||
if file_id != old_kodi_fileid:
|
||||
self.kodi_db.remove_file(old_kodi_fileid)
|
||||
rating_id = self.kodi_db.get_ratingid(kodi_id,
|
||||
v.KODI_TYPE_MOVIE)
|
||||
self.kodi_db.update_ratings(kodi_id,
|
||||
v.KODI_TYPE_MOVIE,
|
||||
"default",
|
||||
rating,
|
||||
api.votecount(),
|
||||
rating_id)
|
||||
self.kodidb.remove_file(old_kodi_fileid)
|
||||
rating_id = self.kodidb.get_ratingid(kodi_id,
|
||||
v.KODI_TYPE_MOVIE)
|
||||
self.kodidb.update_ratings(kodi_id,
|
||||
v.KODI_TYPE_MOVIE,
|
||||
"default",
|
||||
rating,
|
||||
api.votecount(),
|
||||
rating_id)
|
||||
# update new uniqueid Kodi 17
|
||||
if api.provider('imdb') is not None:
|
||||
uniqueid = self.kodi_db.get_uniqueid(kodi_id,
|
||||
v.KODI_TYPE_MOVIE)
|
||||
self.kodi_db.update_uniqueid(kodi_id,
|
||||
v.KODI_TYPE_MOVIE,
|
||||
api.provider('imdb'),
|
||||
"imdb",
|
||||
uniqueid)
|
||||
uniqueid = self.kodidb.get_uniqueid(kodi_id,
|
||||
v.KODI_TYPE_MOVIE)
|
||||
self.kodidb.update_uniqueid(kodi_id,
|
||||
v.KODI_TYPE_MOVIE,
|
||||
api.provider('imdb'),
|
||||
"imdb",
|
||||
uniqueid)
|
||||
else:
|
||||
self.kodi_db.remove_uniqueid(kodi_id, v.KODI_TYPE_MOVIE)
|
||||
self.kodidb.remove_uniqueid(kodi_id, v.KODI_TYPE_MOVIE)
|
||||
uniqueid = -1
|
||||
else:
|
||||
LOG.info("ADD movie plex_id: %s - %s", plex_id, title)
|
||||
rating_id = self.kodi_db.get_ratingid(kodi_id,
|
||||
v.KODI_TYPE_MOVIE)
|
||||
self.kodi_db.add_ratings(rating_id,
|
||||
kodi_id,
|
||||
v.KODI_TYPE_MOVIE,
|
||||
"default",
|
||||
rating,
|
||||
api.votecount())
|
||||
rating_id = self.kodidb.get_ratingid(kodi_id,
|
||||
v.KODI_TYPE_MOVIE)
|
||||
self.kodidb.add_ratings(rating_id,
|
||||
kodi_id,
|
||||
v.KODI_TYPE_MOVIE,
|
||||
"default",
|
||||
rating,
|
||||
api.votecount())
|
||||
if api.provider('imdb') is not None:
|
||||
uniqueid = self.kodi_db.get_uniqueid(kodi_id,
|
||||
v.KODI_TYPE_MOVIE)
|
||||
self.kodi_db.add_uniqueid(uniqueid,
|
||||
kodi_id,
|
||||
v.KODI_TYPE_MOVIE,
|
||||
api.provider('imdb'),
|
||||
"imdb")
|
||||
uniqueid = self.kodidb.get_uniqueid(kodi_id,
|
||||
v.KODI_TYPE_MOVIE)
|
||||
self.kodidb.add_uniqueid(uniqueid,
|
||||
kodi_id,
|
||||
v.KODI_TYPE_MOVIE,
|
||||
api.provider('imdb'),
|
||||
"imdb")
|
||||
else:
|
||||
uniqueid = -1
|
||||
|
||||
# Update Kodi's main entry
|
||||
query = '''
|
||||
INSERT OR REPLACE INTO movie(idMovie, idFile, c00, c01, c02, c03,
|
||||
c04, c05, c06, c07, c09, c10, c11, c12, c14, c15, c16,
|
||||
c18, c19, c21, c22, c23, premiered, userrating)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,
|
||||
?, ?, ?, ?, ?, ?, ?)
|
||||
'''
|
||||
self.kodicursor.execute(
|
||||
query,
|
||||
(kodi_id, file_id, title, api.plot(), api.shortplot(),
|
||||
api.tagline(), api.votecount(), rating_id,
|
||||
api.list_to_string(people['Writer']), api.year(),
|
||||
uniqueid, api.sorttitle(), runtime, api.content_rating(),
|
||||
api.list_to_string(genres), api.list_to_string(people['Director']),
|
||||
title, api.list_to_string(studios), api.trailer(),
|
||||
api.list_to_string(countries), playurl, kodi_pathid,
|
||||
api.premiere_date(), userdata['UserRating']))
|
||||
self.kodidb.add_movie(kodi_id,
|
||||
file_id,
|
||||
title,
|
||||
api.plot(),
|
||||
api.shortplot(),
|
||||
api.tagline(),
|
||||
api.votecount(),
|
||||
rating_id,
|
||||
api.list_to_string(people['Writer']),
|
||||
api.year(),
|
||||
uniqueid,
|
||||
api.sorttitle(),
|
||||
runtime,
|
||||
api.content_rating(),
|
||||
api.list_to_string(genres),
|
||||
api.list_to_string(people['Director']),
|
||||
title,
|
||||
api.list_to_string(studios),
|
||||
api.trailer(),
|
||||
api.list_to_string(countries),
|
||||
playurl,
|
||||
kodi_pathid,
|
||||
api.premiere_date(),
|
||||
userdata['UserRating'])
|
||||
|
||||
self.kodi_db.modify_countries(kodi_id, v.KODI_TYPE_MOVIE, countries)
|
||||
self.kodi_db.modify_people(kodi_id,
|
||||
v.KODI_TYPE_MOVIE,
|
||||
api.people_list())
|
||||
self.kodi_db.modify_genres(kodi_id, v.KODI_TYPE_MOVIE, genres)
|
||||
artwork.modify_artwork(api.artwork(),
|
||||
kodi_id,
|
||||
v.KODI_TYPE_MOVIE,
|
||||
self.kodicursor)
|
||||
self.kodi_db.modify_streams(file_id, api.mediastreams(), runtime)
|
||||
self.kodi_db.modify_studios(kodi_id, v.KODI_TYPE_MOVIE, studios)
|
||||
self.kodidb.modify_countries(kodi_id, v.KODI_TYPE_MOVIE, countries)
|
||||
self.kodidb.modify_people(kodi_id,
|
||||
v.KODI_TYPE_MOVIE,
|
||||
api.people_list())
|
||||
self.kodidb.modify_genres(kodi_id, v.KODI_TYPE_MOVIE, genres)
|
||||
self.kodidb.modify_artwork(api.artwork(),
|
||||
kodi_id,
|
||||
v.KODI_TYPE_MOVIE)
|
||||
self.kodidb.modify_streams(file_id, api.mediastreams(), runtime)
|
||||
self.kodidb.modify_studios(kodi_id, v.KODI_TYPE_MOVIE, studios)
|
||||
tags = [section_name]
|
||||
if collections:
|
||||
for plex_set_id, set_name in collections:
|
||||
tags.append(set_name)
|
||||
# Add any sets from Plex collection tags
|
||||
kodi_set_id = self.kodi_db.create_collection(set_name)
|
||||
self.kodi_db.assign_collection(kodi_set_id, kodi_id)
|
||||
kodi_set_id = self.kodidb.create_collection(set_name)
|
||||
self.kodidb.assign_collection(kodi_set_id, kodi_id)
|
||||
if children is None:
|
||||
# e.g. when added via websocket
|
||||
LOG.debug('Costly looking up Plex collection %s: %s',
|
||||
|
@ -199,18 +193,17 @@ class Movie(ItemBase):
|
|||
set_api = API(children[plex_set_id][0])
|
||||
else:
|
||||
continue
|
||||
artwork.modify_artwork(set_api.artwork(),
|
||||
kodi_set_id,
|
||||
v.KODI_TYPE_SET,
|
||||
self.kodicursor)
|
||||
self.kodi_db.modify_tags(kodi_id, v.KODI_TYPE_MOVIE, tags)
|
||||
self.kodidb.modify_artwork(set_api.artwork(),
|
||||
kodi_set_id,
|
||||
v.KODI_TYPE_SET)
|
||||
self.kodidb.modify_tags(kodi_id, v.KODI_TYPE_MOVIE, tags)
|
||||
# Process playstate
|
||||
self.kodi_db.set_resume(file_id,
|
||||
resume,
|
||||
runtime,
|
||||
playcount,
|
||||
dateplayed,
|
||||
v.PLEX_TYPE_MOVIE)
|
||||
self.kodidb.set_resume(file_id,
|
||||
resume,
|
||||
runtime,
|
||||
playcount,
|
||||
dateplayed,
|
||||
v.PLEX_TYPE_MOVIE)
|
||||
self.plexdb.add_movie(plex_id=plex_id,
|
||||
checksum=api.checksum(),
|
||||
section_id=section_id,
|
||||
|
@ -238,19 +231,18 @@ class Movie(ItemBase):
|
|||
# Remove the plex reference
|
||||
self.plexdb.remove(plex_id, v.PLEX_TYPE_MOVIE)
|
||||
# Remove artwork
|
||||
artwork.delete_artwork(kodi_id, kodi_type, self.self.kodicursor)
|
||||
set_id = self.kodi_db.get_set_id(kodi_id)
|
||||
self.kodi_db.modify_countries(kodi_id, kodi_type)
|
||||
self.kodi_db.modify_people(kodi_id, kodi_type)
|
||||
self.kodi_db.modify_genres(kodi_id, kodi_type)
|
||||
self.kodi_db.modify_studios(kodi_id, kodi_type)
|
||||
self.kodi_db.modify_tags(kodi_id, kodi_type)
|
||||
self.kodidb.delete_artwork(kodi_id, kodi_type)
|
||||
set_id = self.kodidb.get_set_id(kodi_id)
|
||||
self.kodidb.modify_countries(kodi_id, kodi_type)
|
||||
self.kodidb.modify_people(kodi_id, kodi_type)
|
||||
self.kodidb.modify_genres(kodi_id, kodi_type)
|
||||
self.kodidb.modify_studios(kodi_id, kodi_type)
|
||||
self.kodidb.modify_tags(kodi_id, kodi_type)
|
||||
# Delete kodi movie and file
|
||||
self.kodi_db.remove_file(file_id)
|
||||
self.self.kodicursor.execute('DELETE FROM movie WHERE idMovie = ?',
|
||||
(kodi_id,))
|
||||
self.kodidb.remove_file(file_id)
|
||||
self.kodidb.remove_movie(kodi_id)
|
||||
if set_id:
|
||||
self.kodi_db.delete_possibly_empty_set(set_id)
|
||||
self.kodi_db.remove_uniqueid(kodi_id, kodi_type)
|
||||
self.kodi_db.remove_ratings(kodi_id, kodi_type)
|
||||
self.kodidb.delete_possibly_empty_set(set_id)
|
||||
self.kodidb.remove_uniqueid(kodi_id, kodi_type)
|
||||
self.kodidb.remove_ratings(kodi_id, kodi_type)
|
||||
LOG.debug('Deleted movie %s from kodi database', plex_id)
|
||||
|
|
|
@ -6,8 +6,8 @@ from logging import getLogger
|
|||
from .common import ItemBase
|
||||
from ..plex_api import API
|
||||
from ..plex_db import PlexDB
|
||||
from .. import artwork, kodidb_functions as kodidb
|
||||
from .. import plex_functions as PF, utils, state, variables as v
|
||||
from ..kodi_db import KodiMusicDB
|
||||
from .. import artwork, plex_functions as PF, utils, state, variables as v
|
||||
|
||||
LOG = getLogger('PLEX.music')
|
||||
|
||||
|
@ -21,8 +21,12 @@ class MusicMixin(object):
|
|||
self.plexcursor = self.plexconn.cursor()
|
||||
self.kodiconn = utils.kodi_sql('music')
|
||||
self.kodicursor = self.kodiconn.cursor()
|
||||
self.artconn = utils.kodi_sql('texture')
|
||||
self.artcursor = self.artconn.cursor()
|
||||
self.plexdb = PlexDB(self.plexcursor)
|
||||
self.kodi_db = kodidb.KodiDBMethods(self.kodicursor)
|
||||
self.kodidb = KodiMusicDB(texture_db=True,
|
||||
cursor=self.kodicursor,
|
||||
artcursor=self.artcursor)
|
||||
return self
|
||||
|
||||
def remove(self, plex_id, plex_type=None):
|
||||
|
@ -93,7 +97,7 @@ class MusicMixin(object):
|
|||
path_id = self.kodicursor.fetchone()[0]
|
||||
except TypeError:
|
||||
pass
|
||||
self.kodi_db.delete_song_from_song_artist(kodi_id)
|
||||
self.kodidb.delete_song_from_song_artist(kodi_id)
|
||||
self.kodicursor.execute('DELETE FROM song WHERE idSong = ?',
|
||||
(kodi_id, ))
|
||||
# Check whether we have orphaned path entries
|
||||
|
@ -103,7 +107,7 @@ class MusicMixin(object):
|
|||
self.kodicursor.execute('DELETE FROM path WHERE idPath = ?',
|
||||
(path_id, ))
|
||||
if v.KODIVERSION < 18:
|
||||
self.kodi_db.delete_song_from_song_genre(kodi_id)
|
||||
self.kodidb.delete_song_from_song_genre(kodi_id)
|
||||
query = 'DELETE FROM albuminfosong WHERE idAlbumInfoSong = ?'
|
||||
self.kodicursor.execute(query, (kodi_id, ))
|
||||
artwork.delete_artwork(kodi_id, v.KODI_TYPE_SONG, self.kodicursor)
|
||||
|
@ -112,9 +116,9 @@ class MusicMixin(object):
|
|||
'''
|
||||
Remove an album
|
||||
'''
|
||||
self.kodi_db.delete_album_from_discography(kodi_id)
|
||||
self.kodidb.delete_album_from_discography(kodi_id)
|
||||
if v.KODIVERSION < 18:
|
||||
self.kodi_db.delete_album_from_album_genre(kodi_id)
|
||||
self.kodidb.delete_album_from_album_genre(kodi_id)
|
||||
query = 'DELETE FROM albuminfosong WHERE idAlbumInfo = ?'
|
||||
self.kodicursor.execute(query, (kodi_id, ))
|
||||
self.kodicursor.execute('DELETE FROM album_artist WHERE idAlbum = ?',
|
||||
|
@ -183,7 +187,7 @@ class Artist(MusicMixin, ItemBase):
|
|||
# multiple times.
|
||||
# Kodi doesn't allow that. In case that happens we just merge the
|
||||
# artist entries.
|
||||
kodi_id = self.kodi_db.add_artist(api.title(), musicBrainzId)
|
||||
kodi_id = self.kodidb.add_artist(api.title(), musicBrainzId)
|
||||
# Create the reference in plex table
|
||||
query = '''
|
||||
UPDATE artist
|
||||
|
@ -279,7 +283,7 @@ class Album(MusicMixin, ItemBase):
|
|||
# OR ADD THE ALBUM #####
|
||||
else:
|
||||
LOG.info("ADD album plex_id: %s - Name: %s", plex_id, name)
|
||||
kodi_id = self.kodi_db.add_album(name, musicBrainzId)
|
||||
kodi_id = self.kodidb.add_album(name, musicBrainzId)
|
||||
# Process the album info
|
||||
if v.KODIVERSION >= 18:
|
||||
# Kodi Leia
|
||||
|
@ -360,7 +364,7 @@ class Album(MusicMixin, ItemBase):
|
|||
self.kodicursor.execute(query,
|
||||
(artist_id, name, api.year()))
|
||||
if v.KODIVERSION < 18:
|
||||
self.kodi_db.add_music_genres(kodi_id,
|
||||
self.kodidb.add_music_genres(kodi_id,
|
||||
genres,
|
||||
v.KODI_TYPE_ALBUM)
|
||||
# Update artwork
|
||||
|
@ -379,7 +383,7 @@ class Album(MusicMixin, ItemBase):
|
|||
if scan_children:
|
||||
context = Song(self.last_sync,
|
||||
plexdb=self.plexdb,
|
||||
kodi_db=self.kodi_db)
|
||||
kodidb=self.kodidb)
|
||||
for song in children:
|
||||
context.add_update(song,
|
||||
section_name=section_name,
|
||||
|
@ -426,7 +430,7 @@ class Song(MusicMixin, ItemBase):
|
|||
LOG.error('Grandparent tvartist %s xml download failed for %s',
|
||||
artist_id, xml.attrib)
|
||||
return
|
||||
Artist(self.last_sync, plexdb=self.plexdb, kodi_db=self.kodi_db).add_update(
|
||||
Artist(self.last_sync, plexdb=self.plexdb, kodidb=self.kodidb).add_update(
|
||||
artist_xml[0], section_name, section_id)
|
||||
artist = self.plexdb.artist(artist_id)
|
||||
if not artist:
|
||||
|
@ -463,7 +467,7 @@ class Song(MusicMixin, ItemBase):
|
|||
LOG.error('Parent album %s xml download failed for %s',
|
||||
album_id, xml.attrib)
|
||||
return
|
||||
Album(self.last_sync, plexdb=self.plexdb, kodi_db=self.kodi_db).add_update(
|
||||
Album(self.last_sync, plexdb=self.plexdb, kodidb=self.kodidb).add_update(
|
||||
album_xml[0], section_name, section_id)
|
||||
album = self.plexdb.album(album_id)
|
||||
if not album:
|
||||
|
@ -615,7 +619,7 @@ class Song(MusicMixin, ItemBase):
|
|||
else:
|
||||
LOG.info("ADD song plex_id: %s - %s", plex_id, title)
|
||||
# Add path
|
||||
kodi_pathid = self.kodi_db.add_music_path(path, hash_string="123")
|
||||
kodi_pathid = self.kodidb.add_music_path(path, hash_string="123")
|
||||
# Create the song entry
|
||||
if v.KODIVERSION >= 18:
|
||||
# Kodi Leia
|
||||
|
@ -730,7 +734,7 @@ class Song(MusicMixin, ItemBase):
|
|||
(grandparent_id, kodi_id, 1, 0, artist_name))
|
||||
# Add genres
|
||||
if genres:
|
||||
self.kodi_db.add_music_genres(kodi_id, genres, v.KODI_TYPE_SONG)
|
||||
self.kodidb.add_music_genres(kodi_id, genres, v.KODI_TYPE_SONG)
|
||||
artworks = api.artwork()
|
||||
artwork.modify_artwork(artworks,
|
||||
kodi_id,
|
||||
|
|
|
@ -5,7 +5,7 @@ from logging import getLogger
|
|||
|
||||
from .common import ItemBase, process_path
|
||||
from ..plex_api import API
|
||||
from .. import artwork, plex_functions as PF, state, variables as v
|
||||
from .. import plex_functions as PF, state, variables as v
|
||||
|
||||
LOG = getLogger('PLEX.tvshows')
|
||||
|
||||
|
@ -74,38 +74,35 @@ class TvShowMixin(object):
|
|||
"""
|
||||
Remove a TV show, and only the show, no seasons or episodes
|
||||
"""
|
||||
self.kodi_db.modify_genres(kodi_id, v.KODI_TYPE_SHOW)
|
||||
self.kodi_db.modify_studios(kodi_id, v.KODI_TYPE_SHOW)
|
||||
self.kodi_db.modify_tags(kodi_id, v.KODI_TYPE_SHOW)
|
||||
artwork.delete_artwork(kodi_id, v.KODI_TYPE_SHOW, self.kodicursor)
|
||||
self.kodicursor.execute("DELETE FROM tvshow WHERE idShow = ?",
|
||||
(kodi_id,))
|
||||
self.kodidb.modify_genres(kodi_id, v.KODI_TYPE_SHOW)
|
||||
self.kodidb.modify_studios(kodi_id, v.KODI_TYPE_SHOW)
|
||||
self.kodidb.modify_tags(kodi_id, v.KODI_TYPE_SHOW)
|
||||
self.kodidb.delete_artwork(kodi_id, v.KODI_TYPE_SHOW)
|
||||
self.kodidb.remove_show(kodi_id)
|
||||
if v.KODIVERSION >= 17:
|
||||
self.kodi_db.remove_uniqueid(kodi_id, v.KODI_TYPE_SHOW)
|
||||
self.kodi_db.remove_ratings(kodi_id, v.KODI_TYPE_SHOW)
|
||||
self.kodidb.remove_uniqueid(kodi_id, v.KODI_TYPE_SHOW)
|
||||
self.kodidb.remove_ratings(kodi_id, v.KODI_TYPE_SHOW)
|
||||
LOG.debug("Removed tvshow: %s", kodi_id)
|
||||
|
||||
def remove_season(self, kodi_id):
|
||||
"""
|
||||
Remove a season, and only a season, not the show or episodes
|
||||
"""
|
||||
artwork.delete_artwork(kodi_id, v.KODI_TYPE_SEASON, self.kodicursor)
|
||||
self.kodicursor.execute("DELETE FROM seasons WHERE idSeason = ?",
|
||||
(kodi_id,))
|
||||
self.kodidb.delete_artwork(kodi_id, v.KODI_TYPE_SEASON)
|
||||
self.kodidb.remove_season(kodi_id)
|
||||
LOG.debug("Removed season: %s", kodi_id)
|
||||
|
||||
def remove_episode(self, kodi_id, file_id):
|
||||
"""
|
||||
Remove an episode, and episode only from the Kodi DB (not Plex DB)
|
||||
"""
|
||||
self.kodi_db.modify_people(kodi_id, v.KODI_TYPE_EPISODE)
|
||||
self.kodi_db.remove_file(file_id, plex_type=v.PLEX_TYPE_EPISODE)
|
||||
artwork.delete_artwork(kodi_id, v.KODI_TYPE_EPISODE, self.kodicursor)
|
||||
self.kodicursor.execute("DELETE FROM episode WHERE idEpisode = ?",
|
||||
(kodi_id,))
|
||||
self.kodidb.modify_people(kodi_id, v.KODI_TYPE_EPISODE)
|
||||
self.kodidb.remove_file(file_id, plex_type=v.PLEX_TYPE_EPISODE)
|
||||
self.kodidb.delete_artwork(kodi_id, v.KODI_TYPE_EPISODE)
|
||||
self.kodidb.remove_episode(kodi_id)
|
||||
if v.KODIVERSION >= 17:
|
||||
self.kodi_db.remove_uniqueid(kodi_id, v.KODI_TYPE_EPISODE)
|
||||
self.kodi_db.remove_ratings(kodi_id, v.KODI_TYPE_EPISODE)
|
||||
self.kodidb.remove_uniqueid(kodi_id, v.KODI_TYPE_EPISODE)
|
||||
self.kodidb.remove_ratings(kodi_id, v.KODI_TYPE_EPISODE)
|
||||
LOG.debug("Removed episode: %s", kodi_id)
|
||||
|
||||
|
||||
|
@ -126,23 +123,11 @@ class Show(ItemBase, TvShowMixin):
|
|||
show = self.plexdb.show(plex_id)
|
||||
if not show:
|
||||
update_item = False
|
||||
query = 'SELECT COALESCE(MAX(idShow), 0) FROM tvshow'
|
||||
self.kodicursor.execute(query)
|
||||
kodi_id = self.kodicursor.fetchone()[0] + 1
|
||||
kodi_id = self.kodidb.new_show_id()
|
||||
else:
|
||||
update_item = True
|
||||
kodi_id = show['kodi_id']
|
||||
kodi_pathid = show['kodi_pathid']
|
||||
# Verification the item is still in Kodi
|
||||
self.kodicursor.execute('SELECT * FROM tvshow WHERE idShow = ?',
|
||||
(kodi_id,))
|
||||
try:
|
||||
self.kodicursor.fetchone()[0]
|
||||
except TypeError:
|
||||
# item is not found, let's recreate it.
|
||||
update_item = False
|
||||
LOG.info("idShow: %s missing from Kodi, repairing the entry.",
|
||||
kodi_id)
|
||||
|
||||
genres = api.genre_list()
|
||||
genre = api.list_to_string(genres)
|
||||
|
@ -158,7 +143,7 @@ class Show(ItemBase, TvShowMixin):
|
|||
if playurl is None:
|
||||
return
|
||||
path, toplevelpath = process_path(playurl)
|
||||
toppathid = self.kodi_db.add_video_path(
|
||||
toppathid = self.kodidb.add_video_path(
|
||||
toplevelpath,
|
||||
content='tvshows',
|
||||
scraper='metadata.local')
|
||||
|
@ -169,93 +154,91 @@ class Show(ItemBase, TvShowMixin):
|
|||
# Do NOT set a parent id because addon-path cannot be "stacked"
|
||||
toppathid = None
|
||||
|
||||
kodi_pathid = self.kodi_db.add_video_path(path,
|
||||
date_added=api.date_created(),
|
||||
id_parent_path=toppathid)
|
||||
kodi_pathid = self.kodidb.add_video_path(path,
|
||||
date_added=api.date_created(),
|
||||
id_parent_path=toppathid)
|
||||
# UPDATE THE TVSHOW #####
|
||||
if update_item:
|
||||
LOG.info("UPDATE tvshow plex_id: %s - %s", plex_id, api.title())
|
||||
# update new ratings Kodi 17
|
||||
rating_id = self.kodi_db.get_ratingid(kodi_id, v.KODI_TYPE_SHOW)
|
||||
self.kodi_db.update_ratings(kodi_id,
|
||||
v.KODI_TYPE_SHOW,
|
||||
"default",
|
||||
api.audience_rating(),
|
||||
api.votecount(),
|
||||
rating_id)
|
||||
rating_id = self.kodidb.get_ratingid(kodi_id, v.KODI_TYPE_SHOW)
|
||||
self.kodidb.update_ratings(kodi_id,
|
||||
v.KODI_TYPE_SHOW,
|
||||
"default",
|
||||
api.audience_rating(),
|
||||
api.votecount(),
|
||||
rating_id)
|
||||
# update new uniqueid Kodi 17
|
||||
if api.provider('tvdb') is not None:
|
||||
uniqueid = self.kodi_db.get_uniqueid(kodi_id,
|
||||
v.KODI_TYPE_SHOW)
|
||||
self.kodi_db.update_uniqueid(kodi_id,
|
||||
v.KODI_TYPE_SHOW,
|
||||
api.provider('tvdb'),
|
||||
"unknown",
|
||||
uniqueid)
|
||||
uniqueid = self.kodidb.get_uniqueid(kodi_id,
|
||||
v.KODI_TYPE_SHOW)
|
||||
self.kodidb.update_uniqueid(kodi_id,
|
||||
v.KODI_TYPE_SHOW,
|
||||
api.provider('tvdb'),
|
||||
"unknown",
|
||||
uniqueid)
|
||||
else:
|
||||
self.kodi_db.remove_uniqueid(kodi_id, v.KODI_TYPE_SHOW)
|
||||
self.kodidb.remove_uniqueid(kodi_id, v.KODI_TYPE_SHOW)
|
||||
uniqueid = -1
|
||||
# Update the tvshow entry
|
||||
query = '''
|
||||
UPDATE tvshow
|
||||
SET c00 = ?, c01 = ?, c04 = ?, c05 = ?, c08 = ?, c09 = ?,
|
||||
c12 = ?, c13 = ?, c14 = ?, c15 = ?
|
||||
WHERE idShow = ?
|
||||
'''
|
||||
self.kodicursor.execute(
|
||||
query, (api.title(), api.plot(), rating_id,
|
||||
api.premiere_date(), genre, api.title(), uniqueid,
|
||||
api.content_rating(), studio, api.sorttitle(),
|
||||
kodi_id))
|
||||
self.kodidb.update_show(api.title(),
|
||||
api.plot(),
|
||||
rating_id,
|
||||
api.premiere_date(),
|
||||
genre,
|
||||
api.title(),
|
||||
uniqueid,
|
||||
api.content_rating(),
|
||||
studio,
|
||||
api.sorttitle(),
|
||||
kodi_id)
|
||||
# OR ADD THE TVSHOW #####
|
||||
else:
|
||||
LOG.info("ADD tvshow plex_id: %s - %s", plex_id, api.title())
|
||||
# Link the path
|
||||
query = "INSERT INTO tvshowlinkpath(idShow, idPath) values (?, ?)"
|
||||
self.kodicursor.execute(query, (kodi_id, kodi_pathid))
|
||||
rating_id = self.kodi_db.get_ratingid(kodi_id, v.KODI_TYPE_SHOW)
|
||||
self.kodi_db.add_ratings(rating_id,
|
||||
kodi_id,
|
||||
v.KODI_TYPE_SHOW,
|
||||
"default",
|
||||
api.audience_rating(),
|
||||
api.votecount())
|
||||
self.kodidb.add_showlinkpath(kodi_id, kodi_pathid)
|
||||
rating_id = self.kodidb.get_ratingid(kodi_id, v.KODI_TYPE_SHOW)
|
||||
self.kodidb.add_ratings(rating_id,
|
||||
kodi_id,
|
||||
v.KODI_TYPE_SHOW,
|
||||
"default",
|
||||
api.audience_rating(),
|
||||
api.votecount())
|
||||
if api.provider('tvdb') is not None:
|
||||
uniqueid = self.kodi_db.get_uniqueid(kodi_id,
|
||||
v.KODI_TYPE_SHOW)
|
||||
self.kodi_db.add_uniqueid(uniqueid,
|
||||
kodi_id,
|
||||
v.KODI_TYPE_SHOW,
|
||||
api.provider('tvdb'),
|
||||
"unknown")
|
||||
uniqueid = self.kodidb.get_uniqueid(kodi_id,
|
||||
v.KODI_TYPE_SHOW)
|
||||
self.kodidb.add_uniqueid(uniqueid,
|
||||
kodi_id,
|
||||
v.KODI_TYPE_SHOW,
|
||||
api.provider('tvdb'),
|
||||
"unknown")
|
||||
else:
|
||||
uniqueid = -1
|
||||
# Create the tvshow entry
|
||||
query = '''
|
||||
INSERT INTO tvshow(
|
||||
idShow, c00, c01, c04, c05, c08, c09, c12, c13, c14,
|
||||
c15)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
'''
|
||||
self.kodicursor.execute(
|
||||
query, (kodi_id, api.title(), api.plot(), rating_id,
|
||||
api.premiere_date(), genre, api.title(), uniqueid,
|
||||
api.content_rating(), studio, api.sorttitle()))
|
||||
|
||||
self.kodi_db.modify_people(kodi_id,
|
||||
v.KODI_TYPE_SHOW,
|
||||
api.people_list())
|
||||
self.kodi_db.modify_genres(kodi_id, v.KODI_TYPE_SHOW, genres)
|
||||
artwork.modify_artwork(api.artwork(),
|
||||
kodi_id,
|
||||
v.KODI_TYPE_SHOW,
|
||||
self.kodicursor)
|
||||
self.kodidb.add_show(kodi_id,
|
||||
api.title(),
|
||||
api.plot(),
|
||||
rating_id,
|
||||
api.premiere_date(),
|
||||
genre,
|
||||
api.title(),
|
||||
uniqueid,
|
||||
api.content_rating(),
|
||||
studio,
|
||||
api.sorttitle())
|
||||
self.kodidb.modify_people(kodi_id,
|
||||
v.KODI_TYPE_SHOW,
|
||||
api.people_list())
|
||||
self.kodidb.modify_genres(kodi_id, v.KODI_TYPE_SHOW, genres)
|
||||
self.kodidb.modify_artwork(api.artwork(),
|
||||
kodi_id,
|
||||
v.KODI_TYPE_SHOW)
|
||||
# Process studios
|
||||
self.kodi_db.modify_studios(kodi_id, v.KODI_TYPE_SHOW, studios)
|
||||
self.kodidb.modify_studios(kodi_id, v.KODI_TYPE_SHOW, studios)
|
||||
# Process tags: view, PMS collection tags
|
||||
tags = [section_name]
|
||||
tags.extend([i for _, i in api.collection_list()])
|
||||
self.kodi_db.modify_tags(kodi_id, v.KODI_TYPE_SHOW, tags)
|
||||
self.kodidb.modify_tags(kodi_id, v.KODI_TYPE_SHOW, tags)
|
||||
self.plexdb.add_show(plex_id=plex_id,
|
||||
checksum=api.checksum(),
|
||||
section_id=section_id,
|
||||
|
@ -287,18 +270,17 @@ class Season(ItemBase, TvShowMixin):
|
|||
except (TypeError, IndexError, AttributeError):
|
||||
LOG.error("Parent tvshow %s xml download failed", show_id)
|
||||
return False
|
||||
Show(self.last_sync, plexdb=self.plexdb, kodi_db=self.kodi_db).add_update(
|
||||
Show(self.last_sync, plexdb=self.plexdb, kodidb=self.kodidb).add_update(
|
||||
show_xml[0], section_name, section_id)
|
||||
show = self.plexdb.show(show_id)
|
||||
if not show:
|
||||
LOG.error('Still could not find parent tv show %s', show_id)
|
||||
return
|
||||
parent_id = show['kodi_id']
|
||||
kodi_id = self.kodi_db.add_season(parent_id, api.season_number())
|
||||
artwork.modify_artwork(api.artwork(),
|
||||
kodi_id,
|
||||
v.KODI_TYPE_SEASON,
|
||||
self.kodicursor)
|
||||
kodi_id = self.kodidb.add_season(parent_id, api.season_number())
|
||||
self.kodidb.modify_artwork(api.artwork(),
|
||||
kodi_id,
|
||||
v.KODI_TYPE_SEASON)
|
||||
self.plexdb.add_season(plex_id=plex_id,
|
||||
checksum=api.checksum(),
|
||||
section_id=section_id,
|
||||
|
@ -323,24 +305,12 @@ class Episode(ItemBase, TvShowMixin):
|
|||
episode = self.plexdb.episode(plex_id)
|
||||
if not episode:
|
||||
update_item = False
|
||||
query = 'SELECT COALESCE(MAX(idEpisode), 0) FROM episode'
|
||||
self.kodicursor.execute(query)
|
||||
kodi_id = self.kodicursor.fetchone()[0] + 1
|
||||
kodi_id = self.kodidb.new_episode_id()
|
||||
else:
|
||||
update_item = True
|
||||
kodi_id = episode['kodi_id']
|
||||
old_kodi_fileid = episode['kodi_fileid']
|
||||
kodi_pathid = episode['kodi_pathid']
|
||||
# Verification the item is still in Kodi
|
||||
query = 'SELECT * FROM episode WHERE idEpisode = ? LIMIT 1'
|
||||
self.kodicursor.execute(query, (kodi_id, ))
|
||||
try:
|
||||
self.kodicursor.fetchone()[0]
|
||||
except TypeError:
|
||||
# item is not found, let's recreate it.
|
||||
update_item = False
|
||||
LOG.info('idEpisode %s missing from Kodi, repairing entry.',
|
||||
kodi_id)
|
||||
|
||||
peoples = api.people()
|
||||
director = api.list_to_string(peoples['Director'])
|
||||
|
@ -365,7 +335,7 @@ class Episode(ItemBase, TvShowMixin):
|
|||
except (TypeError, IndexError, AttributeError):
|
||||
LOG.error("Grandparent tvshow %s xml download failed", show_id)
|
||||
return False
|
||||
Show(self.last_sync, plexdb=self.plexdb, kodi_db=self.kodi_db).add_update(
|
||||
Show(self.last_sync, plexdb=self.plexdb, kodidb=self.kodidb).add_update(
|
||||
show_xml[0], section_name, section_id)
|
||||
show = self.plexdb.show(show_id)
|
||||
if not show:
|
||||
|
@ -383,7 +353,7 @@ class Episode(ItemBase, TvShowMixin):
|
|||
except (TypeError, IndexError, AttributeError):
|
||||
LOG.error("Parent season %s xml download failed", season_id)
|
||||
return False
|
||||
Season(self.last_sync, plexdb=self.plexdb, kodi_db=self.kodi_db).add_update(
|
||||
Season(self.last_sync, plexdb=self.plexdb, kodidb=self.kodidb).add_update(
|
||||
season_xml[0], section_name, section_id)
|
||||
season = self.plexdb.season(season_id)
|
||||
if not season:
|
||||
|
@ -406,8 +376,8 @@ class Episode(ItemBase, TvShowMixin):
|
|||
# Network share
|
||||
filename = playurl.rsplit("/", 1)[1]
|
||||
path = playurl.replace(filename, "")
|
||||
parent_path_id = self.kodi_db.parent_path_id(path)
|
||||
kodi_pathid = self.kodi_db.add_video_path(
|
||||
parent_path_id = self.kodidb.parent_path_id(path)
|
||||
kodi_pathid = self.kodidb.add_video_path(
|
||||
path, id_parent_path=parent_path_id)
|
||||
if do_indirect:
|
||||
# Set plugin path - do NOT use "intermediate" paths for the show
|
||||
|
@ -418,99 +388,108 @@ class Episode(ItemBase, TvShowMixin):
|
|||
% (path, plex_id, v.PLEX_TYPE_EPISODE, filename))
|
||||
playurl = filename
|
||||
# Root path tvshows/ already saved in Kodi DB
|
||||
kodi_pathid = self.kodi_db.add_video_path(path)
|
||||
kodi_pathid = self.kodidb.add_video_path(path)
|
||||
|
||||
# add/retrieve kodi_pathid and fileid
|
||||
# if the path or file already exists, the calls return current value
|
||||
kodi_fileid = self.kodi_db.add_file(filename,
|
||||
kodi_pathid,
|
||||
api.date_created())
|
||||
kodi_fileid = self.kodidb.add_file(filename,
|
||||
kodi_pathid,
|
||||
api.date_created())
|
||||
|
||||
# UPDATE THE EPISODE #####
|
||||
if update_item:
|
||||
LOG.info("UPDATE episode plex_id: %s - %s", plex_id, api.title())
|
||||
if kodi_fileid != old_kodi_fileid:
|
||||
self.kodi_db.remove_file(old_kodi_fileid)
|
||||
ratingid = self.kodi_db.get_ratingid(kodi_id,
|
||||
v.KODI_TYPE_EPISODE)
|
||||
self.kodi_db.update_ratings(kodi_id,
|
||||
v.KODI_TYPE_EPISODE,
|
||||
"default",
|
||||
userdata['Rating'],
|
||||
api.votecount(),
|
||||
ratingid)
|
||||
self.kodidb.remove_file(old_kodi_fileid)
|
||||
ratingid = self.kodidb.get_ratingid(kodi_id,
|
||||
v.KODI_TYPE_EPISODE)
|
||||
self.kodidb.update_ratings(kodi_id,
|
||||
v.KODI_TYPE_EPISODE,
|
||||
"default",
|
||||
userdata['Rating'],
|
||||
api.votecount(),
|
||||
ratingid)
|
||||
# update new uniqueid Kodi 17
|
||||
uniqueid = self.kodi_db.get_uniqueid(kodi_id,
|
||||
v.KODI_TYPE_EPISODE)
|
||||
self.kodi_db.update_uniqueid(kodi_id,
|
||||
v.KODI_TYPE_EPISODE,
|
||||
api.provider('tvdb'),
|
||||
"tvdb",
|
||||
uniqueid)
|
||||
query = '''
|
||||
UPDATE episode
|
||||
SET c00 = ?, c01 = ?, c03 = ?, c04 = ?, c05 = ?, c09 = ?,
|
||||
c10 = ?, c12 = ?, c13 = ?, c14 = ?, c15 = ?, c16 = ?,
|
||||
c18 = ?, c19 = ?, idFile=?, idSeason = ?,
|
||||
userrating = ?
|
||||
WHERE idEpisode = ?
|
||||
'''
|
||||
self.kodicursor.execute(
|
||||
query, (api.title(), api.plot(), ratingid, writer,
|
||||
api.premiere_date(), api.runtime(), director, season_no,
|
||||
episode_no, api.title(), airs_before_season,
|
||||
airs_before_episode, playurl, kodi_pathid, kodi_fileid,
|
||||
parent_id, userdata['UserRating'], kodi_id))
|
||||
uniqueid = self.kodidb.get_uniqueid(kodi_id,
|
||||
v.KODI_TYPE_EPISODE)
|
||||
self.kodidb.update_uniqueid(kodi_id,
|
||||
v.KODI_TYPE_EPISODE,
|
||||
api.provider('tvdb'),
|
||||
"tvdb",
|
||||
uniqueid)
|
||||
self.kodidb.update_episode(api.title(),
|
||||
api.plot(),
|
||||
ratingid,
|
||||
writer,
|
||||
api.premiere_date(),
|
||||
api.runtime(),
|
||||
director,
|
||||
season_no,
|
||||
episode_no,
|
||||
api.title(),
|
||||
airs_before_season,
|
||||
airs_before_episode,
|
||||
playurl,
|
||||
kodi_pathid,
|
||||
kodi_fileid,
|
||||
parent_id,
|
||||
userdata['UserRating'],
|
||||
kodi_id)
|
||||
|
||||
# OR ADD THE EPISODE #####
|
||||
else:
|
||||
LOG.info("ADD episode plex_id: %s - %s", plex_id, api.title())
|
||||
# Create the episode entry
|
||||
rating_id = self.kodi_db.get_ratingid(kodi_id,
|
||||
v.KODI_TYPE_EPISODE)
|
||||
self.kodi_db.add_ratings(rating_id,
|
||||
rating_id = self.kodidb.get_ratingid(kodi_id,
|
||||
v.KODI_TYPE_EPISODE)
|
||||
self.kodidb.add_ratings(rating_id,
|
||||
kodi_id,
|
||||
v.KODI_TYPE_EPISODE,
|
||||
"default",
|
||||
userdata['Rating'],
|
||||
api.votecount())
|
||||
# add new uniqueid Kodi 17
|
||||
uniqueid = self.kodidb.get_uniqueid(kodi_id,
|
||||
v.KODI_TYPE_EPISODE)
|
||||
self.kodidb.add_uniqueid(uniqueid,
|
||||
kodi_id,
|
||||
v.KODI_TYPE_EPISODE,
|
||||
"default",
|
||||
userdata['Rating'],
|
||||
api.votecount())
|
||||
# add new uniqueid Kodi 17
|
||||
uniqueid = self.kodi_db.get_uniqueid(kodi_id,
|
||||
v.KODI_TYPE_EPISODE)
|
||||
self.kodi_db.add_uniqueid(uniqueid,
|
||||
kodi_id,
|
||||
v.KODI_TYPE_EPISODE,
|
||||
api.provider('tvdb'),
|
||||
"tvdb")
|
||||
query = '''
|
||||
INSERT INTO episode( idEpisode, idFile, c00, c01, c03, c04,
|
||||
c05, c09, c10, c12, c13, c14, idShow, c15, c16, c18,
|
||||
c19, idSeason, userrating)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,
|
||||
?, ?)
|
||||
'''
|
||||
self.kodicursor.execute(
|
||||
query, (kodi_id, kodi_fileid, api.title(), api.plot(), rating_id,
|
||||
writer, api.premiere_date(), api.runtime(), director,
|
||||
season_no, episode_no, api.title(), grandparent_id,
|
||||
airs_before_season, airs_before_episode, playurl,
|
||||
kodi_pathid, parent_id, userdata['UserRating']))
|
||||
api.provider('tvdb'),
|
||||
"tvdb")
|
||||
self.kodidb.add_episode(kodi_id,
|
||||
kodi_fileid,
|
||||
api.title(),
|
||||
api.plot(),
|
||||
rating_id,
|
||||
writer,
|
||||
api.premiere_date(),
|
||||
api.runtime(),
|
||||
director,
|
||||
season_no,
|
||||
episode_no,
|
||||
api.title(),
|
||||
grandparent_id,
|
||||
airs_before_season,
|
||||
airs_before_episode,
|
||||
playurl,
|
||||
kodi_pathid,
|
||||
parent_id,
|
||||
userdata['UserRating'])
|
||||
|
||||
self.kodi_db.modify_people(kodi_id,
|
||||
v.KODI_TYPE_EPISODE,
|
||||
api.people_list())
|
||||
artwork.modify_artwork(api.artwork(),
|
||||
kodi_id,
|
||||
v.KODI_TYPE_EPISODE,
|
||||
self.kodicursor)
|
||||
self.kodidb.modify_people(kodi_id,
|
||||
v.KODI_TYPE_EPISODE,
|
||||
api.people_list())
|
||||
self.kodidb.modify_artwork(api.artwork(),
|
||||
kodi_id,
|
||||
v.KODI_TYPE_EPISODE)
|
||||
streams = api.mediastreams()
|
||||
self.kodi_db.modify_streams(kodi_fileid, streams, api.runtime())
|
||||
self.kodi_db.set_resume(kodi_fileid,
|
||||
api.resume_point(),
|
||||
api.runtime(),
|
||||
userdata['PlayCount'],
|
||||
userdata['LastPlayedDate'],
|
||||
None) # Do send None, we check here
|
||||
self.kodidb.modify_streams(kodi_fileid, streams, api.runtime())
|
||||
self.kodidb.set_resume(kodi_fileid,
|
||||
api.resume_point(),
|
||||
api.runtime(),
|
||||
userdata['PlayCount'],
|
||||
userdata['LastPlayedDate'],
|
||||
None) # Do send None, we check here
|
||||
if not state.DIRECT_PATHS:
|
||||
# need to set a SECOND file entry for a path without plex show id
|
||||
filename = api.file_name(force_first_media=True)
|
||||
|
@ -519,16 +498,16 @@ class Episode(ItemBase, TvShowMixin):
|
|||
filename = ('%s%s/?plex_id=%s&plex_type=%s&mode=play&filename=%s'
|
||||
% (path, show_id, plex_id, v.PLEX_TYPE_EPISODE,
|
||||
filename))
|
||||
kodi_pathid = self.kodi_db.add_video_path(path)
|
||||
kodi_fileid = self.kodi_db.add_file(filename,
|
||||
kodi_pathid,
|
||||
api.date_created())
|
||||
self.kodi_db.set_resume(kodi_fileid,
|
||||
api.resume_point(),
|
||||
api.runtime(),
|
||||
userdata['PlayCount'],
|
||||
userdata['LastPlayedDate'],
|
||||
None) # Do send None - 2nd entry
|
||||
kodi_pathid = self.kodidb.add_video_path(path)
|
||||
kodi_fileid = self.kodidb.add_file(filename,
|
||||
kodi_pathid,
|
||||
api.date_created())
|
||||
self.kodidb.set_resume(kodi_fileid,
|
||||
api.resume_point(),
|
||||
api.runtime(),
|
||||
userdata['PlayCount'],
|
||||
userdata['LastPlayedDate'],
|
||||
None) # Do send None - 2nd entry
|
||||
self.plexdb.add_episode(plex_id=plex_id,
|
||||
checksum=api.checksum(),
|
||||
section_id=section_id,
|
||||
|
|
129
resources/lib/kodi_db/__init__.py
Normal file
129
resources/lib/kodi_db/__init__.py
Normal file
|
@ -0,0 +1,129 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import absolute_import, division, unicode_literals
|
||||
from logging import getLogger
|
||||
|
||||
from .video import KodiVideoDB
|
||||
from .music import KodiMusicDB
|
||||
from .texture import KodiTextureDB
|
||||
|
||||
from .. import path_ops, utils, variables as v
|
||||
|
||||
LOG = getLogger('PLEX.kodi_db')
|
||||
|
||||
|
||||
def kodiid_from_filename(path, kodi_type=None, db_type=None):
|
||||
"""
|
||||
Returns kodi_id if we have an item in the Kodi video or audio database with
|
||||
said path. Feed with either koditype, e.v. 'movie', 'song' or the DB
|
||||
you want to poll ('video' or 'music')
|
||||
Returns None, <kodi_type> if not possible
|
||||
"""
|
||||
kodi_id = None
|
||||
path = utils.try_decode(path)
|
||||
try:
|
||||
filename = path.rsplit('/', 1)[1]
|
||||
path = path.rsplit('/', 1)[0] + '/'
|
||||
except IndexError:
|
||||
filename = path.rsplit('\\', 1)[1]
|
||||
path = path.rsplit('\\', 1)[0] + '\\'
|
||||
if kodi_type == v.KODI_TYPE_SONG or db_type == 'music':
|
||||
with KodiMusicDB() as kodidb:
|
||||
try:
|
||||
kodi_id = kodidb.music_id_from_filename(filename, path)
|
||||
except TypeError:
|
||||
LOG.debug('No Kodi audio db element found for path %s', path)
|
||||
else:
|
||||
kodi_type = v.KODI_TYPE_SONG
|
||||
else:
|
||||
with KodiVideoDB() as kodidb:
|
||||
try:
|
||||
kodi_id, kodi_type = kodidb.video_id_from_filename(filename,
|
||||
path)
|
||||
except TypeError:
|
||||
LOG.debug('No kodi video db element found for path %s', path)
|
||||
return kodi_id, kodi_type
|
||||
|
||||
|
||||
def setup_kodi_default_entries():
|
||||
"""
|
||||
Makes sure that we retain the Kodi standard databases. E.g. that there
|
||||
is a dummy artist with ID 1
|
||||
"""
|
||||
if utils.settings('enableMusic') == 'true':
|
||||
with KodiMusicDB() as kodidb:
|
||||
kodidb.cursor.execute('''
|
||||
INSERT OR REPLACE INTO artist(
|
||||
idArtist,
|
||||
strArtist,
|
||||
strMusicBrainzArtistID)
|
||||
VALUES (?, ?, ?)
|
||||
''', (1, '[Missing Tag]', 'Artist Tag Missing'))
|
||||
if v.KODIVERSION >= 18:
|
||||
kodidb.cursor.execute('''
|
||||
INSERT OR REPLACE INTO versiontagscan(
|
||||
idVersion,
|
||||
iNeedsScan,
|
||||
lastscanned)
|
||||
VALUES (?, ?, ?)
|
||||
''', (v.DB_MUSIC_VERSION[v.KODIVERSION],
|
||||
0,
|
||||
utils.unix_date_to_kodi(utils.unix_timestamp())))
|
||||
|
||||
|
||||
def reset_cached_images():
|
||||
LOG.info('Resetting cached artwork')
|
||||
# Remove all existing textures first
|
||||
path = path_ops.translate_path('special://thumbnails/')
|
||||
if path_ops.exists(path):
|
||||
path_ops.rmtree(path, ignore_errors=True)
|
||||
paths = ('', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'a', 'b', 'c', 'd', 'e', 'f',
|
||||
'Video', 'plex')
|
||||
for path in paths:
|
||||
new_path = path_ops.translate_path('special://thumbnails/%s' % path)
|
||||
path_ops.makedirs(path_ops.encode_path(new_path))
|
||||
with KodiTextureDB() as kodidb:
|
||||
for row in kodidb.cursor.execute('SELECT tbl_name FROM sqlite_master WHERE type=?',
|
||||
('table', )):
|
||||
if row[0] != 'version':
|
||||
kodidb.cursor.execute("DELETE FROM %s" % row[0])
|
||||
|
||||
|
||||
def wipe_dbs(music=True):
|
||||
"""
|
||||
Completely resets the Kodi databases 'video', 'texture' and 'music' (if
|
||||
music sync is enabled)
|
||||
"""
|
||||
LOG.warn('Wiping Kodi databases!')
|
||||
kinds = [KodiVideoDB, KodiTextureDB]
|
||||
if music:
|
||||
kinds.append(KodiMusicDB)
|
||||
for db in kinds:
|
||||
with db() as kodidb:
|
||||
kodidb.cursor.execute("SELECT name FROM sqlite_master WHERE type = 'table'")
|
||||
tables = kodidb.cursor.fetchall()
|
||||
tables = [i[0] for i in tables]
|
||||
if 'version' in tables:
|
||||
tables.remove('version')
|
||||
if 'versiontagscan' in tables:
|
||||
tables.remove('versiontagscan')
|
||||
for table in tables:
|
||||
kodidb.cursor.execute('DELETE FROM %s' % table)
|
||||
setup_kodi_default_entries()
|
||||
# Make sure Kodi knows we wiped the databases
|
||||
import xbmc
|
||||
xbmc.executebuiltin('UpdateLibrary(video)')
|
||||
if utils.settings('enableMusic') == 'true':
|
||||
xbmc.executebuiltin('UpdateLibrary(music)')
|
||||
|
||||
|
||||
KODIDB_FROM_PLEXTYPE = {
|
||||
v.PLEX_TYPE_MOVIE: KodiVideoDB,
|
||||
v.PLEX_TYPE_SHOW: KodiVideoDB,
|
||||
v.PLEX_TYPE_SEASON: KodiVideoDB,
|
||||
v.PLEX_TYPE_EPISODE: KodiVideoDB,
|
||||
v.PLEX_TYPE_ARTIST: KodiMusicDB,
|
||||
v.PLEX_TYPE_ALBUM: KodiMusicDB,
|
||||
v.PLEX_TYPE_SONG: KodiMusicDB
|
||||
}
|
102
resources/lib/kodi_db/common.py
Normal file
102
resources/lib/kodi_db/common.py
Normal file
|
@ -0,0 +1,102 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import absolute_import, division, unicode_literals
|
||||
|
||||
from .. import utils, path_ops
|
||||
|
||||
|
||||
class KodiDBBase(object):
|
||||
"""
|
||||
Kodi database methods used for all types of items
|
||||
"""
|
||||
def __init__(self, texture_db=False, cursor=None, artcursor=None):
|
||||
"""
|
||||
Allows direct use with a cursor instead of context mgr
|
||||
"""
|
||||
self._texture_db = texture_db
|
||||
self.cursor = cursor
|
||||
self.artconn = None
|
||||
self.artcursor = artcursor
|
||||
|
||||
def __enter__(self):
|
||||
self.kodiconn = utils.kodi_sql(self.db_kind)
|
||||
self.cursor = self.kodiconn.cursor()
|
||||
if self._texture_db:
|
||||
self.artconn = utils.kodi_sql('texture')
|
||||
self.artcursor = self.artconn.cursor()
|
||||
return self
|
||||
|
||||
def __exit__(self, e_typ, e_val, trcbak):
|
||||
self.kodiconn.commit()
|
||||
self.kodiconn.close()
|
||||
if self._texture_db:
|
||||
self.artconn.commit()
|
||||
self.artconn.close()
|
||||
|
||||
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):
|
||||
return (x[0] for x in
|
||||
self.cursor.execute('SELECT url FROM art WHERE type == ?',
|
||||
(kodi_type, )))
|
||||
|
||||
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)
|
||||
|
||||
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):
|
||||
for row in self.cursor.execute('SELECT url FROM art WHERE media_id = ? AND media_type = ?',
|
||||
(kodi_id, kodi_type, )):
|
||||
self.delete_cached_artwork(row[0])
|
||||
|
||||
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, ))
|
11
resources/lib/kodi_db/movies.py
Normal file
11
resources/lib/kodi_db/movies.py
Normal file
|
@ -0,0 +1,11 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import absolute_import, division, unicode_literals
|
||||
from logging import getLogger
|
||||
|
||||
from .video import KodiVideoDB
|
||||
|
||||
LOG = getLogger('PLEX.kodi_db.movies')
|
||||
|
||||
|
||||
class KodiMovieDB(KodiVideoDB):
|
247
resources/lib/kodi_db/music.py
Normal file
247
resources/lib/kodi_db/music.py
Normal file
|
@ -0,0 +1,247 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import absolute_import, division, unicode_literals
|
||||
from logging import getLogger
|
||||
|
||||
from . import common
|
||||
from .. import utils, variables as v
|
||||
|
||||
LOG = getLogger('PLEX.kodi_db.music')
|
||||
|
||||
|
||||
class KodiMusicDB(common.KodiDBBase):
|
||||
db_kind = 'music'
|
||||
|
||||
def __enter__(self):
|
||||
self.kodiconn = utils.kodi_sql('music')
|
||||
self.cursor = self.kodiconn.cursor()
|
||||
return self
|
||||
|
||||
def add_music_path(self, path, hash_string=None):
|
||||
"""
|
||||
Add the path (unicode) to the music DB, if it does not exist already.
|
||||
Returns the path id
|
||||
Set hash_string to something unicode to set the strHash attribute
|
||||
"""
|
||||
# SQL won't return existing paths otherwise
|
||||
path = '' if path is None else path
|
||||
self.cursor.execute('SELECT idPath FROM path WHERE strPath = ?',
|
||||
(path,))
|
||||
try:
|
||||
pathid = self.cursor.fetchone()[0]
|
||||
except TypeError:
|
||||
self.cursor.execute("SELECT COALESCE(MAX(idPath),0) FROM path")
|
||||
pathid = self.cursor.fetchone()[0] + 1
|
||||
self.cursor.execute('''
|
||||
INSERT INTO path(idPath, strPath, strHash)
|
||||
VALUES (?, ?, ?)
|
||||
''',
|
||||
(pathid, path, hash_string))
|
||||
return pathid
|
||||
|
||||
def music_id_from_filename(self, filename, path):
|
||||
"""
|
||||
Returns the Kodi song_id from the Kodi music database or None if not
|
||||
found OR something went wrong.
|
||||
"""
|
||||
self.cursor.execute('SELECT idPath FROM path WHERE strPath = ?',
|
||||
(path,))
|
||||
path_ids = self.cursor.fetchall()
|
||||
if len(path_ids) != 1:
|
||||
LOG.debug('Found wrong number of path ids: %s for path %s, abort',
|
||||
path_ids, path)
|
||||
return
|
||||
self.cursor.execute('SELECT idSong FROM song WHERE strFileName = ? AND idPath = ?',
|
||||
(filename, path_ids[0][0]))
|
||||
song_ids = self.cursor.fetchall()
|
||||
if len(song_ids) != 1:
|
||||
LOG.info('Found wrong number of songs %s, abort', song_ids)
|
||||
return
|
||||
return song_ids[0][0]
|
||||
|
||||
def delete_song_from_song_artist(self, song_id):
|
||||
"""
|
||||
Deletes son from song_artist table and possibly orphaned roles
|
||||
"""
|
||||
self.cursor.execute('SELECT idArtist, idRole FROM song_artist WHERE idSong = ? LIMIT 1',
|
||||
(song_id, ))
|
||||
artist = self.cursor.fetchone()
|
||||
if artist is None:
|
||||
# No entry to begin with
|
||||
return
|
||||
# Delete the entry
|
||||
self.cursor.execute('DELETE FROM song_artist WHERE idSong = ?',
|
||||
(song_id, ))
|
||||
# Check whether we need to delete orphaned roles
|
||||
self.cursor.execute('SELECT idRole FROM song_artist WHERE idRole = ? LIMIT 1',
|
||||
(artist[1], ))
|
||||
if not self.cursor.fetchone():
|
||||
# Delete orphaned role
|
||||
self.cursor.execute('DELETE FROM role WHERE idRole = ?',
|
||||
(artist[1], ))
|
||||
|
||||
def delete_album_from_discography(self, album_id):
|
||||
"""
|
||||
Removes the album with id album_id from the table discography
|
||||
"""
|
||||
# Need to get the album name as a string first!
|
||||
self.cursor.execute('SELECT strAlbum, iYear FROM album WHERE idAlbum = ? LIMIT 1',
|
||||
(album_id, ))
|
||||
try:
|
||||
name, year = self.cursor.fetchone()
|
||||
except TypeError:
|
||||
return
|
||||
self.cursor.execute('SELECT idArtist FROM album_artist WHERE idAlbum = ? LIMIT 1',
|
||||
(album_id, ))
|
||||
artist = self.cursor.fetchone()
|
||||
if not artist:
|
||||
return
|
||||
self.cursor.execute('DELETE FROM discography WHERE idArtist = ? AND strAlbum = ? AND strYear = ?',
|
||||
(artist[0], name, year))
|
||||
|
||||
def delete_song_from_song_genre(self, song_id):
|
||||
"""
|
||||
Deletes the one entry with id song_id from the song_genre table.
|
||||
Will also delete orphaned genres from genre table
|
||||
"""
|
||||
self.cursor.execute('SELECT idGenre FROM song_genre WHERE idSong = ?',
|
||||
(song_id, ))
|
||||
genres = self.cursor.fetchall()
|
||||
self.cursor.execute('DELETE FROM song_genre WHERE idSong = ?',
|
||||
(song_id, ))
|
||||
# Check for orphaned genres in both song_genre and album_genre tables
|
||||
for genre in genres:
|
||||
self.cursor.execute('SELECT idGenre FROM song_genre WHERE idGenre = ? LIMIT 1',
|
||||
(genre[0], ))
|
||||
if not self.cursor.fetchone():
|
||||
self.cursor.execute('SELECT idGenre FROM album_genre WHERE idGenre = ? LIMIT 1',
|
||||
(genre[0], ))
|
||||
if not self.cursor.fetchone():
|
||||
self.cursor.execute('DELETE FROM genre WHERE idGenre = ?',
|
||||
(genre[0], ))
|
||||
|
||||
def delete_album_from_album_genre(self, album_id):
|
||||
"""
|
||||
Deletes the one entry with id album_id from the album_genre table.
|
||||
Will also delete orphaned genres from genre table
|
||||
"""
|
||||
self.cursor.execute('SELECT idGenre FROM album_genre WHERE idAlbum = ?',
|
||||
(album_id, ))
|
||||
genres = self.cursor.fetchall()
|
||||
self.cursor.execute('DELETE FROM album_genre WHERE idAlbum = ?',
|
||||
(album_id, ))
|
||||
# Check for orphaned genres in both album_genre and song_genre tables
|
||||
for genre in genres:
|
||||
self.cursor.execute('SELECT idGenre FROM album_genre WHERE idGenre = ? LIMIT 1',
|
||||
(genre[0], ))
|
||||
if not self.cursor.fetchone():
|
||||
self.cursor.execute('SELECT idGenre FROM song_genre WHERE idGenre = ? LIMIT 1',
|
||||
(genre[0], ))
|
||||
if not self.cursor.fetchone():
|
||||
self.cursor.execute('DELETE FROM genre WHERE idGenre = ?',
|
||||
(genre[0], ))
|
||||
|
||||
def add_album(self, name, musicbrainz):
|
||||
"""
|
||||
Adds a single album to the DB
|
||||
"""
|
||||
self.cursor.execute('SELECT idAlbum FROM album WHERE strMusicBrainzAlbumID = ?',
|
||||
(musicbrainz, ))
|
||||
try:
|
||||
albumid = self.cursor.fetchone()[0]
|
||||
except TypeError:
|
||||
# Create the album
|
||||
self.cursor.execute('SELECT COALESCE(MAX(idAlbum),0) FROM album')
|
||||
albumid = self.cursor.fetchone()[0] + 1
|
||||
self.cursor.execute('''
|
||||
INSERT INTO album(
|
||||
idAlbum,
|
||||
strAlbum,
|
||||
strMusicBrainzAlbumID,
|
||||
strReleaseType)
|
||||
VALUES (?, ?, ?, ?)
|
||||
''', (albumid, name, musicbrainz, 'album'))
|
||||
return albumid
|
||||
|
||||
def add_music_genres(self, kodiid, genres, mediatype):
|
||||
"""
|
||||
Adds a list of genres (list of unicode) for a certain Kodi item
|
||||
"""
|
||||
if mediatype == "album":
|
||||
# Delete current genres for clean slate
|
||||
self.cursor.execute('DELETE FROM album_genre WHERE idAlbum = ?',
|
||||
(kodiid, ))
|
||||
for genre in genres:
|
||||
self.cursor.execute('SELECT idGenre FROM genre WHERE strGenre = ?',
|
||||
(genre, ))
|
||||
try:
|
||||
genreid = self.cursor.fetchone()[0]
|
||||
except TypeError:
|
||||
# Create the genre
|
||||
self.cursor.execute('SELECT COALESCE(MAX(idGenre),0) FROM genre')
|
||||
genreid = self.cursor.fetchone()[0] + 1
|
||||
self.cursor.execute('INSERT INTO genre(idGenre, strGenre) VALUES(?, ?)',
|
||||
(genreid, genre))
|
||||
self.cursor.execute('''
|
||||
INSERT OR REPLACE INTO album_genre(
|
||||
idGenre,
|
||||
idAlbum)
|
||||
VALUES (?, ?)
|
||||
''', (genreid, kodiid))
|
||||
elif mediatype == "song":
|
||||
# Delete current genres for clean slate
|
||||
self.cursor.execute('DELETE FROM song_genre WHERE idSong = ?',
|
||||
(kodiid, ))
|
||||
for genre in genres:
|
||||
self.cursor.execute('SELECT idGenre FROM genre WHERE strGenre = ?',
|
||||
(genre, ))
|
||||
try:
|
||||
genreid = self.cursor.fetchone()[0]
|
||||
except TypeError:
|
||||
# Create the genre
|
||||
self.cursor.execute('SELECT COALESCE(MAX(idGenre),0) FROM genre')
|
||||
genreid = self.cursor.fetchone()[0] + 1
|
||||
self.cursor.execute('INSERT INTO genre(idGenre, strGenre) values(?, ?)',
|
||||
(genreid, genre))
|
||||
self.cursor.execute('''
|
||||
INSERT OR REPLACE INTO song_genre(
|
||||
idGenre,
|
||||
idSong)
|
||||
VALUES (?, ?)
|
||||
''', (genreid, kodiid))
|
||||
|
||||
def add_artist(self, name, musicbrainz):
|
||||
"""
|
||||
Adds a single artist's name to the db
|
||||
"""
|
||||
self.cursor.execute('''
|
||||
SELECT idArtist, strArtist
|
||||
FROM artist
|
||||
WHERE strMusicBrainzArtistID = ?
|
||||
''', (musicbrainz, ))
|
||||
try:
|
||||
result = self.cursor.fetchone()
|
||||
artistid = result[0]
|
||||
artistname = result[1]
|
||||
except TypeError:
|
||||
self.cursor.execute('SELECT idArtist FROM artist WHERE strArtist = ? COLLATE NOCASE',
|
||||
(name, ))
|
||||
try:
|
||||
artistid = self.cursor.fetchone()[0]
|
||||
except TypeError:
|
||||
# Krypton has a dummy first entry idArtist: 1 strArtist:
|
||||
# [Missing Tag] strMusicBrainzArtistID: Artist Tag Missing
|
||||
self.cursor.execute('SELECT COALESCE(MAX(idArtist),1) FROM artist')
|
||||
artistid = self.cursor.fetchone()[0] + 1
|
||||
self.cursor.execute('''
|
||||
INSERT INTO artist(
|
||||
idArtist,
|
||||
strArtist,
|
||||
strMusicBrainzArtistID)
|
||||
VALUES (?, ?, ?)
|
||||
''', (artistid, name, musicbrainz))
|
||||
else:
|
||||
if artistname != name:
|
||||
self.cursor.execute('UPDATE artist SET strArtist = ? WHERE idArtist = ?',
|
||||
(name, artistid,))
|
||||
return artistid
|
17
resources/lib/kodi_db/texture.py
Normal file
17
resources/lib/kodi_db/texture.py
Normal file
|
@ -0,0 +1,17 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import absolute_import, division, unicode_literals
|
||||
|
||||
from . import common
|
||||
|
||||
|
||||
class KodiTextureDB(common.KodiDBBase):
|
||||
db_kind = 'texture'
|
||||
|
||||
def url_not_yet_cached(self, url):
|
||||
"""
|
||||
Returns True if url has not yet been cached to the Kodi texture cache
|
||||
"""
|
||||
self.cursor.execute('SELECT url FROM texture WHERE url = ? LIMIT 1',
|
||||
(url, ))
|
||||
return self.cursor.fetchone() is None
|
|
@ -1,52 +1,17 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Connect to the Kodi databases (video and music) and operate on them
|
||||
"""
|
||||
from __future__ import absolute_import, division, unicode_literals
|
||||
from logging import getLogger
|
||||
from sqlite3 import IntegrityError
|
||||
|
||||
from . import artwork, utils, variables as v, state, path_ops
|
||||
from . import common
|
||||
from .. import path_ops, utils, variables as v, state
|
||||
|
||||
###############################################################################
|
||||
|
||||
LOG = getLogger('PLEX.kodidb_functions')
|
||||
LOG = getLogger('PLEX.kodi_db.video')
|
||||
|
||||
|
||||
class GetKodiDB(object):
|
||||
"""
|
||||
Usage: with GetKodiDB(db_type) as kodi_db:
|
||||
do stuff with kodi_db
|
||||
|
||||
Parameters:
|
||||
db_type: DB to open: 'video', 'music', 'plex', 'texture'
|
||||
|
||||
On exiting "with" (no matter what), commits get automatically committed
|
||||
and the db gets closed
|
||||
"""
|
||||
def __init__(self, db_type):
|
||||
self.kodiconn = None
|
||||
self.db_type = db_type
|
||||
|
||||
def __enter__(self):
|
||||
self.kodiconn = utils.kodi_sql(self.db_type)
|
||||
kodi_db = KodiDBMethods(self.kodiconn.cursor())
|
||||
return kodi_db
|
||||
|
||||
def __exit__(self, typus, value, traceback):
|
||||
self.kodiconn.commit()
|
||||
self.kodiconn.close()
|
||||
|
||||
|
||||
class KodiDBMethods(object):
|
||||
"""
|
||||
Best used indirectly with another Class GetKodiDB:
|
||||
with GetKodiDB(db_type) as kodi_db:
|
||||
kodi_db.method()
|
||||
"""
|
||||
def __init__(self, cursor):
|
||||
self.cursor = cursor
|
||||
class KodiVideoDB(common.KodiDBBase):
|
||||
db_kind = 'video'
|
||||
|
||||
def setup_path_table(self):
|
||||
"""
|
||||
|
@ -155,28 +120,6 @@ class KodiDBMethods(object):
|
|||
content, scraper, 1))
|
||||
return pathid
|
||||
|
||||
def add_music_path(self, path, hash_string=None):
|
||||
"""
|
||||
Add the path (unicode) to the music DB, if it does not exist already.
|
||||
Returns the path id
|
||||
Set hash_string to something unicode to set the strHash attribute
|
||||
"""
|
||||
# SQL won't return existing paths otherwise
|
||||
path = '' if path is None else path
|
||||
self.cursor.execute('SELECT idPath FROM path WHERE strPath = ?',
|
||||
(path,))
|
||||
try:
|
||||
pathid = self.cursor.fetchone()[0]
|
||||
except TypeError:
|
||||
self.cursor.execute("SELECT COALESCE(MAX(idPath),0) FROM path")
|
||||
pathid = self.cursor.fetchone()[0] + 1
|
||||
self.cursor.execute('''
|
||||
INSERT INTO path(idPath, strPath, strHash)
|
||||
VALUES (?, ?, ?)
|
||||
''',
|
||||
(pathid, path, hash_string))
|
||||
return pathid
|
||||
|
||||
def get_path(self, path):
|
||||
"""
|
||||
Returns the idPath from the path table for path [unicode] or None
|
||||
|
@ -443,7 +386,7 @@ class KodiDBMethods(object):
|
|||
self.cursor.execute(query_actor_delete, (person[0],))
|
||||
if kind == 'actor':
|
||||
# Delete any associated artwork
|
||||
artwork.delete_artwork(person[0], 'actor', self.cursor)
|
||||
self.delete_artwork(person[0], 'actor')
|
||||
# Save new people to Kodi DB by iterating over the remaining entries
|
||||
if kind == 'actor':
|
||||
query = 'INSERT INTO actor_link VALUES (?, ?, ?, ?, ?)'
|
||||
|
@ -489,11 +432,10 @@ class KodiDBMethods(object):
|
|||
'VALUES (?, ?)',
|
||||
(actor_id, name))
|
||||
if art_url:
|
||||
artwork.modify_art(art_url,
|
||||
actor_id,
|
||||
'actor',
|
||||
'thumb',
|
||||
self.cursor)
|
||||
self.modify_art(art_url,
|
||||
actor_id,
|
||||
'actor',
|
||||
'thumb')
|
||||
return actor_id
|
||||
|
||||
def get_art(self, kodi_id, kodi_type):
|
||||
|
@ -610,26 +552,6 @@ class KodiDBMethods(object):
|
|||
return
|
||||
return movie_id, typus
|
||||
|
||||
def music_id_from_filename(self, filename, path):
|
||||
"""
|
||||
Returns the Kodi song_id from the Kodi music database or None if not
|
||||
found OR something went wrong.
|
||||
"""
|
||||
self.cursor.execute('SELECT idPath FROM path WHERE strPath = ?',
|
||||
(path,))
|
||||
path_ids = self.cursor.fetchall()
|
||||
if len(path_ids) != 1:
|
||||
LOG.debug('Found wrong number of path ids: %s for path %s, abort',
|
||||
path_ids, path)
|
||||
return
|
||||
self.cursor.execute('SELECT idSong FROM song WHERE strFileName = ? AND idPath = ?',
|
||||
(filename, path_ids[0][0]))
|
||||
song_ids = self.cursor.fetchall()
|
||||
if len(song_ids) != 1:
|
||||
LOG.info('Found wrong number of songs %s, abort', song_ids)
|
||||
return
|
||||
return song_ids[0][0]
|
||||
|
||||
def get_resume(self, file_id):
|
||||
"""
|
||||
Returns the first resume point in seconds (int) if found, else None for
|
||||
|
@ -803,208 +725,6 @@ class KodiDBMethods(object):
|
|||
''', (seasonid, showid, seasonnumber))
|
||||
return seasonid
|
||||
|
||||
def add_artist(self, name, musicbrainz):
|
||||
"""
|
||||
Adds a single artist's name to the db
|
||||
"""
|
||||
self.cursor.execute('''
|
||||
SELECT idArtist, strArtist
|
||||
FROM artist
|
||||
WHERE strMusicBrainzArtistID = ?
|
||||
''', (musicbrainz, ))
|
||||
try:
|
||||
result = self.cursor.fetchone()
|
||||
artistid = result[0]
|
||||
artistname = result[1]
|
||||
except TypeError:
|
||||
self.cursor.execute('SELECT idArtist FROM artist WHERE strArtist = ? COLLATE NOCASE',
|
||||
(name, ))
|
||||
try:
|
||||
artistid = self.cursor.fetchone()[0]
|
||||
except TypeError:
|
||||
# Krypton has a dummy first entry idArtist: 1 strArtist:
|
||||
# [Missing Tag] strMusicBrainzArtistID: Artist Tag Missing
|
||||
self.cursor.execute('SELECT COALESCE(MAX(idArtist),1) FROM artist')
|
||||
artistid = self.cursor.fetchone()[0] + 1
|
||||
self.cursor.execute('''
|
||||
INSERT INTO artist(
|
||||
idArtist,
|
||||
strArtist,
|
||||
strMusicBrainzArtistID)
|
||||
VALUES (?, ?, ?)
|
||||
''', (artistid, name, musicbrainz))
|
||||
else:
|
||||
if artistname != name:
|
||||
self.cursor.execute('UPDATE artist SET strArtist = ? WHERE idArtist = ?',
|
||||
(name, artistid,))
|
||||
return artistid
|
||||
|
||||
def delete_song_from_song_artist(self, song_id):
|
||||
"""
|
||||
Deletes son from song_artist table and possibly orphaned roles
|
||||
"""
|
||||
self.cursor.execute('SELECT idArtist, idRole FROM song_artist WHERE idSong = ? LIMIT 1',
|
||||
(song_id, ))
|
||||
artist = self.cursor.fetchone()
|
||||
if artist is None:
|
||||
# No entry to begin with
|
||||
return
|
||||
# Delete the entry
|
||||
self.cursor.execute('DELETE FROM song_artist WHERE idSong = ?',
|
||||
(song_id, ))
|
||||
# Check whether we need to delete orphaned roles
|
||||
self.cursor.execute('SELECT idRole FROM song_artist WHERE idRole = ? LIMIT 1',
|
||||
(artist[1], ))
|
||||
if not self.cursor.fetchone():
|
||||
# Delete orphaned role
|
||||
self.cursor.execute('DELETE FROM role WHERE idRole = ?',
|
||||
(artist[1], ))
|
||||
|
||||
def delete_album_from_discography(self, album_id):
|
||||
"""
|
||||
Removes the album with id album_id from the table discography
|
||||
"""
|
||||
# Need to get the album name as a string first!
|
||||
self.cursor.execute('SELECT strAlbum, iYear FROM album WHERE idAlbum = ? LIMIT 1',
|
||||
(album_id, ))
|
||||
try:
|
||||
name, year = self.cursor.fetchone()
|
||||
except TypeError:
|
||||
return
|
||||
self.cursor.execute('SELECT idArtist FROM album_artist WHERE idAlbum = ? LIMIT 1',
|
||||
(album_id, ))
|
||||
artist = self.cursor.fetchone()
|
||||
if not artist:
|
||||
return
|
||||
self.cursor.execute('DELETE FROM discography WHERE idArtist = ? AND strAlbum = ? AND strYear = ?',
|
||||
(artist[0], name, year))
|
||||
|
||||
def delete_song_from_song_genre(self, song_id):
|
||||
"""
|
||||
Deletes the one entry with id song_id from the song_genre table.
|
||||
Will also delete orphaned genres from genre table
|
||||
"""
|
||||
self.cursor.execute('SELECT idGenre FROM song_genre WHERE idSong = ?',
|
||||
(song_id, ))
|
||||
genres = self.cursor.fetchall()
|
||||
self.cursor.execute('DELETE FROM song_genre WHERE idSong = ?',
|
||||
(song_id, ))
|
||||
# Check for orphaned genres in both song_genre and album_genre tables
|
||||
for genre in genres:
|
||||
self.cursor.execute('SELECT idGenre FROM song_genre WHERE idGenre = ? LIMIT 1',
|
||||
(genre[0], ))
|
||||
if not self.cursor.fetchone():
|
||||
self.cursor.execute('SELECT idGenre FROM album_genre WHERE idGenre = ? LIMIT 1',
|
||||
(genre[0], ))
|
||||
if not self.cursor.fetchone():
|
||||
self.cursor.execute('DELETE FROM genre WHERE idGenre = ?',
|
||||
(genre[0], ))
|
||||
|
||||
def delete_album_from_album_genre(self, album_id):
|
||||
"""
|
||||
Deletes the one entry with id album_id from the album_genre table.
|
||||
Will also delete orphaned genres from genre table
|
||||
"""
|
||||
self.cursor.execute('SELECT idGenre FROM album_genre WHERE idAlbum = ?',
|
||||
(album_id, ))
|
||||
genres = self.cursor.fetchall()
|
||||
self.cursor.execute('DELETE FROM album_genre WHERE idAlbum = ?',
|
||||
(album_id, ))
|
||||
# Check for orphaned genres in both album_genre and song_genre tables
|
||||
for genre in genres:
|
||||
self.cursor.execute('SELECT idGenre FROM album_genre WHERE idGenre = ? LIMIT 1',
|
||||
(genre[0], ))
|
||||
if not self.cursor.fetchone():
|
||||
self.cursor.execute('SELECT idGenre FROM song_genre WHERE idGenre = ? LIMIT 1',
|
||||
(genre[0], ))
|
||||
if not self.cursor.fetchone():
|
||||
self.cursor.execute('DELETE FROM genre WHERE idGenre = ?',
|
||||
(genre[0], ))
|
||||
|
||||
def add_album(self, name, musicbrainz):
|
||||
"""
|
||||
Adds a single album to the DB
|
||||
"""
|
||||
self.cursor.execute('SELECT idAlbum FROM album WHERE strMusicBrainzAlbumID = ?',
|
||||
(musicbrainz, ))
|
||||
try:
|
||||
albumid = self.cursor.fetchone()[0]
|
||||
except TypeError:
|
||||
# Create the album
|
||||
self.cursor.execute('SELECT COALESCE(MAX(idAlbum),0) FROM album')
|
||||
albumid = self.cursor.fetchone()[0] + 1
|
||||
self.cursor.execute('''
|
||||
INSERT INTO album(
|
||||
idAlbum,
|
||||
strAlbum,
|
||||
strMusicBrainzAlbumID,
|
||||
strReleaseType)
|
||||
VALUES (?, ?, ?, ?)
|
||||
''', (albumid, name, musicbrainz, 'album'))
|
||||
return albumid
|
||||
|
||||
def add_music_genres(self, kodiid, genres, mediatype):
|
||||
"""
|
||||
Adds a list of genres (list of unicode) for a certain Kodi item
|
||||
"""
|
||||
if mediatype == "album":
|
||||
# Delete current genres for clean slate
|
||||
self.cursor.execute('DELETE FROM album_genre WHERE idAlbum = ?',
|
||||
(kodiid, ))
|
||||
for genre in genres:
|
||||
self.cursor.execute('SELECT idGenre FROM genre WHERE strGenre = ?',
|
||||
(genre, ))
|
||||
try:
|
||||
genreid = self.cursor.fetchone()[0]
|
||||
except TypeError:
|
||||
# Create the genre
|
||||
self.cursor.execute('SELECT COALESCE(MAX(idGenre),0) FROM genre')
|
||||
genreid = self.cursor.fetchone()[0] + 1
|
||||
self.cursor.execute('INSERT INTO genre(idGenre, strGenre) VALUES(?, ?)',
|
||||
(genreid, genre))
|
||||
self.cursor.execute('''
|
||||
INSERT OR REPLACE INTO album_genre(
|
||||
idGenre,
|
||||
idAlbum)
|
||||
VALUES (?, ?)
|
||||
''', (genreid, kodiid))
|
||||
elif mediatype == "song":
|
||||
# Delete current genres for clean slate
|
||||
self.cursor.execute('DELETE FROM song_genre WHERE idSong = ?',
|
||||
(kodiid, ))
|
||||
for genre in genres:
|
||||
self.cursor.execute('SELECT idGenre FROM genre WHERE strGenre = ?',
|
||||
(genre, ))
|
||||
try:
|
||||
genreid = self.cursor.fetchone()[0]
|
||||
except TypeError:
|
||||
# Create the genre
|
||||
self.cursor.execute('SELECT COALESCE(MAX(idGenre),0) FROM genre')
|
||||
genreid = self.cursor.fetchone()[0] + 1
|
||||
self.cursor.execute('INSERT INTO genre(idGenre, strGenre) values(?, ?)',
|
||||
(genreid, genre))
|
||||
self.cursor.execute('''
|
||||
INSERT OR REPLACE INTO song_genre(
|
||||
idGenre,
|
||||
idSong)
|
||||
VALUES (?, ?)
|
||||
''', (genreid, kodiid))
|
||||
|
||||
# Krypton only stuff ##############################
|
||||
|
||||
def update_userrating(self, kodi_id, kodi_type, userrating):
|
||||
"""
|
||||
Updates userrating for >=Krypton
|
||||
"""
|
||||
if kodi_type == v.KODI_TYPE_MOVIE:
|
||||
identifier = 'idMovie'
|
||||
elif kodi_type == v.KODI_TYPE_EPISODE:
|
||||
identifier = 'idEpisode'
|
||||
elif kodi_type == v.KODI_TYPE_SONG:
|
||||
identifier = 'idSong'
|
||||
self.cursor.execute('UPDATE %s SET userrating = ? WHERE ? = ?' % kodi_type,
|
||||
(userrating, identifier, kodi_id))
|
||||
|
||||
def add_uniqueid(self, *args):
|
||||
"""
|
||||
Feed with:
|
||||
|
@ -1103,141 +823,151 @@ class KodiDBMethods(object):
|
|||
self.cursor.execute('DELETE FROM rating WHERE media_id = ? AND media_type = ?',
|
||||
(kodi_id, kodi_type))
|
||||
|
||||
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 new_show_id(self):
|
||||
self.cursor.execute('SELECT COALESCE(MAX(idShow), 0) FROM tvshow')
|
||||
return self.cursor.fetchone()[0] + 1
|
||||
|
||||
def artwork_generator(self, kodi_type):
|
||||
"""
|
||||
"""
|
||||
return (x[0] for x in
|
||||
self.cursor.execute('SELECT url FROM art WHERE type == ?',
|
||||
(kodi_type, )))
|
||||
def new_episode_id(self):
|
||||
self.cursor.execute('SELECT COALESCE(MAX(idEpisode), 0) FROM episode')
|
||||
return self.cursor.fetchone()[0] + 1
|
||||
|
||||
def url_not_yet_cached(self, url):
|
||||
"""
|
||||
Returns True if url has not yet been cached to the Kodi texture cache
|
||||
"""
|
||||
self.cursor.execute('SELECT url FROM texture WHERE url == ? LIMIT 1',
|
||||
(url, ))
|
||||
return self.cursor.fetchone() is None
|
||||
def add_episode(self, *args):
|
||||
self.cursor.execute(
|
||||
'''
|
||||
INSERT INTO episode(
|
||||
idEpisode,
|
||||
idFile,
|
||||
c00,
|
||||
c01,
|
||||
c03,
|
||||
c04,
|
||||
c05,
|
||||
c09,
|
||||
c10,
|
||||
c12,
|
||||
c13,
|
||||
c14,
|
||||
idShow,
|
||||
c15,
|
||||
c16,
|
||||
c18,
|
||||
c19,
|
||||
idSeason,
|
||||
userrating)
|
||||
VALUES
|
||||
(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
''', (args))
|
||||
|
||||
def update_episode(self, *args):
|
||||
self.cursor.execute(
|
||||
'''
|
||||
UPDATE episode
|
||||
SET c00 = ?,
|
||||
c01 = ?,
|
||||
c03 = ?,
|
||||
c04 = ?,
|
||||
c05 = ?,
|
||||
c09 = ?,
|
||||
c10 = ?,
|
||||
c12 = ?,
|
||||
c13 = ?,
|
||||
c14 = ?,
|
||||
c15 = ?,
|
||||
c16 = ?,
|
||||
c18 = ?,
|
||||
c19 = ?,
|
||||
idFile=?,
|
||||
idSeason = ?,
|
||||
userrating = ?
|
||||
WHERE idEpisode = ?
|
||||
''', (args))
|
||||
|
||||
def kodiid_from_filename(path, kodi_type=None, db_type=None):
|
||||
"""
|
||||
Returns kodi_id if we have an item in the Kodi video or audio database with
|
||||
said path. Feed with either koditype, e.v. 'movie', 'song' or the DB
|
||||
you want to poll ('video' or 'music')
|
||||
Returns None, <kodi_type> if not possible
|
||||
"""
|
||||
kodi_id = None
|
||||
path = utils.try_decode(path)
|
||||
try:
|
||||
filename = path.rsplit('/', 1)[1]
|
||||
path = path.rsplit('/', 1)[0] + '/'
|
||||
except IndexError:
|
||||
filename = path.rsplit('\\', 1)[1]
|
||||
path = path.rsplit('\\', 1)[0] + '\\'
|
||||
if kodi_type == v.KODI_TYPE_SONG or db_type == 'music':
|
||||
with GetKodiDB('music') as kodi_db:
|
||||
try:
|
||||
kodi_id = kodi_db.music_id_from_filename(filename, path)
|
||||
except TypeError:
|
||||
LOG.debug('No Kodi audio db element found for path %s', path)
|
||||
else:
|
||||
kodi_type = v.KODI_TYPE_SONG
|
||||
else:
|
||||
with GetKodiDB('video') as kodi_db:
|
||||
try:
|
||||
kodi_id, kodi_type = kodi_db.video_id_from_filename(filename,
|
||||
path)
|
||||
except TypeError:
|
||||
LOG.debug('No kodi video db element found for path %s', path)
|
||||
return kodi_id, kodi_type
|
||||
def add_show(self, *args):
|
||||
self.cursor.execute(
|
||||
'''
|
||||
INSERT INTO tvshow(
|
||||
idShow,
|
||||
c00,
|
||||
c01,
|
||||
c04,
|
||||
c05,
|
||||
c08,
|
||||
c09,
|
||||
c12,
|
||||
c13,
|
||||
c14,
|
||||
c15)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
''', (args))
|
||||
|
||||
def update_show(self, *args):
|
||||
self.cursor.execute(
|
||||
'''
|
||||
UPDATE tvshow
|
||||
SET c00 = ?,
|
||||
c01 = ?,
|
||||
c04 = ?,
|
||||
c05 = ?,
|
||||
c08 = ?,
|
||||
c09 = ?,
|
||||
c12 = ?,
|
||||
c13 = ?,
|
||||
c14 = ?,
|
||||
c15 = ?
|
||||
WHERE idShow = ?
|
||||
''', (args))
|
||||
|
||||
def setup_kodi_default_entries():
|
||||
"""
|
||||
Makes sure that we retain the Kodi standard databases. E.g. that there
|
||||
is a dummy artist with ID 1
|
||||
"""
|
||||
if utils.settings('enableMusic') == 'true':
|
||||
with GetKodiDB('music') as kodi_db:
|
||||
kodi_db.cursor.execute('''
|
||||
INSERT OR REPLACE INTO artist(
|
||||
idArtist,
|
||||
strArtist,
|
||||
strMusicBrainzArtistID)
|
||||
VALUES (?, ?, ?)
|
||||
''', (1, '[Missing Tag]', 'Artist Tag Missing'))
|
||||
if v.KODIVERSION >= 18:
|
||||
kodi_db.cursor.execute('''
|
||||
INSERT OR REPLACE INTO versiontagscan(
|
||||
idVersion,
|
||||
iNeedsScan,
|
||||
lastscanned)
|
||||
VALUES (?, ?, ?)
|
||||
''', (v.DB_MUSIC_VERSION[v.KODIVERSION],
|
||||
0,
|
||||
utils.unix_date_to_kodi(utils.unix_timestamp())))
|
||||
def add_showlinkpath(self, kodi_id, kodi_pathid):
|
||||
self.cursor.execute('INSERT INTO tvshowlinkpath(idShow, idPath) VALUES (?, ?)',
|
||||
(kodi_id, kodi_pathid))
|
||||
|
||||
def remove_show(self, kodi_id):
|
||||
self.cursor.execute('DELETE FROM tvshow WHERE idShow = ?', (kodi_id,))
|
||||
|
||||
def reset_cached_images():
|
||||
LOG.info('Resetting cached artwork')
|
||||
# Remove all existing textures first
|
||||
path = path_ops.translate_path('special://thumbnails/')
|
||||
if path_ops.exists(path):
|
||||
path_ops.rmtree(path, ignore_errors=True)
|
||||
paths = ('', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'a', 'b', 'c', 'd', 'e', 'f',
|
||||
'Video', 'plex')
|
||||
for path in paths:
|
||||
new_path = path_ops.translate_path('special://thumbnails/%s' % path)
|
||||
path_ops.makedirs(path_ops.encode_path(new_path))
|
||||
with GetKodiDB('texture') as kodi_db:
|
||||
kodi_db.cursor.execute('SELECT tbl_name FROM sqlite_master WHERE type=?',
|
||||
('table', ))
|
||||
rows = kodi_db.cursor.fetchall()
|
||||
for row in rows:
|
||||
if row[0] != 'version':
|
||||
kodi_db.cursor.execute("DELETE FROM %s" % row[0])
|
||||
def remove_season(self, kodi_id):
|
||||
self.cursor.execute('DELETE FROM seasons WHERE idSeason = ?',
|
||||
(kodi_id,))
|
||||
|
||||
def remove_episode(self, kodi_id):
|
||||
self.cursor.execute('DELETE FROM episode WHERE idEpisode = ?',
|
||||
(kodi_id,))
|
||||
|
||||
def wipe_dbs(music=True):
|
||||
"""
|
||||
Completely resets the Kodi databases 'video', 'texture' and 'music' (if
|
||||
music sync is enabled)
|
||||
"""
|
||||
LOG.warn('Wiping Kodi databases!')
|
||||
kinds = ['video', 'texture']
|
||||
if music:
|
||||
kinds.append('music')
|
||||
for db in kinds:
|
||||
with GetKodiDB(db) as kodi_db:
|
||||
kodi_db.cursor.execute("SELECT name FROM sqlite_master WHERE type = 'table'")
|
||||
tables = kodi_db.cursor.fetchall()
|
||||
tables = [i[0] for i in tables]
|
||||
if 'version' in tables:
|
||||
tables.remove('version')
|
||||
if 'versiontagscan' in tables:
|
||||
tables.remove('versiontagscan')
|
||||
for table in tables:
|
||||
kodi_db.cursor.execute('DELETE FROM %s' % table)
|
||||
setup_kodi_default_entries()
|
||||
# Make sure Kodi knows we wiped the databases
|
||||
import xbmc
|
||||
xbmc.executebuiltin('UpdateLibrary(video)')
|
||||
if utils.settings('enableMusic') == 'true':
|
||||
xbmc.executebuiltin('UpdateLibrary(music)')
|
||||
def new_movie_id(self):
|
||||
self.cursor.execute('SELECT COALESCE(MAX(idMovie), 0) FROM movie')
|
||||
return self.cursor.fetchone()[0] + 1
|
||||
|
||||
def add_movie(self, *args):
|
||||
self.cursor.execute(
|
||||
'''
|
||||
INSERT OR REPLACE INTO movie(
|
||||
idMovie,
|
||||
idFile,
|
||||
c00,
|
||||
c01,
|
||||
c02,
|
||||
c03,
|
||||
c04,
|
||||
c05,
|
||||
c06,
|
||||
c07,
|
||||
c09,
|
||||
c10,
|
||||
c11,
|
||||
c12,
|
||||
c14,
|
||||
c15,
|
||||
c16,
|
||||
c18,
|
||||
c19,
|
||||
c21,
|
||||
c22,
|
||||
c23,
|
||||
premiered,
|
||||
userrating)
|
||||
VALUES
|
||||
(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,
|
||||
?, ?, ?, ?)
|
||||
''', (args))
|
||||
|
||||
KODIDB_FROM_PLEXTYPE = {
|
||||
v.PLEX_TYPE_MOVIE: GetKodiDB('video'),
|
||||
v.PLEX_TYPE_SHOW: GetKodiDB('video'),
|
||||
v.PLEX_TYPE_SEASON: GetKodiDB('video'),
|
||||
v.PLEX_TYPE_EPISODE: GetKodiDB('video'),
|
||||
v.PLEX_TYPE_ARTIST: GetKodiDB('music'),
|
||||
v.PLEX_TYPE_ALBUM: GetKodiDB('music'),
|
||||
v.PLEX_TYPE_SONG: GetKodiDB('music')
|
||||
}
|
||||
def remove_movie(self, kodi_id):
|
||||
self.cursor.execute('DELETE FROM movie WHERE idMovie = ?', (kodi_id,))
|
|
@ -12,7 +12,7 @@ import xbmc
|
|||
from xbmcgui import Window
|
||||
|
||||
from .plex_db import PlexDB
|
||||
from . import kodidb_functions as kodidb
|
||||
from . import kodi_db
|
||||
from . import utils
|
||||
from . import plex_functions as PF
|
||||
from .downloadutils import DownloadUtils as DU
|
||||
|
@ -302,7 +302,7 @@ class KodiMonitor(xbmc.Monitor):
|
|||
plex_type = None
|
||||
# If using direct paths and starting playback from a widget
|
||||
if not kodi_id and kodi_type and path:
|
||||
kodi_id, _ = kodidb.kodiid_from_filename(path, kodi_type)
|
||||
kodi_id, _ = kodi_db.kodiid_from_filename(path, kodi_type)
|
||||
if kodi_id:
|
||||
with PlexDB() as plexdb:
|
||||
db_item = plexdb.item_by_kodi_id(kodi_id, kodi_type)
|
||||
|
@ -559,8 +559,8 @@ def _record_playstate(status, ended):
|
|||
last_played = utils.unix_date_to_kodi(utils.unix_timestamp())
|
||||
if playcount is None:
|
||||
LOG.debug('playcount not found, looking it up in the Kodi DB')
|
||||
with kodidb.GetKodiDB('video') as kodi_db:
|
||||
playcount = kodi_db.get_playcount(db_item['kodi_fileid'])
|
||||
with kodi_db.KodiVideoDB() as kodidb:
|
||||
playcount = kodidb.get_playcount(db_item['kodi_fileid'])
|
||||
playcount = 0 if playcount is None else playcount
|
||||
if time < v.IGNORE_SECONDS_AT_START:
|
||||
LOG.debug('Ignoring playback less than %s seconds',
|
||||
|
@ -574,13 +574,13 @@ def _record_playstate(status, ended):
|
|||
v.MARK_PLAYED_AT)
|
||||
playcount += 1
|
||||
time = 0
|
||||
with kodidb.GetKodiDB('video') as kodi_db:
|
||||
kodi_db.set_resume(db_item['kodi_fileid'],
|
||||
time,
|
||||
totaltime,
|
||||
playcount,
|
||||
last_played,
|
||||
status['plex_type'])
|
||||
with kodi_db.KodiVideoDB() as kodidb:
|
||||
kodidb.set_resume(db_item['kodi_fileid'],
|
||||
time,
|
||||
totaltime,
|
||||
playcount,
|
||||
last_played,
|
||||
status['plex_type'])
|
||||
# Hack to force "in progress" widget to appear if it wasn't visible before
|
||||
if (state.FORCE_RELOAD_SKIN and
|
||||
xbmc.getCondVisibility('Window.IsVisible(Home.xml)')):
|
||||
|
@ -600,9 +600,9 @@ def _clean_file_table():
|
|||
"""
|
||||
LOG.debug('Start cleaning Kodi files table')
|
||||
xbmc.sleep(2000)
|
||||
with kodidb.GetKodiDB('video') as kodi_db_1:
|
||||
with kodidb.GetKodiDB('video') as kodi_db_2:
|
||||
for file_id in kodi_db_1.obsolete_file_ids():
|
||||
with kodi_db.KodiVideoDB() as kodidb_1:
|
||||
with kodi_db.KodiVideoDB() as kodidb_2:
|
||||
for file_id in kodidb_1.obsolete_file_ids():
|
||||
LOG.debug('Removing obsolete Kodi file_id %s', file_id)
|
||||
kodi_db_2.remove_file(file_id, remove_orphans=False)
|
||||
kodidb_2.remove_file(file_id, remove_orphans=False)
|
||||
LOG.debug('Done cleaning up Kodi file table')
|
||||
|
|
|
@ -6,7 +6,8 @@ import xbmc
|
|||
from . import common
|
||||
from ..plex_api import API
|
||||
from ..plex_db import PlexDB
|
||||
from .. import backgroundthread, utils, kodidb_functions as kodidb
|
||||
from ..kodi_db import KodiVideoDB
|
||||
from .. import backgroundthread, utils
|
||||
from .. import itemtypes, plex_functions as PF, variables as v, state
|
||||
|
||||
|
||||
|
@ -87,9 +88,9 @@ def process_fanart(plex_id, plex_type, refresh=False):
|
|||
LOG.error('Could not get Kodi id for plex id %s', plex_id)
|
||||
return
|
||||
if not refresh:
|
||||
with kodidb.GetKodiDB('video') as kodi_db:
|
||||
artworks = kodi_db.get_art(db_item['kodi_id'],
|
||||
db_item['kodi_type'])
|
||||
with KodiVideoDB() as kodidb:
|
||||
artworks = kodidb.get_art(db_item['kodi_id'],
|
||||
db_item['kodi_type'])
|
||||
# Check if we even need to get additional art
|
||||
for key in v.ALL_KODI_ARTWORK:
|
||||
if key not in artworks:
|
||||
|
@ -117,8 +118,8 @@ def process_fanart(plex_id, plex_type, refresh=False):
|
|||
if plex_type == v.PLEX_TYPE_MOVIE:
|
||||
for _, setname in api.collection_list():
|
||||
LOG.debug('Getting artwork for movie set %s', setname)
|
||||
with kodidb.GetKodiDB('video') as kodi_db:
|
||||
setid = kodi_db.create_collection(setname)
|
||||
with KodiVideoDB() as kodidb:
|
||||
setid = kodidb.create_collection(setname)
|
||||
external_set_artwork = api.set_artwork()
|
||||
if external_set_artwork and PREFER_KODI_COLLECTION_ART:
|
||||
kodi_artwork = api.artwork(kodi_id=setid,
|
||||
|
|
|
@ -7,7 +7,7 @@ import copy
|
|||
from . import common, videonodes
|
||||
from ..utils import cast
|
||||
from ..plex_db import PlexDB
|
||||
from .. import kodidb_functions as kodidb
|
||||
from .. import kodi_db
|
||||
from .. import itemtypes
|
||||
from .. import plex_functions as PF, music, utils, state, variables as v
|
||||
|
||||
|
@ -58,10 +58,10 @@ def sync_from_pms():
|
|||
# Backup old sections to delete them later, if needed (at the end
|
||||
# of this method, only unused sections will be left in old_sections)
|
||||
old_sections = list(plexdb.section_ids())
|
||||
with kodidb.GetKodiDB('video') as kodi_db:
|
||||
with kodi_db.KodiVideoDB() as kodidb:
|
||||
for section in sections:
|
||||
_process_section(section,
|
||||
kodi_db,
|
||||
kodidb,
|
||||
plexdb,
|
||||
sorted_sections,
|
||||
old_sections,
|
||||
|
@ -77,7 +77,7 @@ def sync_from_pms():
|
|||
return True
|
||||
|
||||
|
||||
def _process_section(section_xml, kodi_db, plexdb, sorted_sections,
|
||||
def _process_section(section_xml, kodidb, plexdb, sorted_sections,
|
||||
old_sections, totalnodes):
|
||||
folder = section_xml.attrib
|
||||
plex_type = folder['type']
|
||||
|
@ -101,7 +101,7 @@ def _process_section(section_xml, kodi_db, plexdb, sorted_sections,
|
|||
current_tagid = section[3]
|
||||
except TypeError:
|
||||
LOG.info('Creating section id: %s in Plex database.', section_id)
|
||||
tagid = kodi_db.create_tag(section_name)
|
||||
tagid = kodidb.create_tag(section_name)
|
||||
# Create playlist for the video library
|
||||
if (section_name not in playlists and
|
||||
plex_type in (v.PLEX_TYPE_MOVIE, v.PLEX_TYPE_SHOW)):
|
||||
|
@ -133,13 +133,13 @@ def _process_section(section_xml, kodi_db, plexdb, sorted_sections,
|
|||
if current_sectionname != section_name:
|
||||
LOG.info('section id: %s new sectionname: %s',
|
||||
section_id, section_name)
|
||||
tagid = kodi_db.create_tag(section_name)
|
||||
tagid = kodidb.create_tag(section_name)
|
||||
|
||||
# Update view with new info
|
||||
plexdb.add_section(section_id,
|
||||
section_name,
|
||||
plex_type,
|
||||
tagid)
|
||||
section_name,
|
||||
plex_type,
|
||||
tagid)
|
||||
|
||||
if plexdb.section_id_by_name(current_sectionname) is None:
|
||||
# The tag could be a combined view. Ensure there's
|
||||
|
@ -177,7 +177,7 @@ def _process_section(section_xml, kodi_db, plexdb, sorted_sections,
|
|||
# Update items with new tag
|
||||
for item in plexdb.kodi_id_by_section(section_id):
|
||||
# Remove the "s" from viewtype for tags
|
||||
kodi_db.update_tag(
|
||||
kodidb.update_tag(
|
||||
current_tagid, tagid, item[0], current_sectiontype[:-1])
|
||||
else:
|
||||
# Validate the playlist exists or recreate it
|
||||
|
@ -214,24 +214,25 @@ def delete_sections(old_sections):
|
|||
with PlexDB() as plexdb:
|
||||
old_sections = [plexdb.section(x) for x in old_sections]
|
||||
LOG.info("Removing entire Plex library sections: %s", old_sections)
|
||||
with kodidb.GetKodiDB() as kodi_db:
|
||||
with kodi_db.KodiVideoDB() as kodidb:
|
||||
for section in old_sections:
|
||||
if section[2] == v.KODI_TYPE_MOVIE:
|
||||
if section[2] == v.KODI_TYPE_PHOTO:
|
||||
# not synced
|
||||
plexdb.remove_section(section[0])
|
||||
elif section[2] == v.KODI_TYPE_MOVIE:
|
||||
video_library_update = True
|
||||
context = itemtypes.Movie(plexdb=plexdb,
|
||||
kodi_db=kodi_db)
|
||||
kodidb=kodidb)
|
||||
elif section[2] == v.KODI_TYPE_SHOW:
|
||||
video_library_update = True
|
||||
context = itemtypes.Show(plexdb=plexdb,
|
||||
kodi_db=kodi_db)
|
||||
elif section[2] == v.KODI_TYPE_ARTIST:
|
||||
kodidb=kodidb)
|
||||
with kodi_db.KodiMusicDB() as kodidb:
|
||||
for section in old_sections:
|
||||
if section[2] == v.KODI_TYPE_ARTIST:
|
||||
music_library_update = True
|
||||
context = itemtypes.Artist(plexdb=plexdb,
|
||||
kodi_db=kodi_db)
|
||||
elif section[2] == v.KODI_TYPE_PHOTO:
|
||||
# not synced
|
||||
plexdb.remove_section(section[0])
|
||||
continue
|
||||
kodidb=kodidb)
|
||||
for plex_id in plexdb.plexid_by_section(section[0]):
|
||||
context.remove(plex_id)
|
||||
# Only remove Plex entry if we've removed all items first
|
||||
|
|
|
@ -8,7 +8,7 @@ from .full_sync import PLAYLIST_SYNC_ENABLED
|
|||
from .fanart import SYNC_FANART, FanartTask
|
||||
from ..plex_api import API
|
||||
from ..plex_db import PlexDB
|
||||
from .. import kodidb_functions as kodidb
|
||||
from .. import kodi_db
|
||||
from .. import backgroundthread, playlists, plex_functions as PF, itemtypes
|
||||
from .. import artwork, utils, variables as v, state
|
||||
|
||||
|
@ -360,6 +360,6 @@ def cache_artwork(plex_id, plex_type, kodi_id=None, kodi_type=None):
|
|||
LOG.error('Could not retrieve Plex db info for %s', plex_id)
|
||||
return
|
||||
kodi_id, kodi_type = item['kodi_id'], item['kodi_type']
|
||||
with kodidb.KODIDB_FROM_PLEXTYPE[plex_type] as kodi_db:
|
||||
for url in kodi_db.art_urls(kodi_id, kodi_type):
|
||||
with kodi_db.KODIDB_FROM_PLEXTYPE[plex_type] as kodidb:
|
||||
for url in kodidb.art_urls(kodi_id, kodi_type):
|
||||
artwork.cache_url(url)
|
||||
|
|
|
@ -13,7 +13,7 @@ from .plex_db import PlexDB
|
|||
from . import plex_functions as PF
|
||||
from . import utils
|
||||
from .downloadutils import DownloadUtils as DU
|
||||
from . import kodidb_functions as kodidb
|
||||
from .kodi_db import KodiVideoDB
|
||||
from . import playlist_func as PL
|
||||
from . import playqueue as PQ
|
||||
from . import json_rpc as js
|
||||
|
@ -429,8 +429,8 @@ def _conclude_playback(playqueue, pos):
|
|||
with PlexDB() as plexdb:
|
||||
db_item = plexdb.item_by_id(item.plex_id, item.plex_type)
|
||||
file_id = db_item['kodi_fileid'] if db_item else None
|
||||
with kodidb.GetKodiDB('video') as kodi_db:
|
||||
item.offset = kodi_db.get_resume(file_id)
|
||||
with KodiVideoDB() as kodidb:
|
||||
item.offset = kodidb.get_resume(file_id)
|
||||
LOG.info('Resuming playback at %s', item.offset)
|
||||
if v.KODIVERSION >= 18 and api:
|
||||
# Kodi 18 Alpha 3 broke StartOffset
|
||||
|
|
|
@ -5,11 +5,11 @@ from logging import getLogger
|
|||
from threading import Thread
|
||||
from urlparse import parse_qsl
|
||||
|
||||
from .kodi_db import KodiVideoDB
|
||||
from . import playback
|
||||
from . import context_entry
|
||||
from . import json_rpc as js
|
||||
from . import pickler
|
||||
from . import kodidb_functions as kodidb
|
||||
from . import state
|
||||
|
||||
###############################################################################
|
||||
|
@ -47,8 +47,8 @@ class PlaybackStarter(Thread):
|
|||
resolve=resolve)
|
||||
elif mode == 'navigation':
|
||||
# e.g. when plugin://...tvshows is called for entire season
|
||||
with kodidb.GetKodiDB('video') as kodi_db:
|
||||
show_id = kodi_db.show_id_from_path(params.get('path'))
|
||||
with KodiVideoDB() as kodidb:
|
||||
show_id = kodidb.show_id_from_path(params.get('path'))
|
||||
if show_id:
|
||||
js.activate_window('videos',
|
||||
'videodb://tvshows/titles/%s' % show_id)
|
||||
|
|
|
@ -11,7 +11,7 @@ from urlparse import parse_qsl, urlsplit
|
|||
from .plex_api import API
|
||||
from .plex_db import PlexDB
|
||||
from . import plex_functions as PF
|
||||
from . import kodidb_functions as kodidb
|
||||
from .kodi_db import kodiid_from_filename
|
||||
from .downloadutils import DownloadUtils as DU
|
||||
from . import utils
|
||||
from . import json_rpc as js
|
||||
|
@ -360,8 +360,8 @@ def verify_kodi_item(plex_id, kodi_item):
|
|||
if (not state.DIRECT_PATHS and state.ENABLE_MUSIC and
|
||||
kodi_item.get('type') == v.KODI_TYPE_SONG and
|
||||
kodi_item['file'].startswith('http')):
|
||||
kodi_item['id'], _ = kodidb.kodiid_from_filename(kodi_item['file'],
|
||||
v.KODI_TYPE_SONG)
|
||||
kodi_item['id'], _ = kodiid_from_filename(kodi_item['file'],
|
||||
v.KODI_TYPE_SONG)
|
||||
LOG.debug('Detected song. Research results: %s', kodi_item)
|
||||
return kodi_item
|
||||
# Need more info since we don't have kodi_id nor type. Use file path.
|
||||
|
@ -372,16 +372,16 @@ def verify_kodi_item(plex_id, kodi_item):
|
|||
raise PlaylistError
|
||||
LOG.debug('Starting research for Kodi id since we didnt get one: %s',
|
||||
kodi_item)
|
||||
kodi_id, _ = kodidb.kodiid_from_filename(kodi_item['file'],
|
||||
v.KODI_TYPE_MOVIE)
|
||||
kodi_id, _ = kodiid_from_filename(kodi_item['file'],
|
||||
v.KODI_TYPE_MOVIE)
|
||||
kodi_item['type'] = v.KODI_TYPE_MOVIE
|
||||
if kodi_id is None:
|
||||
kodi_id, _ = kodidb.kodiid_from_filename(kodi_item['file'],
|
||||
v.KODI_TYPE_EPISODE)
|
||||
kodi_id, _ = kodiid_from_filename(kodi_item['file'],
|
||||
v.KODI_TYPE_EPISODE)
|
||||
kodi_item['type'] = v.KODI_TYPE_EPISODE
|
||||
if kodi_id is None:
|
||||
kodi_id, _ = kodidb.kodiid_from_filename(kodi_item['file'],
|
||||
v.KODI_TYPE_SONG)
|
||||
kodi_id, _ = kodiid_from_filename(kodi_item['file'],
|
||||
v.KODI_TYPE_SONG)
|
||||
kodi_item['type'] = v.KODI_TYPE_SONG
|
||||
kodi_item['id'] = kodi_id
|
||||
kodi_item['type'] = None if kodi_id is None else kodi_item['type']
|
||||
|
|
|
@ -9,7 +9,7 @@ from logging import getLogger
|
|||
|
||||
from .common import Playlist, PlaylistError
|
||||
from ..plex_db import PlexDB
|
||||
from .. import kodidb_functions as kodidb
|
||||
from ..kodi_db import kodiid_from_filename
|
||||
from .. import path_ops, utils, variables as v
|
||||
###############################################################################
|
||||
LOG = getLogger('PLEX.playlists.db')
|
||||
|
@ -88,8 +88,8 @@ def m3u_to_plex_ids(playlist):
|
|||
plex_ids.append(plex_id)
|
||||
else:
|
||||
# Add-on paths not working, try direct
|
||||
kodi_id, kodi_type = kodidb.kodiid_from_filename(
|
||||
entry, db_type=playlist.kodi_type)
|
||||
kodi_id, kodi_type = kodiid_from_filename(entry,
|
||||
db_type=playlist.kodi_type)
|
||||
if not kodi_id:
|
||||
continue
|
||||
with PlexDB() as plexdb:
|
||||
|
|
|
@ -38,13 +38,13 @@ from urlparse import parse_qsl
|
|||
from xbmcgui import ListItem
|
||||
|
||||
from .plex_db import PlexDB
|
||||
from .kodi_db import KodiVideoDB, KodiMusicDB
|
||||
from .utils import cast
|
||||
from .downloadutils import DownloadUtils as DU
|
||||
from . import clientinfo
|
||||
from . import utils
|
||||
from . import path_ops
|
||||
from . import plex_functions as PF
|
||||
from . import kodidb_functions as kodidb
|
||||
from . import variables as v
|
||||
from . import state
|
||||
|
||||
|
@ -939,13 +939,13 @@ class API(object):
|
|||
else:
|
||||
return artworks
|
||||
# Grab artwork from the season
|
||||
with kodidb.GetKodiDB('video') as kodi_db:
|
||||
season_art = kodi_db.get_art(season_id, v.KODI_TYPE_SEASON)
|
||||
with KodiVideoDB() as kodidb:
|
||||
season_art = kodidb.get_art(season_id, v.KODI_TYPE_SEASON)
|
||||
for kodi_art in season_art:
|
||||
artworks['season.%s' % kodi_art] = season_art[kodi_art]
|
||||
# Grab more artwork from the show
|
||||
with kodidb.GetKodiDB('video') as kodi_db:
|
||||
show_art = kodi_db.get_art(show_id, v.KODI_TYPE_SHOW)
|
||||
with KodiVideoDB() as kodidb:
|
||||
show_art = kodidb.get_art(show_id, v.KODI_TYPE_SHOW)
|
||||
for kodi_art in show_art:
|
||||
artworks['tvshow.%s' % kodi_art] = show_art[kodi_art]
|
||||
return artworks
|
||||
|
@ -953,11 +953,11 @@ class API(object):
|
|||
if kodi_id:
|
||||
# in Kodi database, potentially with additional e.g. clearart
|
||||
if self.plex_type() in v.PLEX_VIDEOTYPES:
|
||||
with kodidb.GetKodiDB('video') as kodi_db:
|
||||
return kodi_db.get_art(kodi_id, kodi_type)
|
||||
with KodiVideoDB() as kodidb:
|
||||
return kodidb.get_art(kodi_id, kodi_type)
|
||||
else:
|
||||
with kodidb.GetKodiDB('music') as kodi_db:
|
||||
return kodi_db.get_art(kodi_id, kodi_type)
|
||||
with KodiMusicDB() as kodidb:
|
||||
return kodidb.get_art(kodi_id, kodi_type)
|
||||
|
||||
# Grab artwork from Plex
|
||||
# if self.plex_type() == v.PLEX_TYPE_EPISODE:
|
||||
|
|
|
@ -7,7 +7,7 @@ import xbmc
|
|||
from .downloadutils import DownloadUtils as DU
|
||||
from . import library_sync
|
||||
from . import backgroundthread, utils, path_ops, artwork, variables as v, state
|
||||
from . import plex_db, kodidb_functions as kodidb
|
||||
from . import plex_db, kodi_db
|
||||
|
||||
LOG = getLogger('PLEX.sync')
|
||||
|
||||
|
@ -118,7 +118,7 @@ class Sync(backgroundthread.KillableThread):
|
|||
return
|
||||
# ask to reset all existing or not
|
||||
if utils.yesno_dialog('Image Texture Cache', utils.lang(39251)):
|
||||
kodidb.reset_cached_images()
|
||||
kodi_db.reset_cached_images()
|
||||
self.start_image_cache_thread()
|
||||
|
||||
def on_library_scan_finished(self, successful):
|
||||
|
@ -236,9 +236,9 @@ class Sync(backgroundthread.KillableThread):
|
|||
plex_db.initialize()
|
||||
# Hack to speed up look-ups for actors (giant table!)
|
||||
utils.create_kodi_db_indicees()
|
||||
with kodidb.GetKodiDB('video') as kodi_db:
|
||||
with kodi_db.KodiVideoDB() as kodidb:
|
||||
# Setup the paths for addon-paths (even when using direct paths)
|
||||
kodi_db.setup_path_table()
|
||||
kodidb.setup_path_table()
|
||||
|
||||
while not self.isCanceled():
|
||||
# In the event the server goes offline
|
||||
|
|
|
@ -526,8 +526,7 @@ def wipe_database():
|
|||
delete_playlists()
|
||||
# Clean up the video nodes
|
||||
delete_nodes()
|
||||
from . import kodidb_functions
|
||||
from . import plex_db
|
||||
from . import kodi_db, plex_db
|
||||
# First get the paths to all synced playlists
|
||||
playlist_paths = []
|
||||
try:
|
||||
|
@ -545,7 +544,7 @@ def wipe_database():
|
|||
# Plex DB completely empty yet. Wipe existing Kodi music only if we
|
||||
# expect to sync Plex music
|
||||
music = settings('enableMusic') == 'true'
|
||||
kodidb_functions.wipe_dbs(music)
|
||||
kodi_db.wipe_dbs(music)
|
||||
plex_db.wipe()
|
||||
plex_db.initialize()
|
||||
# Delete all synced playlists
|
||||
|
@ -558,7 +557,7 @@ def wipe_database():
|
|||
|
||||
LOG.info("Resetting all cached artwork.")
|
||||
# Remove all cached artwork
|
||||
kodidb_functions.reset_cached_images()
|
||||
kodi_db.reset_cached_images()
|
||||
# reset the install run flag
|
||||
settings('SyncInstallRunDone', value="false")
|
||||
LOG.info('Wiping done')
|
||||
|
|
Loading…
Reference in a new issue