This commit is contained in:
Croneter 2018-06-15 15:15:35 +02:00
parent 12f1486f53
commit 9963163f0e
4 changed files with 148 additions and 145 deletions

View File

@ -117,12 +117,12 @@ class Items(object):
if kodi_type == v.KODI_TYPE_MOVIE:
for setname in api.collection_list():
LOG.debug('Getting artwork for movie set %s', setname)
setid = self.kodi_db.createBoxset(setname)
setid = self.kodi_db.create_collection(setname)
self.artwork.modify_artwork(api.set_artwork(),
setid,
v.KODI_TYPE_SET,
self.kodicursor)
self.kodi_db.assignBoxset(setid, kodi_id)
self.kodi_db.assign_collection(setid, kodi_id)
return True
def updateUserdata(self, xml):
@ -143,12 +143,12 @@ class Items(object):
# Grab the user's viewcount, resume points etc. from PMS' answer
userdata = api.userdata()
# Write to Kodi DB
self.kodi_db.addPlaystate(fileid,
userdata['Resume'],
userdata['Runtime'],
userdata['PlayCount'],
userdata['LastPlayedDate'],
api.plex_type())
self.kodi_db.set_resume(fileid,
userdata['Resume'],
userdata['Runtime'],
userdata['PlayCount'],
userdata['LastPlayedDate'],
api.plex_type())
if v.KODIVERSION >= 17:
self.kodi_db.update_userrating(db_item[0],
db_item[4],
@ -171,12 +171,12 @@ class Items(object):
view_count = 1
resume = 0
# Do the actual update
self.kodi_db.addPlaystate(file_id,
resume,
duration,
view_count,
lastViewedAt,
plex_type)
self.kodi_db.set_resume(file_id,
resume,
duration,
view_count,
lastViewedAt,
plex_type)
class Movies(Items):
@ -448,14 +448,14 @@ class Movies(Items):
tags.append("Favorite movies")
self.kodi_db.modify_tags(movieid, v.KODI_TYPE_MOVIE, tags)
# Add any sets from Plex collection tags
self.kodi_db.addSets(movieid, collections, kodicursor)
self.kodi_db.add_sets(movieid, collections)
# Process playstates
self.kodi_db.addPlaystate(fileid,
resume,
runtime,
playcount,
dateplayed,
v.PLEX_TYPE_MOVIE)
self.kodi_db.set_resume(fileid,
resume,
runtime,
playcount,
dateplayed,
v.PLEX_TYPE_MOVIE)
def remove(self, plex_id):
"""
@ -993,11 +993,11 @@ class TVShows(Items):
kodicursor)
streams = api.mediastreams()
self.kodi_db.modify_streams(fileid, streams, runtime)
self.kodi_db.addPlaystate(fileid,
resume,
runtime,
playcount,
dateplayed,
self.kodi_db.set_resume(fileid,
resume,
runtime,
playcount,
dateplayed,
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
@ -1009,11 +1009,11 @@ class TVShows(Items):
filename))
pathid = self.kodi_db.add_video_path(path)
fileid = self.kodi_db.add_file(filename, pathid, dateadded)
self.kodi_db.addPlaystate(fileid,
resume,
runtime,
playcount,
dateplayed,
self.kodi_db.set_resume(fileid,
resume,
runtime,
playcount,
dateplayed,
None) # Do send None - 2nd entry
@catch_exceptions(warnuser=True)
@ -1201,7 +1201,7 @@ class Music(Items):
# multiple times.
# Kodi doesn't allow that. In case that happens we just merge the
# artist entries.
artistid = self.kodi_db.addArtist(name, musicBrainzId)
artistid = self.kodi_db.add_artist(name, musicBrainzId)
# Create the reference in plex table
plex_db.addReference(itemid,
v.PLEX_TYPE_ARTIST,
@ -1304,7 +1304,7 @@ class Music(Items):
# multiple times.
# Kodi doesn't allow that. In case that happens we just merge the
# artist entries.
album_id = self.kodi_db.addAlbum(name, musicBrainzId)
album_id = self.kodi_db.add_album(name, musicBrainzId)
# Create the reference in plex table
plex_db.addReference(plex_id,
v.PLEX_TYPE_ALBUM,
@ -1389,7 +1389,9 @@ class Music(Items):
'''
kodicursor.execute(query, (artist_id, name, year))
if v.KODIVERSION < 18:
self.kodi_db.addMusicGenres(album_id, self.genres, v.KODI_TYPE_ALBUM)
self.kodi_db.add_music_genres(album_id,
self.genres,
v.KODI_TYPE_ALBUM)
# Update artwork
artwork.modify_artwork(artworks, album_id, v.KODI_TYPE_ALBUM, kodicursor)
# Add all children - all tracks
@ -1541,7 +1543,7 @@ class Music(Items):
LOG.info("ADD song itemid: %s - Title: %s", itemid, title)
# Add path
pathid = self.kodi_db.add_music_path(path, strHash="123")
pathid = self.kodi_db.add_music_path(path, hash_string="123")
try:
# Get the album
@ -1553,7 +1555,7 @@ class Music(Items):
if album_name:
LOG.info("Creating virtual music album for song: %s.",
itemid)
albumid = self.kodi_db.addAlbum(
albumid = self.kodi_db.add_album(
album_name,
api.provider('MusicBrainzAlbum'))
plex_db.addReference("%salbum%s" % (itemid, albumid),
@ -1711,7 +1713,7 @@ class Music(Items):
artist_name))
# Add genres
if genres:
self.kodi_db.addMusicGenres(songid, genres, v.KODI_TYPE_SONG)
self.kodi_db.add_music_genres(songid, genres, v.KODI_TYPE_SONG)
artworks = api.artwork()
artwork.modify_artwork(artworks, songid, v.KODI_TYPE_SONG, kodicursor)
if item.get('parentKey') is None:

View File

@ -1,5 +1,7 @@
# -*- coding: utf-8 -*-
#
# Connect to the Kodi databases (video and music) and operate on them
#
###############################################################################
from logging import getLogger
from ntpath import dirname
@ -156,7 +158,12 @@ class KodiDBMethods(object):
content, scraper, 1))
return pathid
def add_music_path(self, path, strHash=None):
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
if path is None:
path = ''
@ -171,7 +178,7 @@ class KodiDBMethods(object):
INSERT INTO path(idPath, strPath, strHash)
VALUES (?, ?, ?)
'''
self.cursor.execute(query, (pathid, path, strHash))
self.cursor.execute(query, (pathid, path, hash_string))
return pathid
def get_path(self, path):
@ -597,21 +604,13 @@ class KodiDBMethods(object):
Returns None if not found OR if too many entries were found
"""
query = ' '.join((
"SELECT idFile, idPath",
"FROM files",
"WHERE strFilename = ?"
))
query = 'SELECT idFile, idPath FROM files WHERE strFilename = ?'
self.cursor.execute(query, (filename,))
files = self.cursor.fetchall()
if len(files) == 0:
LOG.info('Did not find any file, abort')
return
query = ' '.join((
"SELECT strPath",
"FROM path",
"WHERE idPath = ?"
))
query = 'SELECT strPath FROM path WHERE idPath = ?'
# result will contain a list of all idFile with matching filename and
# matching path
result = []
@ -619,14 +618,14 @@ class KodiDBMethods(object):
# Use idPath to get path as a string
self.cursor.execute(query, (file[1],))
try:
strPath = self.cursor.fetchone()[0]
path_str = self.cursor.fetchone()[0]
except TypeError:
# idPath not found; skip
continue
# For whatever reason, double might have become triple
strPath = strPath.replace('///', '//')
strPath = strPath.replace('\\\\\\', '\\\\')
if strPath == path:
path_str = path_str.replace('///', '//')
path_str = path_str.replace('\\\\\\', '\\\\')
if path_str == path:
result.append(file[0])
if len(result) == 0:
LOG.info('Did not find matching paths, abort')
@ -637,33 +636,26 @@ class KodiDBMethods(object):
LOG.warn('We found too many items with matching filenames and '
' paths, aborting')
return
idFile = result[0]
file_id = result[0]
# Try movies first
query = ' '.join((
"SELECT idMovie",
"FROM movie",
"WHERE idFile = ?"
))
self.cursor.execute(query, (idFile,))
self.cursor.execute('SELECT idMovie FROM movie WHERE idFile = ?',
(file_id, ))
try:
itemId = self.cursor.fetchone()[0]
movie_id = self.cursor.fetchone()[0]
typus = v.KODI_TYPE_MOVIE
except TypeError:
# Try tv shows next
query = ' '.join((
"SELECT idEpisode",
"FROM episode",
"WHERE idFile = ?"
))
self.cursor.execute(query, (idFile,))
query = 'SELECT idEpisode FROM episode WHERE idFile = ?'
self.cursor.execute(query,
(file_id, ))
try:
itemId = self.cursor.fetchone()[0]
movie_id = self.cursor.fetchone()[0]
typus = v.KODI_TYPE_EPISODE
except TypeError:
LOG.warn('Unexpectantly did not find a match!')
return
return itemId, typus
return movie_id, typus
def music_id_from_filename(self, filename, path):
"""
@ -726,8 +718,12 @@ class KodiDBMethods(object):
answ = None
return answ
def addPlaystate(self, file_id, resume_seconds, total_seconds, playcount,
dateplayed, plex_type):
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
@ -746,8 +742,8 @@ class KodiDBMethods(object):
len(file_ids))
raise RuntimeError
for new_id in file_ids:
self.addPlaystate(new_id[0], resume_seconds, total_seconds,
playcount, dateplayed, None)
self.set_resume(new_id[0], resume_seconds, total_seconds,
playcount, dateplayed, None)
return
# Delete existing resume point
@ -779,87 +775,72 @@ class KodiDBMethods(object):
'',
1))
def createTag(self, name):
# This will create and return the tag_id
query = ' '.join((
"SELECT tag_id",
"FROM tag",
"WHERE name = ?",
"COLLATE NOCASE"
))
def create_tag(self, name):
"""
Will create a new tag if needed and return the tag_id
"""
query = '''
SELECT tag_id FROM tag WHERE name = ? COLLATE NOCASE
'''
self.cursor.execute(query, (name,))
try:
tag_id = self.cursor.fetchone()[0]
except TypeError:
self.cursor.execute("select coalesce(max(tag_id),0) from tag")
tag_id = self.cursor.fetchone()[0] + 1
query = "INSERT INTO tag(tag_id, name) values(?, ?)"
self.cursor.execute(query, (tag_id, name))
LOG.debug("Create tag_id: %s name: %s", tag_id, name)
return tag_id
def updateTag(self, oldtag, newtag, kodiid, mediatype):
def update_tag(self, oldtag, newtag, kodiid, mediatype):
"""
Updates the tag_id by replaying oldtag with newtag
"""
query = '''
UPDATE tag_link SET tag_id = ?
WHERE media_id = ? AND media_type = ? AND tag_id = ?
'''
try:
query = ' '.join((
"UPDATE tag_link",
"SET tag_id = ?",
"WHERE media_id = ?",
"AND media_type = ?",
"AND tag_id = ?"
))
self.cursor.execute(query, (newtag, kodiid, mediatype, oldtag,))
except Exception as e:
except:
# The new tag we are going to apply already exists for this item
# delete current tag instead
query = ' '.join((
"DELETE FROM tag_link",
"WHERE media_id = ?",
"AND media_type = ?",
"AND tag_id = ?"
))
query = '''
DELETE FROM tag_link
WHERE media_id = ? AND media_type = ? AND tag_id = ?
'''
self.cursor.execute(query, (kodiid, mediatype, oldtag,))
def addSets(self, movieid, collections, kodicursor):
def add_sets(self, movieid, collections):
"""
Will add the movie to all collections (a list of unicodes)
"""
for setname in collections:
setid = self.createBoxset(setname)
self.assignBoxset(setid, movieid)
setid = self.create_collection(setname)
self.assign_collection(setid, movieid)
def createBoxset(self, boxsetname):
LOG.debug("Adding boxset: %s", boxsetname)
query = ' '.join((
"SELECT idSet",
"FROM sets",
"WHERE strSet = ?",
"COLLATE NOCASE"
))
self.cursor.execute(query, (boxsetname,))
def create_collection(self, set_name):
"""
Returns the collection/set id for set_name [unicode]
"""
LOG.debug("Adding boxset: %s", set_name)
query = 'SELECT idSet FROM sets WHERE strSet = ? COLLATE NOCASE'
self.cursor.execute(query, (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
query = "INSERT INTO sets(idSet, strSet) values(?, ?)"
self.cursor.execute(query, (setid, boxsetname))
self.cursor.execute(query, (setid, set_name))
return setid
def assignBoxset(self, setid, movieid):
query = ' '.join((
"UPDATE movie",
"SET idSet = ?",
"WHERE idMovie = ?"
))
def assign_collection(self, setid, movieid):
"""
Assign the movie to one set/collection
"""
query = 'UPDATE movie SET idSet = ? WHERE idMovie = ?'
self.cursor.execute(query, (setid, movieid,))
def remove_from_set(self, movieid):
@ -912,7 +893,10 @@ class KodiDBMethods(object):
self.cursor.execute(query, (seasonid, showid, seasonnumber))
return seasonid
def addArtist(self, name, musicbrainz):
def add_artist(self, name, musicbrainz):
"""
Adds a single artist's name to the db
"""
query = '''
SELECT idArtist, strArtist
FROM artist
@ -1047,8 +1031,10 @@ class KodiDBMethods(object):
self.cursor.execute('DELETE FROM genre WHERE idGenre = ?',
(genre[0], ))
def addAlbum(self, name, musicbrainz):
def add_album(self, name, musicbrainz):
"""
Adds a single album to the DB
"""
query = 'SELECT idAlbum FROM album WHERE strMusicBrainzAlbumID = ?'
self.cursor.execute(query, (musicbrainz,))
try:
@ -1065,7 +1051,10 @@ class KodiDBMethods(object):
self.cursor.execute(query, (albumid, name, musicbrainz, 'album'))
return albumid
def addMusicGenres(self, kodiid, genres, mediatype):
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
query = 'DELETE FROM album_genre WHERE idAlbum = ?'
@ -1121,13 +1110,13 @@ class KodiDBMethods(object):
Updates userrating for >=Krypton
"""
if kodi_type == v.KODI_TYPE_MOVIE:
ID = 'idMovie'
identifier = 'idMovie'
elif kodi_type == v.KODI_TYPE_EPISODE:
ID = 'idEpisode'
identifier = 'idEpisode'
elif kodi_type == v.KODI_TYPE_SONG:
ID = 'idSong'
identifier = 'idSong'
query = '''UPDATE %s SET userrating = ? WHERE ? = ?''' % kodi_type
self.cursor.execute(query, (userrating, ID, kodi_id))
self.cursor.execute(query, (userrating, identifier, kodi_id))
def add_uniqueid(self, *args):
"""
@ -1146,6 +1135,9 @@ class KodiDBMethods(object):
self.cursor.execute(query, (args))
def get_uniqueid(self, kodi_id, kodi_type):
"""
Returns the uniqueid_id
"""
query = '''
SELECT uniqueid_id FROM uniqueid
WHERE media_id = ? AND media_type = ?
@ -1171,6 +1163,9 @@ class KodiDBMethods(object):
self.cursor.execute(query, (args))
def remove_uniqueid(self, kodi_id, kodi_type):
"""
Deletes the entry from the uniqueid table for the item
"""
query = '''
DELETE FROM uniqueid
WHERE media_id = ? AND media_type = ?
@ -1178,6 +1173,9 @@ class KodiDBMethods(object):
self.cursor.execute(query, (kodi_id, kodi_type))
def get_ratingid(self, kodi_id, kodi_type):
"""
Create if needed and return the unique rating_id from rating table
"""
query = '''
SELECT rating_id FROM rating
WHERE media_id = ? AND media_type = ?
@ -1220,6 +1218,9 @@ class KodiDBMethods(object):
self.cursor.execute(query, (args))
def remove_ratings(self, kodi_id, kodi_type):
"""
Removes all ratings from the rating table for the item
"""
query = '''
DELETE FROM rating
WHERE media_id = ? AND media_type = ?

View File

@ -533,12 +533,12 @@ def _record_playstate(status, ended):
playcount += 1
time = 0
with kodidb.GetKodiDB('video') as kodi_db:
kodi_db.addPlaystate(kodi_db_item[1],
time,
totaltime,
playcount,
last_played,
status['plex_type'])
kodi_db.set_resume(kodi_db_item[1],
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)')):

View File

@ -326,7 +326,7 @@ class LibrarySync(Thread):
current_tagid = view[2]
except TypeError:
LOG.info('Creating viewid: %s in Plex database.', folderid)
tagid = kodi_db.createTag(foldername)
tagid = kodi_db.create_tag(foldername)
# Create playlist for the video library
if (foldername not in lists and
mediatype in (v.PLEX_TYPE_MOVIE, v.PLEX_TYPE_SHOW)):
@ -361,7 +361,7 @@ class LibrarySync(Thread):
# View was modified, update with latest info
if current_viewname != foldername:
LOG.info('viewid: %s new viewname: %s', folderid, foldername)
tagid = kodi_db.createTag(foldername)
tagid = kodi_db.create_tag(foldername)
# Update view with new info
plex_db.updateView(foldername, tagid, folderid)
@ -407,7 +407,7 @@ class LibrarySync(Thread):
items = plex_db.getItem_byView(folderid)
for item in items:
# Remove the "s" from viewtype for tags
kodi_db.updateTag(
kodi_db.update_tag(
current_tagid, tagid, item[0], current_viewtype[:-1])
else:
# Validate the playlist exists or recreate it