PlexKodiConnect/resources/lib/kodidb_functions.py

1244 lines
50 KiB
Python
Raw Normal View History

#!/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
2017-12-10 00:35:08 +11:00
from logging import getLogger
from sqlite3 import IntegrityError
from . import artwork, utils, variables as v, state, path_ops
2016-08-31 00:43:56 +10:00
###############################################################################
2018-06-22 03:24:37 +10:00
LOG = getLogger('PLEX.kodidb_functions')
2018-02-25 23:42:20 +11:00
class GetKodiDB(object):
2016-02-12 00:03:04 +11:00
"""
2017-01-29 23:06:09 +11:00
Usage: with GetKodiDB(db_type) as kodi_db:
2016-02-12 00:03:04 +11:00
do stuff with kodi_db
Parameters:
2017-01-29 23:06:09 +11:00
db_type: DB to open: 'video', 'music', 'plex', 'texture'
2016-02-12 00:03:04 +11:00
On exiting "with" (no matter what), commits get automatically committed
and the db gets closed
"""
2017-01-29 23:06:09 +11:00
def __init__(self, db_type):
2018-02-25 23:42:20 +11:00
self.kodiconn = None
2017-01-29 23:06:09 +11:00
self.db_type = db_type
2016-02-12 00:03:04 +11:00
def __enter__(self):
2018-06-22 03:24:37 +10:00
self.kodiconn = utils.kodi_sql(self.db_type)
2018-02-25 23:42:20 +11:00
kodi_db = KodiDBMethods(self.kodiconn.cursor())
2017-01-09 01:03:41 +11:00
return kodi_db
2016-02-12 00:03:04 +11:00
2018-02-25 23:42:20 +11:00
def __exit__(self, typus, value, traceback):
2016-02-12 00:03:04 +11:00
self.kodiconn.commit()
self.kodiconn.close()
2018-02-25 23:42:20 +11:00
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
2016-08-31 00:43:56 +10:00
2018-02-20 20:19:11 +11:00
def setup_path_table(self):
"""
Use with Kodi video DB
Sets strContent to e.g. 'movies' and strScraper to metadata.local
For some reason, Kodi ignores this if done via itemtypes while e.g.
adding or updating items. (addPath method does NOT work)
"""
2018-03-11 00:51:00 +11:00
path_id = self.get_path('plugin://%s.movies/' % v.ADDON_ID)
if path_id is None:
self.cursor.execute("select coalesce(max(idPath),0) from path")
path_id = self.cursor.fetchone()[0] + 1
query = '''
INSERT INTO path(idPath,
strPath,
strContent,
strScraper,
noUpdate,
exclude)
2018-02-24 03:22:57 +11:00
VALUES (?, ?, ?, ?, ?, ?)
'''
self.cursor.execute(query, (path_id,
'plugin://%s.movies/' % v.ADDON_ID,
'movies',
'metadata.local',
1,
2018-02-24 03:22:57 +11:00
0))
2018-02-20 20:19:11 +11:00
# And TV shows
2018-03-11 00:51:00 +11:00
path_id = self.get_path('plugin://%s.tvshows/' % v.ADDON_ID)
if path_id is None:
self.cursor.execute("select coalesce(max(idPath),0) from path")
path_id = self.cursor.fetchone()[0] + 1
query = '''
INSERT INTO path(idPath,
strPath,
strContent,
strScraper,
noUpdate,
exclude)
2018-02-24 03:22:57 +11:00
VALUES (?, ?, ?, ?, ?, ?)
'''
self.cursor.execute(query, (path_id,
'plugin://%s.tvshows/' % v.ADDON_ID,
'tvshows',
'metadata.local',
1,
2018-02-24 03:22:57 +11:00
0))
2018-03-11 01:44:08 +11:00
def parent_path_id(self, path):
"""
2018-03-11 01:44:08 +11:00
Video DB: Adds all subdirectories to path table while setting a "trail"
of parent path ids
"""
parentpath = path_ops.path.abspath(
path_ops.path.join(path,
path_ops.decode_path(path_ops.path.pardir)))
2018-03-11 00:51:00 +11:00
pathid = self.get_path(parentpath)
if pathid is None:
2018-03-05 01:29:45 +11:00
self.cursor.execute("SELECT COALESCE(MAX(idPath),0) FROM path")
pathid = self.cursor.fetchone()[0] + 1
2018-06-22 03:24:37 +10:00
datetime = utils.unix_date_to_kodi(utils.unix_timestamp())
2018-11-09 01:15:52 +11:00
self.cursor.execute('''
INSERT INTO path(idPath, strPath, dateAdded)
VALUES (?, ?, ?)
''',
(pathid, parentpath, datetime))
if parentpath != path:
# In case we end up having media in the filesystem root, C:\
parent_id = self.parent_path_id(parentpath)
2018-11-09 01:15:52 +11:00
self.cursor.execute('UPDATE path SET idParentPath = ? WHERE idPath = ?',
(parent_id, pathid))
return pathid
2018-03-11 00:51:00 +11:00
def add_video_path(self, path, date_added=None, id_parent_path=None,
content=None, scraper=None):
"""
Returns the idPath from the path table. Creates a new entry if path
[unicode] does not yet exist (using date_added [kodi date type],
id_parent_path [int], content ['tvshows', 'movies', None], scraper
[usually 'metadata.local'])
WILL activate noUpdate for the path!
"""
2018-11-09 01:15:52 +11:00
path = '' if path is None else path
self.cursor.execute('SELECT idPath FROM path WHERE strPath = ? LIMIT 1',
(path, ))
try:
pathid = self.cursor.fetchone()[0]
except TypeError:
2018-03-05 01:29:45 +11:00
self.cursor.execute("SELECT COALESCE(MAX(idPath),0) FROM path")
pathid = self.cursor.fetchone()[0] + 1
2018-11-09 01:15:52 +11:00
self.cursor.execute('''
INSERT INTO path(
idPath,
strPath,
dateAdded,
idParentPath,
strContent,
strScraper,
noUpdate)
VALUES (?, ?, ?, ?, ?, ?, ?)
''',
2018-03-11 00:51:00 +11:00
(pathid, path, date_added, id_parent_path,
content, scraper, 1))
2018-03-05 01:29:45 +11:00
return pathid
2018-06-15 23:15:35 +10:00
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
"""
2018-03-05 01:29:45 +11:00
# SQL won't return existing paths otherwise
2018-11-09 01:15:52 +11:00
path = '' if path is None else path
self.cursor.execute('SELECT idPath FROM path WHERE strPath = ?',
(path,))
2018-03-05 01:29:45 +11:00
try:
pathid = self.cursor.fetchone()[0]
except TypeError:
self.cursor.execute("SELECT COALESCE(MAX(idPath),0) FROM path")
pathid = self.cursor.fetchone()[0] + 1
2018-11-09 01:15:52 +11:00
self.cursor.execute('''
INSERT INTO path(idPath, strPath, strHash)
VALUES (?, ?, ?)
''',
(pathid, path, hash_string))
return pathid
2018-03-11 00:51:00 +11:00
def get_path(self, path):
"""
Returns the idPath from the path table for path [unicode] or None
"""
self.cursor.execute('SELECT idPath FROM path WHERE strPath = ?',
2018-11-09 01:15:52 +11:00
(path, ))
try:
2018-11-09 01:15:52 +11:00
return self.cursor.fetchone()[0]
except TypeError:
2018-11-09 01:15:52 +11:00
pass
2018-03-11 03:09:21 +11:00
def add_file(self, filename, path_id, date_added):
2018-03-11 01:44:08 +11:00
"""
Adds the filename [unicode] to the table files if not already added
and returns the idFile.
"""
2018-11-07 23:37:37 +11:00
self.cursor.execute('SELECT idFile FROM files WHERE idPath = ? AND strFilename = ?',
(path_id, filename))
try:
2018-03-11 03:09:21 +11:00
file_id = self.cursor.fetchone()[0]
except TypeError:
2018-03-11 01:44:08 +11:00
self.cursor.execute('SELECT COALESCE(MAX(idFile), 0) FROM files')
2018-03-11 03:09:21 +11:00
file_id = self.cursor.fetchone()[0] + 1
2018-11-07 23:37:37 +11:00
self.cursor.execute('''
INSERT INTO files(
idFile, idPath, strFilename, dateAdded)
VALUES (?, ?, ?, ?)
''',
2018-06-22 03:24:37 +10:00
(file_id, path_id, filename, date_added))
2018-03-11 03:09:21 +11:00
return file_id
def obsolete_file_ids(self):
"""
2018-11-09 01:15:52 +11:00
Returns a generator for idFile of all Kodi file ids that do not have a
dateAdded set (dateAdded NULL) and the filename start with
'plugin://plugin.video.plexkodiconnect'
These entries should be deleted as they're created falsely by Kodi.
"""
2018-11-09 01:15:52 +11:00
return (x[0] for x in self.cursor.execute('''
SELECT idFile FROM files
WHERE dateAdded IS NULL
AND strFilename LIKE \'plugin://plugin.video.plexkodiconnect%\'
2018-11-09 01:15:52 +11:00
'''))
def show_id_from_path(self, path):
"""
Returns the idShow for path [unicode] or None
"""
self.cursor.execute('SELECT idPath FROM path WHERE strPath = ? LIMIT 1',
(path, ))
try:
path_id = self.cursor.fetchone()[0]
except TypeError:
return
2018-11-09 01:15:52 +11:00
self.cursor.execute('SELECT idShow FROM tvshowlinkpath WHERE idPath = ? LIMIT 1',
(path_id, ))
try:
2018-11-09 01:15:52 +11:00
return self.cursor.fetchone()[0]
except TypeError:
2018-11-09 01:15:52 +11:00
pass
def remove_file(self, file_id, remove_orphans=True, plex_type=None):
2018-03-11 03:09:21 +11:00
"""
Removes the entry for file_id from the files table. Will also delete
entries from the associated tables: bookmark, settings, streamdetails.
If remove_orphans is true, this method will delete any orphaned path
entries in the Kodi path table
Passing plex_type = v.PLEX_TYPE_EPISODE deletes any secondary files for
add-on paths
2018-03-11 03:09:21 +11:00
"""
if not state.DIRECT_PATHS and plex_type == v.PLEX_TYPE_EPISODE:
# Hack for the 2 entries for episodes for addon paths
2018-11-09 01:15:52 +11:00
self.cursor.execute('SELECT strFilename FROM files WHERE idFile = ? LIMIT 1',
(file_id, ))
filename = self.cursor.fetchone()
if not filename:
LOG.error('Could not find file_id %s', file_id)
return
2018-11-09 01:15:52 +11:00
for new_id in self.cursor.execute('SELECT idFile FROM files WHERE strFilename = ? LIMIT 2',
(filename[0], )):
self.remove_file(new_id[0], remove_orphans=remove_orphans)
return
self.cursor.execute('SELECT idPath FROM files WHERE idFile = ? LIMIT 1',
(file_id,))
try:
path_id = self.cursor.fetchone()[0]
except TypeError:
return
2018-03-11 03:09:21 +11:00
self.cursor.execute('DELETE FROM files WHERE idFile = ?',
(file_id,))
self.cursor.execute('DELETE FROM bookmark WHERE idFile = ?',
(file_id,))
self.cursor.execute('DELETE FROM settings WHERE idFile = ?',
(file_id,))
self.cursor.execute('DELETE FROM streamdetails WHERE idFile = ?',
(file_id,))
self.cursor.execute('DELETE FROM stacktimes WHERE idFile = ?',
(file_id,))
if remove_orphans:
# Delete orphaned path entry
2018-11-09 01:15:52 +11:00
self.cursor.execute('SELECT idFile FROM files WHERE idPath = ? LIMIT 1',
(path_id,))
if self.cursor.fetchone() is None:
self.cursor.execute('DELETE FROM path WHERE idPath = ?',
(path_id,))
2018-02-28 07:14:42 +11:00
def _modify_link_and_table(self, kodi_id, kodi_type, entries, link_table,
table, key, first_id=None):
first_id = first_id if first_id is not None else 1
2018-02-28 07:14:42 +11:00
entry_ids = []
for entry in entries:
2018-11-09 01:15:52 +11:00
self.cursor.execute('''
SELECT %s FROM %s WHERE name = ? COLLATE NOCASE LIMIT 1
''' % (key, table), (entry, ))
2018-02-28 07:14:42 +11:00
try:
entry_id = self.cursor.fetchone()[0]
except TypeError:
2018-11-09 01:15:52 +11:00
self.cursor.execute('SELECT COALESCE(MAX(%s), %s) FROM %s'
% (key, first_id - 1, table))
2018-02-28 07:14:42 +11:00
entry_id = self.cursor.fetchone()[0] + 1
2018-11-09 01:15:52 +11:00
self.cursor.execute('INSERT INTO %s(%s, name) values(?, ?)'
% (table, key), (entry_id, entry))
2018-02-28 07:14:42 +11:00
finally:
entry_ids.append(entry_id)
# Now process the ids obtained from the names
# Get the existing, old entries
outdated_entries = []
2018-11-09 01:15:52 +11:00
for entry_id in self.cursor.execute('SELECT %s FROM %s WHERE media_id = ? AND media_type = ?'
% (key, link_table), (kodi_id, kodi_type)):
2018-02-28 07:14:42 +11:00
try:
2018-02-28 23:45:08 +11:00
entry_ids.remove(entry_id[0])
2018-02-28 07:14:42 +11:00
except ValueError:
2018-02-28 23:45:08 +11:00
outdated_entries.append(entry_id[0])
2018-02-28 07:14:42 +11:00
# Add all new entries that haven't already been added
for entry_id in entry_ids:
try:
2018-11-09 01:15:52 +11:00
self.cursor.execute('INSERT INTO %s VALUES (?, ?, ?)' % link_table,
(entry_id, kodi_id, kodi_type))
except IntegrityError:
LOG.info('IntegrityError: skipping entry %s for table %s',
entry_id, link_table)
2018-02-28 07:14:42 +11:00
# Delete all outdated references in the link table. Also check whether
# we need to delete orphaned entries in the master table
for entry_id in outdated_entries:
2018-11-09 01:15:52 +11:00
self.cursor.execute('''
DELETE FROM %s WHERE %s = ? AND media_id = ? AND media_type = ?
''' % (link_table, key), (entry_id, kodi_id, kodi_type))
self.cursor.execute('SELECT %s FROM %s WHERE %s = ?' % (key, link_table, key),
(entry_id, ))
2018-02-28 07:14:42 +11:00
if self.cursor.fetchone() is None:
# Delete in the original table because entry is now orphaned
2018-11-09 01:15:52 +11:00
self.cursor.execute('DELETE FROM %s WHERE %s = ?' % (table, key),
(entry_id, ))
2018-02-28 07:14:42 +11:00
def modify_countries(self, kodi_id, kodi_type, countries=None):
2018-02-28 07:14:42 +11:00
"""
Writes a country (string) in the list countries into the Kodi DB. Will
also delete any orphaned country entries.
"""
self._modify_link_and_table(kodi_id,
kodi_type,
2018-11-09 01:15:52 +11:00
countries if countries else [],
2018-02-28 07:14:42 +11:00
'country_link',
'country',
'country_id')
def modify_genres(self, kodi_id, kodi_type, genres=None):
2018-02-28 07:14:42 +11:00
"""
Writes a country (string) in the list countries into the Kodi DB. Will
also delete any orphaned country entries.
"""
self._modify_link_and_table(kodi_id,
kodi_type,
2018-11-09 01:15:52 +11:00
genres if genres else [],
2018-02-28 07:14:42 +11:00
'genre_link',
'genre',
'genre_id')
def modify_studios(self, kodi_id, kodi_type, studios=None):
2018-02-28 07:14:42 +11:00
"""
Writes a country (string) in the list countries into the Kodi DB. Will
also delete any orphaned country entries.
"""
self._modify_link_and_table(kodi_id,
kodi_type,
2018-11-09 01:15:52 +11:00
studios if studios else [],
2018-02-28 07:14:42 +11:00
'studio_link',
'studio',
'studio_id')
def modify_tags(self, kodi_id, kodi_type, tags=None):
2018-02-28 07:14:42 +11:00
"""
Writes a country (string) in the list countries into the Kodi DB. Will
also delete any orphaned country entries.
"""
self._modify_link_and_table(kodi_id,
kodi_type,
2018-11-09 01:15:52 +11:00
tags if tags else [],
2018-02-28 07:14:42 +11:00
'tag_link',
'tag',
'tag_id')
def modify_people(self, kodi_id, kodi_type, people=None):
"""
Makes sure that actors, directors and writers are recorded correctly
for the elmement kodi_id, kodi_type.
Will also delete a freshly orphaned actor entry.
"""
2018-11-09 01:15:52 +11:00
for kind, people_list in (people if people else
{'actor': [],
'director': [],
'writer': []}).iteritems():
self._modify_people_kind(kodi_id, kodi_type, kind, people_list)
def _modify_people_kind(self, kodi_id, kodi_type, kind, people_list):
# Get the people already saved in the DB for this specific item
if kind == 'actor':
2016-12-21 02:13:19 +11:00
query = '''
SELECT actor.actor_id, actor.name, art.url, actor_link.role,
actor_link.cast_order
FROM actor_link
LEFT JOIN actor ON actor.actor_id = actor_link.actor_id
LEFT JOIN art ON (art.media_id = actor_link.actor_id AND
art.media_type = 'actor')
WHERE actor_link.media_id = ? AND actor_link.media_type = ?
2016-12-21 02:13:19 +11:00
'''
else:
2016-12-21 02:13:19 +11:00
query = '''
SELECT actor.actor_id, actor.name
FROM {0}_link
LEFT JOIN actor ON actor.actor_id = {0}_link.actor_id
WHERE {0}_link.media_id = ? AND {0}_link.media_type = ?
'''.format(kind)
2018-02-26 03:45:38 +11:00
self.cursor.execute(query, (kodi_id, kodi_type))
old_people = self.cursor.fetchall()
# Determine which people we need to save or delete
outdated_people = []
for person in old_people:
try:
people_list.remove(person[1:])
except ValueError:
outdated_people.append(person)
# Get rid of old entries
2018-02-26 03:45:38 +11:00
query = '''
DELETE FROM %s_link
WHERE actor_id = ? AND media_id = ? AND media_type = ?
''' % kind
query_actor_check = 'SELECT actor_id FROM %s_link WHERE actor_id = ?'
query_actor_delete = 'DELETE FROM actor WHERE actor_id = ?'
for person in outdated_people:
# Delete the outdated entry
self.cursor.execute(query, (person[0], kodi_id, kodi_type))
# Do we now have orphaned entries?
for person_kind in ('actor', 'writer', 'director'):
self.cursor.execute(query_actor_check % person_kind,
(person[0],))
if self.cursor.fetchone() is not None:
break
else:
# person entry in actor table is now orphaned
# Delete the person from actor table
self.cursor.execute(query_actor_delete, (person[0],))
if kind == 'actor':
# Delete any associated artwork
2018-11-06 04:00:01 +11:00
artwork.delete_artwork(person[0], 'actor', self.cursor)
# Save new people to Kodi DB by iterating over the remaining entries
if kind == 'actor':
query = 'INSERT INTO actor_link VALUES (?, ?, ?, ?, ?)'
for person in people_list:
# Make sure the person entry in table actor exists
actor_id = self._get_actor_id(person[0], art_url=person[1])
# Link the person with the media element
try:
self.cursor.execute(query, (actor_id, kodi_id, kodi_type,
person[2], person[3]))
except IntegrityError:
# With Kodi, an actor may have only one role, unlike Plex
pass
else:
query = 'INSERT INTO %s_link VALUES (?, ?, ?)' % kind
for person in people_list:
# Make sure the person entry in table actor exists:
actor_id = self._get_actor_id(person[0])
# Link the person with the media element
try:
self.cursor.execute(query, (actor_id, kodi_id, kodi_type))
except IntegrityError:
# Again, Kodi may have only one person assigned to a role
pass
def _get_actor_id(self, name, art_url=None):
"""
Returns the actor_id [int] for name [unicode] in table actor (without
ensuring that the name matches).
If not, will create a new record with actor_id, name, art_url
Uses Plex ids and thus assumes that Plex person id is unique!
"""
self.cursor.execute('SELECT actor_id FROM actor WHERE name=? LIMIT 1',
(name,))
try:
2018-11-09 01:15:52 +11:00
return self.cursor.fetchone()[0]
except TypeError:
# Not yet in actor DB, add person
self.cursor.execute('SELECT COALESCE(MAX(actor_id),0) FROM actor')
actor_id = self.cursor.fetchone()[0] + 1
self.cursor.execute('INSERT INTO actor(actor_id, name) '
'VALUES (?, ?)',
(actor_id, name))
if art_url:
2018-11-06 04:00:01 +11:00
artwork.modify_art(art_url,
actor_id,
'actor',
'thumb',
self.cursor)
2018-11-09 01:15:52 +11:00
return actor_id
2018-02-26 03:45:38 +11:00
2018-03-04 00:40:12 +11:00
def get_art(self, kodi_id, kodi_type):
"""
Returns a dict of all available artwork with unicode urls/paths:
{
'thumb'
'poster'
'banner'
'clearart'
'clearlogo'
2018-03-05 00:12:43 +11:00
'discart'
'fanart' and also potentially more fanart 'fanart1', 'fanart2',
2018-03-04 00:40:12 +11:00
}
2018-03-05 00:12:43 +11:00
Missing fanart will not appear in the dict. 'landscape' and 'icon'
might be implemented in the future.
2018-03-04 00:40:12 +11:00
"""
2018-11-09 01:15:52 +11:00
self.cursor.execute('SELECT type, url FROM art WHERE media_id=? AND media_type=?',
(kodi_id, kodi_type))
2018-03-04 00:40:12 +11:00
return dict(self.cursor.fetchall())
2018-02-26 19:18:44 +11:00
def modify_streams(self, fileid, streamdetails=None, runtime=None):
"""
Leave streamdetails and runtime empty to delete all stream entries for
fileid
"""
# First remove any existing entries
self.cursor.execute('DELETE FROM streamdetails WHERE idFile = ?',
(fileid,))
if not streamdetails:
return
for videotrack in streamdetails['video']:
2018-11-09 01:15:52 +11:00
self.cursor.execute('''
INSERT INTO streamdetails(
idFile, iStreamType, strVideoCodec, fVideoAspect,
iVideoWidth, iVideoHeight, iVideoDuration ,strStereoMode)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
2018-11-09 01:15:52 +11:00
''', (fileid, 0, videotrack['codec'],
videotrack['aspect'], videotrack['width'],
videotrack['height'], runtime,
videotrack['video3DFormat']))
for audiotrack in streamdetails['audio']:
2018-11-09 01:15:52 +11:00
self.cursor.execute('''
INSERT INTO streamdetails(
idFile, iStreamType, strAudioCodec, iAudioChannels,
strAudioLanguage)
VALUES (?, ?, ?, ?, ?)
2018-11-09 01:15:52 +11:00
''', (fileid, 1, audiotrack['codec'],
audiotrack['channels'],
audiotrack['language']))
for subtitletrack in streamdetails['subtitle']:
2018-11-09 01:15:52 +11:00
self.cursor.execute('''
INSERT INTO streamdetails(idFile, iStreamType,
strSubtitleLanguage)
VALUES (?, ?, ?)
2018-11-09 01:15:52 +11:00
''', (fileid, 2, subtitletrack))
2016-03-12 00:42:14 +11:00
2017-12-14 06:14:27 +11:00
def video_id_from_filename(self, filename, path):
2016-03-23 02:17:06 +11:00
"""
Returns the tuple (itemId, type) where
itemId: Kodi DB unique Id for either movie or episode
type: either 'movie' or 'episode'
Returns None if not found OR if too many entries were found
2016-03-23 02:17:06 +11:00
"""
2018-11-09 01:15:52 +11:00
self.cursor.execute('SELECT idFile, idPath FROM files WHERE strFilename = ?',
(filename,))
files = self.cursor.fetchall()
if len(files) == 0:
2018-02-25 23:37:30 +11:00
LOG.info('Did not find any file, abort')
return
# result will contain a list of all idFile with matching filename and
# matching path
result = []
for file in files:
# Use idPath to get path as a string
2018-11-09 01:15:52 +11:00
self.cursor.execute('SELECT strPath FROM path WHERE idPath = ?',
(file[1], ))
2016-03-23 02:17:06 +11:00
try:
2018-06-15 23:15:35 +10:00
path_str = self.cursor.fetchone()[0]
except TypeError:
# idPath not found; skip
continue
# For whatever reason, double might have become triple
2018-11-09 01:15:52 +11:00
path_str = path_str.replace('///', '//').replace('\\\\\\', '\\\\')
2018-06-15 23:15:35 +10:00
if path_str == path:
result.append(file[0])
if len(result) == 0:
2018-02-25 23:37:30 +11:00
LOG.info('Did not find matching paths, abort')
return
# Kodi seems to make ONE temporary entry; we only want the earlier,
# permanent one
if len(result) > 2:
2018-02-25 23:37:30 +11:00
LOG.warn('We found too many items with matching filenames and '
2016-08-31 00:43:56 +10:00
' paths, aborting')
return
2018-06-15 23:15:35 +10:00
file_id = result[0]
2016-03-23 02:17:06 +11:00
# Try movies first
2018-06-15 23:15:35 +10:00
self.cursor.execute('SELECT idMovie FROM movie WHERE idFile = ?',
(file_id, ))
try:
2018-06-15 23:15:35 +10:00
movie_id = self.cursor.fetchone()[0]
typus = v.KODI_TYPE_MOVIE
except TypeError:
# Try tv shows next
2018-11-09 01:15:52 +11:00
self.cursor.execute('SELECT idEpisode FROM episode WHERE idFile = ?',
2018-06-15 23:15:35 +10:00
(file_id, ))
2016-03-23 02:17:06 +11:00
try:
2018-06-15 23:15:35 +10:00
movie_id = self.cursor.fetchone()[0]
typus = v.KODI_TYPE_EPISODE
except TypeError:
2018-06-17 21:21:22 +10:00
LOG.debug('Did not find a video DB match')
return
2018-06-15 23:15:35 +10:00
return movie_id, typus
2016-03-23 02:17:06 +11:00
2017-12-14 06:14:27 +11:00
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.
"""
2018-11-09 01:15:52 +11:00
self.cursor.execute('SELECT idPath FROM path WHERE strPath = ?',
(path,))
2018-05-03 02:50:31 +10:00
path_ids = self.cursor.fetchall()
if len(path_ids) != 1:
2018-06-03 22:04:11 +10:00
LOG.debug('Found wrong number of path ids: %s for path %s, abort',
2018-05-03 02:50:31 +10:00
path_ids, path)
2017-12-14 06:14:27 +11:00
return
2018-11-09 01:15:52 +11:00
self.cursor.execute('SELECT idSong FROM song WHERE strFileName = ? AND idPath = ?',
(filename, path_ids[0][0]))
2018-05-03 02:50:31 +10:00
song_ids = self.cursor.fetchall()
if len(song_ids) != 1:
LOG.info('Found wrong number of songs %s, abort', song_ids)
2017-12-14 06:14:27 +11:00
return
2018-05-03 02:50:31 +10:00
return song_ids[0][0]
2017-12-14 06:14:27 +11:00
2018-02-08 00:32:58 +11:00
def get_resume(self, file_id):
"""
Returns the first resume point in seconds (int) if found, else None for
the Kodi file_id provided
"""
2018-11-09 01:15:52 +11:00
self.cursor.execute('SELECT timeInSeconds FROM bookmark WHERE idFile = ? LIMIT 1',
(file_id,))
2018-02-08 00:32:58 +11:00
try:
2018-11-09 01:15:52 +11:00
return self.cursor.fetchone()[0]
2018-02-08 00:32:58 +11:00
except TypeError:
2018-11-09 01:15:52 +11:00
pass
2018-02-08 00:32:58 +11:00
def get_playcount(self, file_id):
"""
Returns the playcount for the item file_id or None if not found
"""
2018-11-09 01:15:52 +11:00
self.cursor.execute('SELECT playCount FROM files WHERE idFile = ? LIMIT 1',
(file_id, ))
try:
2018-11-09 01:15:52 +11:00
return self.cursor.fetchone()[0]
except TypeError:
2018-11-09 01:15:52 +11:00
pass
2018-06-15 23:15:35 +10:00
def set_resume(self, file_id, resume_seconds, total_seconds, playcount,
dateplayed, plex_type):
"""
Adds a resume marker for a video library item. Will even set 2,
considering add-on path widget hacks.
"""
if not state.DIRECT_PATHS and plex_type == v.PLEX_TYPE_EPISODE:
# Need to make sure to set a SECOND bookmark entry for another,
# second file_id that points to the path .tvshows instead of
# .tvshows/<plex show id/!
2018-11-09 01:15:52 +11:00
self.cursor.execute('SELECT strFilename FROM files WHERE idFile = ? LIMIT 1',
(file_id, ))
for new_id in self.cursor.execute('SELECT idFile FROM files WHERE strFilename = ? LIMIT 2',
(self.cursor.fetchone()[0], )):
2018-06-15 23:15:35 +10:00
self.set_resume(new_id[0], resume_seconds, total_seconds,
playcount, dateplayed, None)
return
# Delete existing resume point
2018-03-11 03:09:21 +11:00
self.cursor.execute('DELETE FROM bookmark WHERE idFile = ?', (file_id,))
# Set watched count
2018-11-09 01:15:52 +11:00
self.cursor.execute('UPDATE files SET playCount = ?, lastPlayed = ? WHERE idFile = ?',
(playcount, dateplayed, file_id))
# Set the resume bookmark
if resume_seconds:
self.cursor.execute(
'select coalesce(max(idBookmark),0) from bookmark')
bookmark_id = self.cursor.fetchone()[0] + 1
2018-11-09 01:15:52 +11:00
self.cursor.execute('''
INSERT INTO bookmark(
2018-11-09 01:15:52 +11:00
idBookmark,
idFile,
timeInSeconds,
totalTimeInSeconds,
thumbNailImage,
player,
playerState,
type)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
2018-11-09 01:15:52 +11:00
''', (bookmark_id,
file_id,
resume_seconds,
total_seconds,
'',
'VideoPlayer',
'',
1))
2018-06-15 23:15:35 +10:00
def create_tag(self, name):
"""
Will create a new tag if needed and return the tag_id
"""
2018-11-09 01:15:52 +11:00
self.cursor.execute('SELECT tag_id FROM tag WHERE name = ? COLLATE NOCASE',
(name,))
2018-02-25 23:35:09 +11:00
try:
tag_id = self.cursor.fetchone()[0]
except TypeError:
self.cursor.execute("select coalesce(max(tag_id),0) from tag")
2018-02-25 23:35:09 +11:00
tag_id = self.cursor.fetchone()[0] + 1
2018-11-09 01:15:52 +11:00
self.cursor.execute('INSERT INTO tag(tag_id, name) VALUES(?, ?)',
(tag_id, name))
return tag_id
2018-06-15 23:15:35 +10:00
def update_tag(self, oldtag, newtag, kodiid, mediatype):
"""
Updates the tag_id by replaying oldtag with newtag
"""
2018-02-25 23:35:09 +11:00
try:
2018-11-09 01:15:52 +11:00
self.cursor.execute('''
UPDATE tag_link
SET tag_id = ?
WHERE media_id = ? AND media_type = ? AND tag_id = ?
''', (newtag, kodiid, mediatype, oldtag,))
2018-06-15 23:15:35 +10:00
except:
2018-02-25 23:35:09 +11:00
# The new tag we are going to apply already exists for this item
# delete current tag instead
2018-11-09 01:15:52 +11:00
self.cursor.execute('''
2018-06-15 23:15:35 +10:00
DELETE FROM tag_link
WHERE media_id = ? AND media_type = ? AND tag_id = ?
2018-11-09 01:15:52 +11:00
''', (kodiid, mediatype, oldtag,))
2018-06-15 23:15:35 +10:00
def create_collection(self, set_name):
"""
Returns the collection/set id for set_name [unicode]
"""
2018-11-09 01:15:52 +11:00
self.cursor.execute('SELECT idSet FROM sets WHERE strSet = ? COLLATE NOCASE',
(set_name,))
try:
setid = self.cursor.fetchone()[0]
except TypeError:
self.cursor.execute("select coalesce(max(idSet),0) from sets")
setid = self.cursor.fetchone()[0] + 1
2018-11-09 01:15:52 +11:00
self.cursor.execute('INSERT INTO sets(idSet, strSet) VALUES(?, ?)',
(setid, set_name))
return setid
2018-06-15 23:15:35 +10:00
def assign_collection(self, setid, movieid):
"""
Assign the movie to one set/collection
"""
2018-11-09 01:15:52 +11:00
self.cursor.execute('UPDATE movie SET idSet = ? WHERE idMovie = ?',
(setid, movieid,))
def remove_from_set(self, movieid):
"""
Remove the movie with movieid [int] from an associated movie set, movie
collection
"""
self.cursor.execute('UPDATE movie SET idSet = null WHERE idMovie = ?',
(movieid,))
2018-02-26 19:06:35 +11:00
def get_set_id(self, kodi_id):
"""
Returns the set_id for the movie with kodi_id or None
"""
2018-11-09 01:15:52 +11:00
self.cursor.execute('SELECT idSet FROM movie WHERE idMovie = ?',
(kodi_id, ))
2018-02-26 19:06:35 +11:00
try:
2018-11-09 01:15:52 +11:00
return self.cursor.fetchone()[0]
2018-02-26 19:06:35 +11:00
except TypeError:
2018-11-09 01:15:52 +11:00
pass
2018-02-26 19:06:35 +11:00
def delete_possibly_empty_set(self, set_id):
"""
Checks whether there are other movies in the set set_id. If not,
deletes the set
"""
2018-11-09 01:15:52 +11:00
self.cursor.execute('SELECT idSet FROM movie WHERE idSet = ?',
(set_id, ))
2018-02-26 19:06:35 +11:00
if self.cursor.fetchone() is None:
2018-11-09 01:15:52 +11:00
self.cursor.execute('DELETE FROM sets WHERE idSet = ?', (set_id,))
2018-02-26 19:06:35 +11:00
2018-03-11 01:02:06 +11:00
def add_season(self, showid, seasonnumber):
"""
Adds a TV show season to the Kodi video DB or simply returns the ID,
if there already is an entry in the DB
"""
2018-11-09 01:15:52 +11:00
self.cursor.execute('SELECT idSeason FROM seasons WHERE idShow = ? AND season = ?',
(showid, seasonnumber,))
try:
seasonid = self.cursor.fetchone()[0]
except TypeError:
2018-03-11 01:02:06 +11:00
self.cursor.execute("SELECT COALESCE(MAX(idSeason),0) FROM seasons")
seasonid = self.cursor.fetchone()[0] + 1
2018-11-09 01:15:52 +11:00
self.cursor.execute('''
2018-03-11 01:02:06 +11:00
INSERT INTO seasons(idSeason, idShow, season)
VALUES (?, ?, ?)
2018-11-09 01:15:52 +11:00
''', (seasonid, showid, seasonnumber))
return seasonid
2018-06-15 23:15:35 +10:00
def add_artist(self, name, musicbrainz):
"""
Adds a single artist's name to the db
"""
2018-11-09 01:15:52 +11:00
self.cursor.execute('''
SELECT idArtist, strArtist
FROM artist
WHERE strMusicBrainzArtistID = ?
2018-11-09 01:15:52 +11:00
''', (musicbrainz, ))
try:
result = self.cursor.fetchone()
artistid = result[0]
artistname = result[1]
except TypeError:
2018-11-09 01:15:52 +11:00
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
2018-11-09 01:15:52 +11:00
self.cursor.execute('SELECT COALESCE(MAX(idArtist),1) FROM artist')
artistid = self.cursor.fetchone()[0] + 1
2018-11-09 01:15:52 +11:00
self.cursor.execute('''
INSERT INTO artist(
idArtist,
strArtist,
strMusicBrainzArtistID)
VALUES (?, ?, ?)
2018-11-09 01:15:52 +11:00
''', (artistid, name, musicbrainz))
else:
if artistname != name:
2018-11-09 01:15:52 +11:00
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
"""
2018-11-09 01:15:52 +11:00
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
2018-11-09 01:15:52 +11:00
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!
2018-11-09 01:15:52 +11:00
self.cursor.execute('SELECT strAlbum, iYear FROM album WHERE idAlbum = ? LIMIT 1',
(album_id, ))
try:
name, year = self.cursor.fetchone()
except TypeError:
return
2018-11-09 01:15:52 +11:00
self.cursor.execute('SELECT idArtist FROM album_artist WHERE idAlbum = ? LIMIT 1',
(album_id, ))
artist = self.cursor.fetchone()
if not artist:
return
2018-11-09 01:15:52 +11:00
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
"""
2018-11-09 01:15:52 +11:00
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:
2018-11-09 01:15:52 +11:00
self.cursor.execute('SELECT idGenre FROM song_genre WHERE idGenre = ? LIMIT 1',
(genre[0], ))
if not self.cursor.fetchone():
2018-11-09 01:15:52 +11:00
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
"""
2018-11-09 01:15:52 +11:00
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:
2018-11-09 01:15:52 +11:00
self.cursor.execute('SELECT idGenre FROM album_genre WHERE idGenre = ? LIMIT 1',
(genre[0], ))
if not self.cursor.fetchone():
2018-11-09 01:15:52 +11:00
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], ))
2018-06-15 23:15:35 +10:00
def add_album(self, name, musicbrainz):
"""
Adds a single album to the DB
"""
2018-11-09 01:15:52 +11:00
self.cursor.execute('SELECT idAlbum FROM album WHERE strMusicBrainzAlbumID = ?',
(musicbrainz, ))
try:
albumid = self.cursor.fetchone()[0]
except TypeError:
2016-01-02 16:24:28 +11:00
# Create the album
self.cursor.execute('SELECT COALESCE(MAX(idAlbum),0) FROM album')
albumid = self.cursor.fetchone()[0] + 1
2018-11-09 01:15:52 +11:00
self.cursor.execute('''
INSERT INTO album(
idAlbum,
strAlbum,
strMusicBrainzAlbumID,
strReleaseType)
2018-02-25 23:35:09 +11:00
VALUES (?, ?, ?, ?)
2018-11-09 01:15:52 +11:00
''', (albumid, name, musicbrainz, 'album'))
return albumid
2018-06-15 23:15:35 +10:00
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
2018-11-09 01:15:52 +11:00
self.cursor.execute('DELETE FROM album_genre WHERE idAlbum = ?',
(kodiid, ))
for genre in genres:
2018-11-09 01:15:52 +11:00
self.cursor.execute('SELECT idGenre FROM genre WHERE strGenre = ?',
(genre, ))
try:
genreid = self.cursor.fetchone()[0]
except TypeError:
# Create the genre
2018-11-09 01:15:52 +11:00
self.cursor.execute('SELECT COALESCE(MAX(idGenre),0) FROM genre')
genreid = self.cursor.fetchone()[0] + 1
2018-11-09 01:15:52 +11:00
self.cursor.execute('INSERT INTO genre(idGenre, strGenre) VALUES(?, ?)',
(genreid, genre))
self.cursor.execute('''
INSERT OR REPLACE INTO album_genre(
idGenre,
idAlbum)
VALUES (?, ?)
2018-11-09 01:15:52 +11:00
''', (genreid, kodiid))
elif mediatype == "song":
# Delete current genres for clean slate
2018-11-09 01:15:52 +11:00
self.cursor.execute('DELETE FROM song_genre WHERE idSong = ?',
(kodiid, ))
for genre in genres:
2018-11-09 01:15:52 +11:00
self.cursor.execute('SELECT idGenre FROM genre WHERE strGenre = ?',
(genre, ))
try:
genreid = self.cursor.fetchone()[0]
except TypeError:
# Create the genre
2018-11-09 01:15:52 +11:00
self.cursor.execute('SELECT COALESCE(MAX(idGenre),0) FROM genre')
genreid = self.cursor.fetchone()[0] + 1
2018-11-09 01:15:52 +11:00
self.cursor.execute('INSERT INTO genre(idGenre, strGenre) values(?, ?)',
(genreid, genre))
self.cursor.execute('''
INSERT OR REPLACE INTO song_genre(
idGenre,
idSong)
VALUES (?, ?)
2018-11-09 01:15:52 +11:00
''', (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:
2018-06-15 23:15:35 +10:00
identifier = 'idMovie'
elif kodi_type == v.KODI_TYPE_EPISODE:
2018-06-15 23:15:35 +10:00
identifier = 'idEpisode'
elif kodi_type == v.KODI_TYPE_SONG:
2018-06-15 23:15:35 +10:00
identifier = 'idSong'
2018-11-09 01:15:52 +11:00
self.cursor.execute('UPDATE %s SET userrating = ? WHERE ? = ?' % kodi_type,
(userrating, identifier, kodi_id))
def add_uniqueid(self, *args):
"""
Feed with:
2017-02-14 06:50:10 +11:00
uniqueid_id: int
media_id: int
media_type: string
value: string
type: e.g. 'imdb' or 'tvdb'
"""
2018-11-09 01:15:52 +11:00
self.cursor.execute('''
INSERT INTO uniqueid(
2018-11-09 01:15:52 +11:00
uniqueid_id,
media_id,
media_type,
value,
type)
VALUES (?, ?, ?, ?, ?)
2018-11-09 01:15:52 +11:00
''', (args))
2017-02-14 06:26:30 +11:00
def get_uniqueid(self, kodi_id, kodi_type):
2018-06-15 23:15:35 +10:00
"""
Returns the uniqueid_id
"""
2018-11-09 01:15:52 +11:00
self.cursor.execute('SELECT uniqueid_id FROM uniqueid WHERE media_id = ? AND media_type =?',
(kodi_id, kodi_type))
try:
2018-11-09 01:15:52 +11:00
return self.cursor.fetchone()[0]
except TypeError:
2018-11-09 01:15:52 +11:00
self.cursor.execute('SELECT COALESCE(MAX(uniqueid_id),0) FROM uniqueid')
return self.cursor.fetchone()[0] + 1
def update_uniqueid(self, *args):
"""
Pass in media_id, media_type, value, type, uniqueid_id
"""
2018-11-09 01:15:52 +11:00
self.cursor.execute('''
UPDATE uniqueid
SET media_id = ?, media_type = ?, value = ?, type = ?
WHERE uniqueid_id = ?
2018-11-09 01:15:52 +11:00
''', (args))
def remove_uniqueid(self, kodi_id, kodi_type):
2018-06-15 23:15:35 +10:00
"""
Deletes the entry from the uniqueid table for the item
"""
2018-11-09 01:15:52 +11:00
self.cursor.execute('DELETE FROM uniqueid WHERE media_id = ? AND media_type = ?',
(kodi_id, kodi_type))
2017-02-14 06:23:02 +11:00
def get_ratingid(self, kodi_id, kodi_type):
2018-06-15 23:15:35 +10:00
"""
Create if needed and return the unique rating_id from rating table
"""
2018-11-09 01:15:52 +11:00
self.cursor.execute('SELECT rating_id FROM rating WHERE media_id = ? AND media_type = ?',
(kodi_id, kodi_type))
try:
2018-11-09 01:15:52 +11:00
return self.cursor.fetchone()[0]
except TypeError:
self.cursor.execute('SELECT COALESCE(MAX(rating_id),0) FROM rating')
2018-11-09 01:15:52 +11:00
return self.cursor.fetchone()[0] + 1
def update_ratings(self, *args):
"""
Feed with media_id, media_type, rating_type, rating, votes, rating_id
"""
2018-11-09 01:15:52 +11:00
self.cursor.execute('''
UPDATE rating
SET media_id = ?,
media_type = ?,
rating_type = ?,
rating = ?,
votes = ?
WHERE rating_id = ?
2018-11-09 01:15:52 +11:00
''', (args))
def add_ratings(self, *args):
"""
feed with:
rating_id, media_id, media_type, rating_type, rating, votes
rating_type = 'default'
"""
2018-11-09 01:15:52 +11:00
self.cursor.execute('''
INSERT INTO rating(
2018-11-09 01:15:52 +11:00
rating_id,
media_id,
media_type,
rating_type,
rating, votes)
VALUES (?, ?, ?, ?, ?, ?)
2018-11-09 01:15:52 +11:00
''', (args))
def remove_ratings(self, kodi_id, kodi_type):
2018-06-15 23:15:35 +10:00
"""
Removes all ratings from the rating table for the item
"""
2018-11-09 01:15:52 +11:00
self.cursor.execute('DELETE FROM rating WHERE media_id = ? AND media_type = ?',
(kodi_id, kodi_type))
2018-11-06 04:00:01 +11:00
def art_urls(self, kodi_id, kodi_type):
2018-11-09 01:15:52 +11:00
return (x[0] for x in
self.cursor.execute('SELECT url FROM art WHERE media_id = ? AND media_type = ?',
(kodi_id, kodi_type)))
2018-11-06 04:00:01 +11:00
2018-11-06 01:23:51 +11:00
def artwork_generator(self, kodi_type):
"""
"""
2018-11-09 01:15:52 +11:00
return (x[0] for x in
self.cursor.execute('SELECT url FROM art WHERE type == ?',
(kodi_type, )))
2018-11-06 01:23:51 +11:00
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
2018-04-28 17:12:29 +10:00
def kodiid_from_filename(path, kodi_type=None, db_type=None):
"""
2017-12-14 06:14:27 +11:00
Returns kodi_id if we have an item in the Kodi video or audio database with
2018-04-28 17:12:29 +10:00
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
"""
2017-12-14 06:14:27 +11:00
kodi_id = None
2018-06-22 03:24:37 +10:00
path = utils.try_decode(path)
try:
2017-12-14 06:14:27 +11:00
filename = path.rsplit('/', 1)[1]
path = path.rsplit('/', 1)[0] + '/'
except IndexError:
2017-12-14 06:14:27 +11:00
filename = path.rsplit('\\', 1)[1]
path = path.rsplit('\\', 1)[0] + '\\'
2018-04-28 17:12:29 +10:00
if kodi_type == v.KODI_TYPE_SONG or db_type == 'music':
2017-12-14 06:14:27 +11:00
with GetKodiDB('music') as kodi_db:
try:
2018-05-03 02:50:31 +10:00
kodi_id = kodi_db.music_id_from_filename(filename, path)
2017-12-14 06:14:27 +11:00
except TypeError:
2018-02-25 23:37:30 +11:00
LOG.debug('No Kodi audio db element found for path %s', path)
2018-05-03 02:50:31 +10:00
else:
kodi_type = v.KODI_TYPE_SONG
2017-12-14 06:14:27 +11:00
else:
with GetKodiDB('video') as kodi_db:
try:
2018-04-28 17:12:29 +10:00
kodi_id, kodi_type = kodi_db.video_id_from_filename(filename,
path)
2017-12-14 06:14:27 +11:00
except TypeError:
2018-02-25 23:37:30 +11:00
LOG.debug('No kodi video db element found for path %s', path)
2018-04-28 17:12:29 +10:00
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 GetKodiDB('music') as kodi_db:
2018-11-09 01:15:52 +11:00
kodi_db.cursor.execute('''
INSERT OR REPLACE INTO artist(
2018-11-09 01:15:52 +11:00
idArtist,
strArtist,
strMusicBrainzArtistID)
VALUES (?, ?, ?)
2018-11-09 01:15:52 +11:00
''', (1, '[Missing Tag]', 'Artist Tag Missing'))
if v.KODIVERSION >= 18:
2018-11-09 01:15:52 +11:00
kodi_db.cursor.execute('''
INSERT OR REPLACE INTO versiontagscan(
2018-11-09 01:15:52 +11:00
idVersion,
iNeedsScan,
lastscanned)
VALUES (?, ?, ?)
2018-11-09 01:15:52 +11:00
''', (v.DB_MUSIC_VERSION[v.KODIVERSION],
0,
utils.unix_date_to_kodi(utils.unix_timestamp())))
2018-11-06 04:00:01 +11:00
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:
2018-11-09 01:15:52 +11:00
kodi_db.cursor.execute('SELECT tbl_name FROM sqlite_master WHERE type=?',
('table', ))
2018-11-06 04:00:01 +11:00
rows = kodi_db.cursor.fetchall()
for row in rows:
if row[0] != 'version':
kodi_db.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 = ['video', 'texture']
if music:
kinds.append('music')
for db in kinds:
with GetKodiDB(db) as kodi_db:
2018-11-09 01:15:52 +11:00
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:
2018-11-09 01:15:52 +11:00
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)')
2018-11-06 04:00:01 +11:00
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')
}