PlexKodiConnect/resources/lib/itemtypes.py

1968 lines
80 KiB
Python
Raw Normal View History

# -*- coding: utf-8 -*-
2016-02-20 06:03:06 +11:00
###############################################################################
2017-12-10 00:35:08 +11:00
from logging import getLogger
from ntpath import dirname
from datetime import datetime
2018-02-11 22:06:04 +11:00
from artwork import Artwork
2018-02-11 23:24:00 +11:00
from utils import window, kodi_sql, catch_exceptions
import plexdb_functions as plexdb
import kodidb_functions as kodidb
2016-02-20 06:03:06 +11:00
2018-02-11 22:06:04 +11:00
from PlexAPI import API
from PlexFunctions import GetPlexMetadata
import variables as v
2017-05-17 23:42:12 +10:00
import state
2016-02-20 06:03:06 +11:00
###############################################################################
2018-02-11 22:06:04 +11:00
LOG = getLogger("PLEX." + __name__)
2016-08-31 00:40:11 +10:00
# Note: always use same order of URL arguments, NOT urlencode:
# plex_id=<plex_id>&plex_type=<plex_type>&mode=play
2016-08-31 00:40:11 +10:00
###############################################################################
class Items(object):
2016-01-11 01:16:59 +11:00
"""
Items to be called with "with Items() as xxx:" to ensure that __enter__
2016-01-11 18:10:36 +11:00
method is called (opens db connections)
Input:
kodiType: optional argument; e.g. 'video' or 'music'
2016-01-11 01:16:59 +11:00
"""
def __init__(self):
2018-02-11 22:06:04 +11:00
self.artwork = Artwork()
2016-08-31 00:40:11 +10:00
self.server = window('pms_server')
2018-02-11 22:06:04 +11:00
self.plexconn = None
self.plexcursor = None
self.kodiconn = None
self.kodicursor = None
self.plex_db = None
self.kodi_db = None
def __enter__(self):
2016-01-11 01:16:59 +11:00
"""
Open DB connections and cursors
"""
2018-02-11 22:59:04 +11:00
self.plexconn = kodi_sql('plex')
self.plexcursor = self.plexconn.cursor()
2018-02-11 22:59:04 +11:00
self.kodiconn = kodi_sql('video')
self.kodicursor = self.kodiconn.cursor()
self.plex_db = plexdb.Plex_DB_Functions(self.plexcursor)
2018-02-25 23:42:20 +11:00
self.kodi_db = kodidb.KodiDBMethods(self.kodicursor)
return self
def __exit__(self, exc_type, exc_val, exc_tb):
"""
Make sure DB changes are committed and connection to DB is closed.
"""
self.plexconn.commit()
self.kodiconn.commit()
self.plexconn.close()
self.kodiconn.close()
return self
2018-02-11 23:24:00 +11:00
@catch_exceptions(warnuser=True)
2017-02-02 22:27:21 +11:00
def getfanart(self, plex_id, refresh=False):
"""
2017-02-02 22:27:21 +11:00
Tries to get additional fanart for movies (+sets) and TV shows.
Returns True if successful, False otherwise
"""
2017-02-02 22:27:21 +11:00
with plexdb.Get_Plex_DB() as plex_db:
db_item = plex_db.getItem_byId(plex_id)
try:
kodi_id = db_item[0]
kodi_type = db_item[4]
except TypeError:
2018-02-11 22:06:04 +11:00
LOG.error('Could not get Kodi id for plex id %s, abort getfanart',
plex_id)
2017-02-02 22:27:21 +11:00
return False
if refresh is True:
# Leave the Plex art untouched
allartworks = None
else:
with kodidb.GetKodiDB('video') as kodi_db:
2018-03-04 23:39:18 +11:00
allartworks = kodi_db.get_art(kodi_id, kodi_type)
2017-02-02 22:27:21 +11:00
# Check if we even need to get additional art
needsupdate = False
2018-03-04 23:39:18 +11:00
for key in v.ALL_KODI_ARTWORK:
if key not in allartworks:
2017-02-02 22:27:21 +11:00
needsupdate = True
break
if needsupdate is False:
2018-02-11 22:06:04 +11:00
LOG.debug('Already got all fanart for Plex id %s', plex_id)
2017-02-02 22:27:21 +11:00
return True
xml = GetPlexMetadata(plex_id)
if xml is None:
# Did not receive a valid XML - skip that item for now
2018-02-11 22:06:04 +11:00
LOG.error("Could not get metadata for %s. Skipping that item "
"for now", plex_id)
2017-02-02 22:27:21 +11:00
return False
elif xml == 401:
2018-02-11 22:06:04 +11:00
LOG.error('HTTP 401 returned by PMS. Too much strain? '
2017-02-02 22:27:21 +11:00
'Cancelling sync for now')
# Kill remaining items in queue (for main thread to cont.)
return False
2018-02-11 22:06:04 +11:00
api = API(xml[0])
if allartworks is None:
2018-02-12 00:42:49 +11:00
allartworks = api.artwork()
2018-03-04 23:39:18 +11:00
self.artwork.modify_artwork(api.fanart_artwork(allartworks),
kodi_id,
kodi_type,
self.kodicursor)
# Also get artwork for collections/movie sets
2017-02-02 22:27:21 +11:00
if kodi_type == v.KODI_TYPE_MOVIE:
2018-02-12 00:42:49 +11:00
for setname in api.collection_list():
2018-02-11 22:06:04 +11:00
LOG.debug('Getting artwork for movie set %s', setname)
setid = self.kodi_db.createBoxset(setname)
2018-03-04 23:39:18 +11:00
self.artwork.modify_artwork(api.set_artwork(),
setid,
v.KODI_TYPE_SET,
self.kodicursor)
2017-02-02 22:27:21 +11:00
self.kodi_db.assignBoxset(setid, kodi_id)
return True
2018-02-11 22:06:04 +11:00
def updateUserdata(self, xml):
2016-02-04 00:44:11 +11:00
"""
Updates the Kodi watched state of the item from PMS. Also retrieves
Plex resume points for movies in progress.
2016-03-11 04:34:11 +11:00
viewtag and viewid only serve as dummies
2016-02-04 00:44:11 +11:00
"""
for mediaitem in xml:
2018-02-11 22:06:04 +11:00
api = API(mediaitem)
2016-02-04 00:44:11 +11:00
# Get key and db entry on the Kodi db side
2018-02-12 00:42:49 +11:00
db_item = self.plex_db.getItem_byId(api.plex_id())
2016-02-11 22:44:12 +11:00
try:
fileid = db_item[1]
except TypeError:
2016-02-11 22:44:12 +11:00
continue
2016-02-04 00:44:11 +11:00
# Grab the user's viewcount, resume points etc. from PMS' answer
2018-02-12 00:42:49 +11:00
userdata = api.userdata()
2016-02-04 00:44:11 +11:00
# Write to Kodi DB
self.kodi_db.addPlaystate(fileid,
userdata['Resume'],
userdata['Runtime'],
userdata['PlayCount'],
userdata['LastPlayedDate'])
if v.KODIVERSION >= 17:
self.kodi_db.update_userrating(db_item[0],
db_item[4],
userdata['UserRating'])
2016-02-04 00:44:11 +11:00
def updatePlaystate(self, mark_played, view_count, resume, duration,
file_id, lastViewedAt):
2016-03-28 01:57:35 +11:00
"""
Use with websockets, not xml
"""
# If the playback was stopped, check whether we need to increment the
# playcount. PMS won't tell us the playcount via websockets
2018-02-16 02:59:12 +11:00
LOG.debug('Set playstate for file_id %s: viewcount: %s, resume: %s',
file_id, view_count, resume)
if mark_played:
2018-02-11 22:06:04 +11:00
LOG.info('Marking as completely watched in Kodi')
try:
view_count += 1
except TypeError:
view_count = 1
resume = 0
2016-03-28 01:57:35 +11:00
# Do the actual update
self.kodi_db.addPlaystate(file_id,
resume,
duration,
view_count,
lastViewedAt)
2016-03-25 04:52:02 +11:00
class Movies(Items):
2018-02-11 22:06:04 +11:00
"""
Used for plex library-type movies
"""
2018-02-11 23:24:00 +11:00
@catch_exceptions(warnuser=True)
def add_update(self, item, viewtag=None, viewid=None):
2018-02-11 22:06:04 +11:00
"""
Process single movie
"""
kodicursor = self.kodicursor
plex_db = self.plex_db
artwork = self.artwork
2018-02-11 22:06:04 +11:00
api = API(item)
# If the item already exist in the local Kodi DB we'll perform a full
# item update
# If the item doesn't exist, we'll add it to the database
update_item = True
2018-02-12 00:42:49 +11:00
itemid = api.plex_id()
# Cannot parse XML, abort
if not itemid:
2018-02-11 22:06:04 +11:00
LOG.error("Cannot parse XML data for movie")
return
plex_dbitem = plex_db.getItem_byId(itemid)
try:
movieid = plex_dbitem[0]
fileid = plex_dbitem[1]
pathid = plex_dbitem[2]
2016-02-05 06:23:04 +11:00
except TypeError:
# movieid
update_item = False
kodicursor.execute("select coalesce(max(idMovie),0) from movie")
movieid = kodicursor.fetchone()[0] + 1
else:
# Verification the item is still in Kodi
query = "SELECT * FROM movie WHERE idMovie = ?"
kodicursor.execute(query, (movieid,))
try:
kodicursor.fetchone()[0]
except TypeError:
# item is not found, let's recreate it.
update_item = False
2018-02-11 22:06:04 +11:00
LOG.info("movieid: %s missing from Kodi, repairing the entry.",
movieid)
# fileId information
2018-02-12 00:42:49 +11:00
checksum = api.checksum()
dateadded = api.date_created()
userdata = api.userdata()
playcount = userdata['PlayCount']
dateplayed = userdata['LastPlayedDate']
resume = userdata['Resume']
runtime = userdata['Runtime']
# item details
2018-02-12 00:42:49 +11:00
people = api.people()
writer = api.list_to_string(people['Writer'])
director = api.list_to_string(people['Director'])
genres = api.genre_list()
genre = api.list_to_string(genres)
title, sorttitle = api.titles()
plot = api.plot()
2015-12-29 04:47:16 +11:00
shortplot = None
2018-02-12 00:42:49 +11:00
tagline = api.tagline()
2015-12-30 23:25:37 +11:00
votecount = None
2018-02-12 00:42:49 +11:00
collections = api.collection_list()
2016-01-11 19:57:45 +11:00
2016-04-02 19:31:21 +11:00
rating = userdata['Rating']
2018-02-12 00:42:49 +11:00
year = api.year()
premieredate = api.premiere_date()
imdb = api.provider('imdb')
mpaa = api.content_rating()
countries = api.country_list()
country = api.list_to_string(countries)
studios = api.music_studio_list()
try:
studio = studios[0]
except IndexError:
studio = None
2018-02-12 18:10:39 +11:00
trailer = api.trailer_id()
if trailer:
trailer = ('plugin://%s.movies/?plex_id=%s&plex_type=%s&mode=play'
2018-02-12 18:10:39 +11:00
% (v.ADDON_ID, trailer, v.PLEX_TYPE_CLIP))
# GET THE FILE AND PATH #####
2018-02-11 22:06:04 +11:00
do_indirect = not state.DIRECT_PATHS
2017-05-17 23:42:12 +10:00
if state.DIRECT_PATHS:
# Direct paths is set the Kodi way
2018-02-12 00:42:49 +11:00
playurl = api.file_path(force_first_media=True)
if playurl is None:
# Something went wrong, trying to use non-direct paths
2018-02-11 22:06:04 +11:00
do_indirect = True
else:
2018-02-12 00:42:49 +11:00
playurl = api.validate_playurl(playurl, api.plex_type())
if playurl is None:
return False
if "\\" in playurl:
# Local path
filename = playurl.rsplit("\\", 1)[1]
else:
# Network share
filename = playurl.rsplit("/", 1)[1]
path = playurl.replace(filename, "")
2018-02-11 22:06:04 +11:00
if do_indirect:
# Set plugin path and media flags using real filename
path = 'plugin://%s.movies/' % v.ADDON_ID
filename = ('%s?plex_id=%s&plex_type=%s&mode=play'
% (path, itemid, v.PLEX_TYPE_MOVIE))
playurl = filename
# movie table:
# c22 - playurl
# c23 - pathid
# This information is used later by file browser.
# add/retrieve pathid and fileid
# if the path or file already exists, the calls return current value
2018-03-05 01:29:45 +11:00
pathid = self.kodi_db.add_video_path(path)
fileid = self.kodi_db.addFile(filename, pathid)
# UPDATE THE MOVIE #####
if update_item:
2018-02-11 22:06:04 +11:00
LOG.info("UPDATE movie itemid: %s - Title: %s", itemid, title)
# Update the movie entry
2017-01-25 02:54:51 +11:00
if v.KODIVERSION >= 17:
# update new ratings Kodi 17
2017-02-20 01:57:31 +11:00
rating_id = self.kodi_db.get_ratingid(movieid,
v.KODI_TYPE_MOVIE)
self.kodi_db.update_ratings(movieid,
v.KODI_TYPE_MOVIE,
"default",
rating,
votecount,
2017-02-20 01:57:31 +11:00
rating_id)
# update new uniqueid Kodi 17
if imdb is not None:
uniqueid = self.kodi_db.get_uniqueid(movieid,
v.KODI_TYPE_MOVIE)
self.kodi_db.update_uniqueid(movieid,
v.KODI_TYPE_MOVIE,
imdb,
"imdb",
uniqueid)
else:
self.kodi_db.remove_uniqueid(movieid, v.KODI_TYPE_MOVIE)
uniqueid = -1
2017-02-03 01:23:54 +11:00
query = '''
UPDATE movie
SET c00 = ?, c01 = ?, c02 = ?, c03 = ?, c04 = ?, c05 = ?,
c06 = ?, c07 = ?, c09 = ?, c10 = ?, c11 = ?, c12 = ?,
c14 = ?, c15 = ?, c16 = ?, c18 = ?, c19 = ?, c21 = ?,
c22 = ?, c23 = ?, idFile=?, premiered = ?,
userrating = ?
WHERE idMovie = ?
'''
kodicursor.execute(query, (title, plot, shortplot, tagline,
2017-05-01 04:41:28 +10:00
votecount, rating_id, writer, year, uniqueid, sorttitle,
2017-02-20 01:57:31 +11:00
runtime, mpaa, genre, director, title, studio, trailer,
2017-09-23 23:56:26 +10:00
country, playurl, pathid, fileid, premieredate,
2017-02-20 01:57:31 +11:00
userdata['UserRating'], movieid))
else:
2017-02-03 01:23:54 +11:00
query = '''
UPDATE movie
SET c00 = ?, c01 = ?, c02 = ?, c03 = ?, c04 = ?, c05 = ?,
c06 = ?, c07 = ?, c09 = ?, c10 = ?, c11 = ?, c12 = ?,
c14 = ?, c15 = ?, c16 = ?, c18 = ?, c19 = ?, c21 = ?,
c22 = ?, c23 = ?, idFile=?
WHERE idMovie = ?
'''
kodicursor.execute(query, (title, plot, shortplot, tagline,
votecount, rating, writer, year, imdb, sorttitle, runtime,
mpaa, genre, director, title, studio, trailer, country,
playurl, pathid, fileid, movieid))
2017-02-03 01:23:54 +11:00
# OR ADD THE MOVIE #####
else:
2018-02-11 22:06:04 +11:00
LOG.info("ADD movie itemid: %s - Title: %s", itemid, title)
2017-01-25 02:54:51 +11:00
if v.KODIVERSION >= 17:
# add new ratings Kodi 17
rating_id = self.kodi_db.get_ratingid(movieid,
v.KODI_TYPE_MOVIE)
2017-02-20 01:57:31 +11:00
self.kodi_db.add_ratings(rating_id,
movieid,
v.KODI_TYPE_MOVIE,
"default",
rating,
votecount)
# add new uniqueid Kodi 17
if imdb is not None:
uniqueid = self.kodi_db.get_uniqueid(movieid,
v.KODI_TYPE_MOVIE)
self.kodi_db.add_uniqueid(uniqueid,
movieid,
v.KODI_TYPE_MOVIE,
imdb,
"imdb")
else:
uniqueid = -1
2017-02-03 01:23:54 +11:00
query = '''
INSERT INTO movie(idMovie, idFile, c00, c01, c02, c03,
c04, c05, c06, c07, c09, c10, c11, c12, c14, c15, c16,
2017-02-03 01:23:54 +11:00
c18, c19, c21, c22, c23, premiered, userrating)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,
2017-02-03 01:23:54 +11:00
?, ?, ?, ?, ?, ?, ?)
'''
kodicursor.execute(query, (movieid, fileid, title, plot,
2017-02-20 01:57:31 +11:00
shortplot, tagline, votecount, rating_id, writer, year,
2017-05-01 04:41:28 +10:00
uniqueid, sorttitle, runtime, mpaa, genre, director,
2017-09-23 23:56:26 +10:00
title, studio, trailer, country, playurl, pathid, premieredate,
2017-02-03 01:23:54 +11:00
userdata['UserRating']))
else:
2017-02-03 01:23:54 +11:00
query = '''
INSERT INTO movie(idMovie, idFile, c00, c01, c02, c03,
c04, c05, c06, c07, c09, c10, c11, c12, c14, c15, c16,
c18, c19, c21, c22, c23)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,
2017-02-03 01:23:54 +11:00
?, ?, ?, ?, ?)
'''
kodicursor.execute(query, (movieid, fileid, title, plot,
shortplot, tagline, votecount, rating, writer, year, imdb,
sorttitle, runtime, mpaa, genre, director, title, studio,
trailer, country, playurl, pathid))
# Create or update the reference in plex table Add reference is
2016-10-27 06:06:16 +11:00
# idempotent; the call here updates also fileid and pathid when item is
# moved or renamed
plex_db.addReference(itemid,
v.PLEX_TYPE_MOVIE,
movieid,
v.KODI_TYPE_MOVIE,
kodi_fileid=fileid,
kodi_pathid=pathid,
parent_id=None,
checksum=checksum,
view_id=viewid)
# Update the path
query = ' '.join((
"UPDATE path",
"SET strPath = ?, strContent = ?, strScraper = ?, noUpdate = ?",
"WHERE idPath = ?"
))
kodicursor.execute(query, (path, "movies", "metadata.local", 1, pathid))
# Update the file
query = ' '.join((
"UPDATE files",
"SET idPath = ?, strFilename = ?, dateAdded = ?",
"WHERE idFile = ?"
))
kodicursor.execute(query, (pathid, filename, dateadded, fileid))
2018-02-11 22:06:04 +11:00
# Process countries
2018-02-28 07:14:42 +11:00
self.kodi_db.modify_countries(movieid, v.KODI_TYPE_MOVIE, countries)
# Process cast
self.kodi_db.modify_people(movieid,
v.KODI_TYPE_MOVIE,
api.people_list())
# Process genres
2018-02-28 07:14:42 +11:00
self.kodi_db.modify_genres(movieid, v.KODI_TYPE_MOVIE, genres)
# Process artwork
2018-03-04 23:39:18 +11:00
artwork.modify_artwork(api.artwork(),
movieid,
v.KODI_TYPE_MOVIE,
kodicursor)
# Process stream details
2018-02-26 19:18:44 +11:00
self.kodi_db.modify_streams(fileid, api.mediastreams(), runtime)
# Process studios
2018-02-28 07:14:42 +11:00
self.kodi_db.modify_studios(movieid, v.KODI_TYPE_MOVIE, studios)
2016-03-02 02:18:12 +11:00
# Process tags: view, Plex collection tags
2016-01-12 01:56:56 +11:00
tags = [viewtag]
tags.extend(collections)
2016-03-02 02:18:12 +11:00
if userdata['Favorite']:
tags.append("Favorite movies")
2018-02-28 07:14:42 +11:00
self.kodi_db.modify_tags(movieid, v.KODI_TYPE_MOVIE, tags)
2016-05-17 01:56:48 +10:00
# Add any sets from Plex collection tags
self.kodi_db.addSets(movieid, collections, kodicursor)
# Process playstates
2016-04-26 22:41:58 +10:00
self.kodi_db.addPlaystate(fileid, resume, runtime, playcount, dateplayed)
def remove(self, itemid):
2018-02-11 22:06:04 +11:00
"""
Remove movieid, fileid, plex reference
"""
plex_db = self.plex_db
kodicursor = self.kodicursor
artwork = self.artwork
plex_dbitem = plex_db.getItem_byId(itemid)
try:
kodi_id = plex_dbitem[0]
file_id = plex_dbitem[1]
kodi_type = plex_dbitem[4]
LOG.debug('Removing %sid: %s file_id: %s',
kodi_type, kodi_id, file_id)
except TypeError:
return
# Remove the plex reference
plex_db.removeItem(itemid)
# Remove artwork
2018-03-04 23:39:18 +11:00
artwork.delete_artwork(kodi_id, kodi_type, kodicursor)
if kodi_type == v.KODI_TYPE_MOVIE:
2018-02-26 19:06:35 +11:00
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)
2018-02-26 19:18:44 +11:00
self.kodi_db.modify_streams(file_id)
2018-02-26 19:33:13 +11:00
self.kodi_db.delete_playstate(file_id)
# Delete kodi movie and file
kodicursor.execute("DELETE FROM movie WHERE idMovie = ?",
(kodi_id,))
kodicursor.execute("DELETE FROM files WHERE idFile = ?",
(file_id,))
2018-02-26 19:06:35 +11:00
if set_id:
self.kodi_db.delete_possibly_empty_set(set_id)
if v.KODIVERSION >= 17:
2017-02-03 03:09:20 +11:00
self.kodi_db.remove_uniqueid(kodi_id, kodi_type)
self.kodi_db.remove_ratings(kodi_id, kodi_type)
elif kodi_type == v.KODI_TYPE_SET:
# Delete kodi boxset
boxset_movies = plex_db.getItem_byParentId(kodi_id,
v.KODI_TYPE_MOVIE)
for movie in boxset_movies:
2016-05-31 16:06:42 +10:00
plexid = movie[0]
movieid = movie[1]
self.kodi_db.removefromBoxset(movieid)
# Update plex reference
plex_db.updateParentId(plexid, None)
kodicursor.execute("DELETE FROM sets WHERE idSet = ?", (kodi_id,))
2018-02-26 20:28:48 +11:00
LOG.debug("Deleted %s %s from kodi database", kodi_type, itemid)
2016-01-10 02:14:02 +11:00
class TVShows(Items):
2018-02-11 22:06:04 +11:00
"""
For Plex library-type TV shows
"""
2018-02-11 23:24:00 +11:00
@catch_exceptions(warnuser=True)
def add_update(self, item, viewtag=None, viewid=None):
2018-02-11 22:06:04 +11:00
"""
Process a single show
"""
kodicursor = self.kodicursor
plex_db = self.plex_db
artwork = self.artwork
2018-02-11 22:06:04 +11:00
api = API(item)
update_item = True
2018-02-12 00:42:49 +11:00
itemid = api.plex_id()
2016-01-10 02:14:02 +11:00
if not itemid:
2018-02-11 22:06:04 +11:00
LOG.error("Cannot parse XML data for TV show")
2016-01-10 02:14:02 +11:00
return
update_item = True
plex_dbitem = plex_db.getItem_byId(itemid)
try:
showid = plex_dbitem[0]
pathid = plex_dbitem[2]
except TypeError:
update_item = False
kodicursor.execute("select coalesce(max(idShow),0) from tvshow")
showid = kodicursor.fetchone()[0] + 1
else:
# Verification the item is still in Kodi
query = "SELECT * FROM tvshow WHERE idShow = ?"
kodicursor.execute(query, (showid,))
try:
kodicursor.fetchone()[0]
except TypeError:
# item is not found, let's recreate it.
update_item = False
2018-02-11 22:06:04 +11:00
LOG.info("showid: %s missing from Kodi, repairing the entry.",
showid)
# fileId information
2018-02-12 00:42:49 +11:00
checksum = api.checksum()
# item details
2018-02-12 00:42:49 +11:00
genres = api.genre_list()
title, sorttitle = api.titles()
plot = api.plot()
rating = api.audience_rating()
2017-02-19 02:30:06 +11:00
votecount = None
2018-02-12 00:42:49 +11:00
premieredate = api.premiere_date()
tvdb = api.provider('tvdb')
mpaa = api.content_rating()
genre = api.list_to_string(genres)
studios = api.music_studio_list()
collections = api.collection_list()
2016-01-10 02:14:02 +11:00
try:
studio = studios[0]
except IndexError:
studio = None
# GET THE FILE AND PATH #####
2018-02-11 22:06:04 +11:00
do_indirect = not state.DIRECT_PATHS
2017-05-17 23:42:12 +10:00
if state.DIRECT_PATHS:
# Direct paths is set the Kodi way
2018-02-12 00:42:49 +11:00
playurl = api.tv_show_path()
if playurl is None:
# Something went wrong, trying to use non-direct paths
2018-02-11 22:06:04 +11:00
do_indirect = True
else:
2018-02-12 00:42:49 +11:00
playurl = api.validate_playurl(playurl,
api.plex_type(),
folder=True)
if playurl is None:
return False
if "\\" in playurl:
# Local path
path = "%s\\" % playurl
toplevelpath = "%s\\" % dirname(dirname(path))
else:
# Network path
path = "%s/" % playurl
toplevelpath = "%s/" % dirname(dirname(path))
2018-02-11 22:06:04 +11:00
if do_indirect:
# Set plugin path
toplevelpath = "plugin://%s.tvshows/" % v.ADDON_ID
path = "%s%s/" % (toplevelpath, itemid)
# Add top path
2018-03-05 01:29:45 +11:00
toppathid = self.kodi_db.add_video_path(toplevelpath)
2016-10-27 05:53:20 +11:00
# add/retrieve pathid and fileid
# if the path or file already exists, the calls return current value
2018-03-05 01:29:45 +11:00
pathid = self.kodi_db.add_video_path(path)
# UPDATE THE TVSHOW #####
if update_item:
2018-02-11 22:06:04 +11:00
LOG.info("UPDATE tvshow itemid: %s - Title: %s", itemid, title)
2017-02-19 02:30:06 +11:00
# Add reference is idempotent; the call here updates also fileid
# and pathid when item is moved or renamed
plex_db.addReference(itemid,
v.PLEX_TYPE_SHOW,
showid,
v.KODI_TYPE_SHOW,
kodi_pathid=pathid,
checksum=checksum,
view_id=viewid)
2017-01-25 02:54:51 +11:00
if v.KODIVERSION >= 17:
# update new ratings Kodi 17
2017-02-19 02:30:06 +11:00
rating_id = self.kodi_db.get_ratingid(showid, v.KODI_TYPE_SHOW)
self.kodi_db.update_ratings(showid,
v.KODI_TYPE_SHOW,
"default",
rating,
2017-02-19 02:30:06 +11:00
votecount,
rating_id)
# update new uniqueid Kodi 17
2017-05-01 18:08:23 +10:00
if tvdb is not None:
uniqueid = self.kodi_db.get_uniqueid(showid,
v.KODI_TYPE_SHOW)
self.kodi_db.update_uniqueid(showid,
v.KODI_TYPE_SHOW,
tvdb,
"unknown",
uniqueid)
else:
self.kodi_db.remove_uniqueid(showid, v.KODI_TYPE_SHOW)
2017-05-01 18:08:23 +10:00
uniqueid = -1
2017-02-19 02:30:06 +11:00
# Update the tvshow entry
query = '''
UPDATE tvshow
SET c00 = ?, c01 = ?, c04 = ?, c05 = ?, c08 = ?, c09 = ?,
c12 = ?, c13 = ?, c14 = ?, c15 = ?
WHERE idShow = ?
'''
kodicursor.execute(query, (title, plot, rating_id,
premieredate, genre, title,
uniqueid, mpaa, studio, sorttitle,
showid))
2017-02-19 02:30:06 +11:00
else:
# Update the tvshow entry
query = '''
UPDATE tvshow
SET c00 = ?, c01 = ?, c04 = ?, c05 = ?, c08 = ?, c09 = ?,
c12 = ?, c13 = ?, c14 = ?, c15 = ?
WHERE idShow = ?
'''
kodicursor.execute(query, (title, plot, rating, premieredate,
genre, title, tvdb, mpaa, studio,
sorttitle, showid))
2017-02-19 02:30:06 +11:00
# OR ADD THE TVSHOW #####
else:
2018-02-11 22:06:04 +11:00
LOG.info("ADD tvshow itemid: %s - Title: %s", itemid, title)
2017-02-19 02:30:06 +11:00
query = '''
UPDATE path
SET strPath = ?, strContent = ?, strScraper = ?, noUpdate = ?
WHERE idPath = ?
'''
kodicursor.execute(query, (toplevelpath,
"tvshows",
"metadata.local",
1,
toppathid))
# Link the path
query = "INSERT INTO tvshowlinkpath(idShow, idPath) values (?, ?)"
kodicursor.execute(query, (showid, pathid))
# Create the reference in plex table
plex_db.addReference(itemid,
v.PLEX_TYPE_SHOW,
2016-10-27 05:53:20 +11:00
showid,
v.KODI_TYPE_SHOW,
kodi_pathid=pathid,
2016-10-27 05:53:20 +11:00
checksum=checksum,
view_id=viewid)
2017-01-25 02:54:51 +11:00
if v.KODIVERSION >= 17:
# add new ratings Kodi 17
rating_id = self.kodi_db.get_ratingid(showid, v.KODI_TYPE_SHOW)
2017-02-19 02:30:06 +11:00
self.kodi_db.add_ratings(rating_id,
showid,
v.KODI_TYPE_SHOW,
"default",
rating,
2017-02-19 02:30:06 +11:00
votecount)
# add new uniqueid Kodi 17
2017-05-01 18:08:23 +10:00
if tvdb is not None:
uniqueid = self.kodi_db.get_uniqueid(showid,
v.KODI_TYPE_SHOW)
2017-05-01 18:08:23 +10:00
self.kodi_db.add_uniqueid(uniqueid,
showid,
v.KODI_TYPE_SHOW,
tvdb,
"unknown")
else:
uniqueid = -1
2017-02-19 02:30:06 +11:00
# Create the tvshow entry
query = '''
INSERT INTO tvshow(
idShow, c00, c01, c04, c05, c08, c09, c12, c13, c14,
c15)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
'''
2017-02-19 02:30:06 +11:00
kodicursor.execute(query, (showid, title, plot, rating_id,
premieredate, genre, title,
uniqueid, mpaa, studio, sorttitle))
2017-02-19 02:30:06 +11:00
else:
# Create the tvshow entry
query = '''
INSERT INTO tvshow(
idShow, c00, c01, c04, c05, c08, c09, c12, c13, c14,
c15)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
'''
2017-02-19 02:30:06 +11:00
kodicursor.execute(query, (showid, title, plot, rating,
premieredate, genre, title, tvdb,
mpaa, studio, sorttitle))
# Update the path
2017-02-19 02:30:06 +11:00
query = '''
UPDATE path
SET strPath = ?, strContent = ?, strScraper = ?, noUpdate = ?,
idParentPath = ?
WHERE idPath = ?
'''
kodicursor.execute(query, (path, None, None, 1, toppathid, pathid))
2017-02-19 02:30:06 +11:00
self.kodi_db.modify_people(showid, v.KODI_TYPE_SHOW, api.people_list())
self.kodi_db.modify_genres(showid, v.KODI_TYPE_SHOW, genres)
2018-03-04 23:39:18 +11:00
artwork.modify_artwork(api.artwork(),
showid,
v.KODI_TYPE_SHOW,
kodicursor)
# Process studios
self.kodi_db.modify_studios(showid, v.KODI_TYPE_SHOW, studios)
2016-03-02 02:28:48 +11:00
# Process tags: view, PMS collection tags
2016-01-12 01:56:56 +11:00
tags = [viewtag]
tags.extend(collections)
self.kodi_db.modify_tags(showid, v.KODI_TYPE_SHOW, tags)
2018-02-11 23:24:00 +11:00
@catch_exceptions(warnuser=True)
def add_updateSeason(self, item, viewtag=None, viewid=None):
2018-02-11 22:06:04 +11:00
"""
Process a single season of a certain tv show
"""
api = API(item)
2018-02-12 00:42:49 +11:00
plex_id = api.plex_id()
if not plex_id:
2018-02-11 22:06:04 +11:00
LOG.error('Error getting plex_id for season, skipping')
return
kodicursor = self.kodicursor
plex_db = self.plex_db
artwork = self.artwork
2018-02-12 00:42:49 +11:00
seasonnum = api.season_number()
2016-03-14 02:06:54 +11:00
# Get parent tv show Plex id
plexshowid = item.attrib.get('parentRatingKey')
# Get Kodi showid
plex_dbitem = plex_db.getItem_byId(plexshowid)
2016-03-14 02:06:54 +11:00
try:
showid = plex_dbitem[0]
2018-02-11 22:06:04 +11:00
except TypeError:
LOG.error('Could not find parent tv show for season %s. '
'Skipping season for now.', plex_id)
2016-03-14 02:06:54 +11:00
return
2016-04-26 22:41:58 +10:00
seasonid = self.kodi_db.addSeason(showid, seasonnum)
2018-02-12 00:42:49 +11:00
checksum = api.checksum()
2016-01-12 03:37:01 +11:00
# Check whether Season already exists
plex_dbitem = plex_db.getItem_byId(plex_id)
2018-02-11 22:06:04 +11:00
update_item = False if plex_dbitem is None else True
2016-01-12 03:37:01 +11:00
# Process artwork
2018-02-12 00:42:49 +11:00
allartworks = api.artwork()
2018-03-04 23:39:18 +11:00
artwork.modify_artwork(allartworks,
seasonid,
v.KODI_TYPE_SEASON,
kodicursor)
2016-01-12 03:37:01 +11:00
if update_item:
# Update a reference: checksum in plex table
plex_db.updateReference(plex_id, checksum)
2016-01-12 03:37:01 +11:00
else:
# Create the reference in plex table
plex_db.addReference(plex_id,
v.PLEX_TYPE_SEASON,
2016-08-31 00:40:11 +10:00
seasonid,
v.KODI_TYPE_SEASON,
parent_id=showid,
view_id=viewid,
2016-08-31 00:40:11 +10:00
checksum=checksum)
2018-02-11 23:24:00 +11:00
@catch_exceptions(warnuser=True)
2016-01-10 02:14:02 +11:00
def add_updateEpisode(self, item, viewtag=None, viewid=None):
"""
2018-02-11 22:06:04 +11:00
Process single episode
2016-01-10 02:14:02 +11:00
"""
kodicursor = self.kodicursor
plex_db = self.plex_db
artwork = self.artwork
2018-02-11 22:06:04 +11:00
api = API(item)
# If the item already exist in the local Kodi DB we'll perform a full
# item update
# If the item doesn't exist, we'll add it to the database
update_item = True
2018-02-12 00:42:49 +11:00
itemid = api.plex_id()
if not itemid:
2018-02-11 22:06:04 +11:00
LOG.error('Error getting itemid for episode, skipping')
return
plex_dbitem = plex_db.getItem_byId(itemid)
try:
episodeid = plex_dbitem[0]
fileid = plex_dbitem[1]
pathid = plex_dbitem[2]
except TypeError:
update_item = False
# episodeid
kodicursor.execute("select coalesce(max(idEpisode),0) from episode")
episodeid = kodicursor.fetchone()[0] + 1
else:
# Verification the item is still in Kodi
query = "SELECT * FROM episode WHERE idEpisode = ?"
kodicursor.execute(query, (episodeid,))
try:
kodicursor.fetchone()[0]
except TypeError:
# item is not found, let's recreate it.
update_item = False
2018-02-11 22:06:04 +11:00
LOG.info("episodeid: %s missing from Kodi, repairing entry.",
episodeid)
# fileId information
2018-02-12 00:42:49 +11:00
checksum = api.checksum()
dateadded = api.date_created()
userdata = api.userdata()
playcount = userdata['PlayCount']
dateplayed = userdata['LastPlayedDate']
2018-02-12 00:42:49 +11:00
tvdb = api.provider('tvdb')
votecount = None
# item details
2018-02-12 00:42:49 +11:00
peoples = api.people()
director = api.list_to_string(peoples['Director'])
writer = api.list_to_string(peoples['Writer'])
title, _ = api.titles()
plot = api.plot()
2016-04-02 19:31:21 +11:00
rating = userdata['Rating']
2018-02-12 00:42:49 +11:00
resume, runtime = api.resume_runtime()
premieredate = api.premiere_date()
# episode details
2018-02-12 00:42:49 +11:00
series_id, _, season, episode = api.episode_data()
2016-01-10 02:14:02 +11:00
if season is None:
2016-03-12 00:47:41 +11:00
season = -1
2016-04-20 19:09:01 +10:00
if episode is None:
episode = -1
2016-03-12 00:47:41 +11:00
# if item.get('AbsoluteEpisodeNumber'):
# # Anime scenario
# season = 1
# episode = item['AbsoluteEpisodeNumber']
# else:
# season = -1
2018-02-11 22:06:04 +11:00
# # Specials ordering within season
# if item.get('AirsAfterSeasonNumber'):
# airs_before_season = item['AirsAfterSeasonNumber']
# # Kodi default number for afterseason ordering
# airs_before_episode = 4096
# else:
# airs_before_season = item.get('AirsBeforeSeasonNumber')
# airs_before_episode = item.get('AirsBeforeEpisodeNumber')
airs_before_season = "-1"
airs_before_episode = "-1"
# Get season id
2018-02-11 22:06:04 +11:00
show = plex_db.getItem_byId(series_id)
try:
showid = show[0]
except TypeError:
2018-02-11 22:06:04 +11:00
LOG.error("Parent tvshow now found, skip item")
2016-01-30 06:07:21 +11:00
return False
seasonid = self.kodi_db.addSeason(showid, season)
# GET THE FILE AND PATH #####
2018-02-11 22:06:04 +11:00
do_indirect = not state.DIRECT_PATHS
2018-02-12 00:42:49 +11:00
playurl = api.file_path(force_first_media=True)
2017-05-17 23:42:12 +10:00
if state.DIRECT_PATHS:
# Direct paths is set the Kodi way
if playurl is None:
# Something went wrong, trying to use non-direct paths
2018-02-11 22:06:04 +11:00
do_indirect = True
else:
2018-02-12 00:42:49 +11:00
playurl = api.validate_playurl(playurl, api.plex_type())
if playurl is None:
return False
if "\\" in playurl:
# Local path
filename = playurl.rsplit("\\", 1)[1]
else:
# Network share
filename = playurl.rsplit("/", 1)[1]
path = playurl.replace(filename, "")
2018-02-11 22:06:04 +11:00
parent_path_id = self.kodi_db.getParentPathId(path)
if do_indirect:
2018-02-22 18:05:07 +11:00
# Set plugin path - do NOT use "intermediate" paths for the show
# as with direct paths!
2018-03-05 01:29:45 +11:00
path = 'plugin://%s.tvshows/%s/' % (v.ADDON_ID, series_id)
filename = ('%s?plex_id=%s&plex_type=%s&mode=play'
% (path, itemid, v.PLEX_TYPE_EPISODE))
playurl = filename
2018-03-05 01:29:45 +11:00
parent_path_id = self.kodi_db.getParentPathId(path)
# add/retrieve pathid and fileid
# if the path or file already exists, the calls return current value
2018-03-05 01:29:45 +11:00
pathid = self.kodi_db.add_video_path(path)
fileid = self.kodi_db.addFile(filename, pathid)
# UPDATE THE EPISODE #####
if update_item:
2018-02-11 22:06:04 +11:00
LOG.info("UPDATE episode itemid: %s", itemid)
# Update the movie entry
2017-02-03 01:23:54 +11:00
if v.KODIVERSION >= 17:
# update new ratings Kodi 17
2017-02-14 06:23:02 +11:00
ratingid = self.kodi_db.get_ratingid(episodeid,
v.KODI_TYPE_EPISODE)
self.kodi_db.update_ratings(episodeid,
v.KODI_TYPE_EPISODE,
"default",
rating,
votecount,
ratingid)
# update new uniqueid Kodi 17
2017-02-14 06:26:30 +11:00
uniqueid = self.kodi_db.get_uniqueid(episodeid,
v.KODI_TYPE_EPISODE)
self.kodi_db.update_uniqueid(episodeid,
v.KODI_TYPE_EPISODE,
tvdb,
"tvdb",
uniqueid)
2017-02-03 01:23:54 +11:00
query = '''
UPDATE episode
SET c00 = ?, c01 = ?, c03 = ?, c04 = ?, c05 = ?, c09 = ?,
c10 = ?, c12 = ?, c13 = ?, c14 = ?, c15 = ?, c16 = ?,
c18 = ?, c19 = ?, idFile=?, idSeason = ?,
userrating = ?
2017-02-03 22:34:14 +11:00
WHERE idEpisode = ?
2017-02-03 01:23:54 +11:00
'''
kodicursor.execute(query, (title, plot, rating, writer,
premieredate, runtime, director, season, episode, title,
2018-02-11 22:06:04 +11:00
airs_before_season, airs_before_episode, playurl, pathid,
2017-02-03 01:23:54 +11:00
fileid, seasonid, userdata['UserRating'], episodeid))
elif v.KODIVERSION == 16:
# Kodi Jarvis
query = '''
UPDATE episode
SET c00 = ?, c01 = ?, c03 = ?, c04 = ?, c05 = ?, c09 = ?,
c10 = ?, c12 = ?, c13 = ?, c14 = ?, c15 = ?, c16 = ?,
c18 = ?, c19 = ?, idFile=?, idSeason = ?
WHERE idEpisode = ?
'''
kodicursor.execute(query, (title, plot, rating, writer,
premieredate, runtime, director, season, episode, title,
2018-02-11 22:06:04 +11:00
airs_before_season, airs_before_episode, playurl, pathid,
fileid, seasonid, episodeid))
else:
2017-02-03 01:23:54 +11:00
query = '''
UPDATE episode
SET c00 = ?, c01 = ?, c03 = ?, c04 = ?, c05 = ?, c09 = ?,
c10 = ?, c12 = ?, c13 = ?, c14 = ?, c15 = ?, c16 = ?,
c18 = ?, c19 = ?, idFile = ?
WHERE idEpisode = ?
'''
kodicursor.execute(query, (title, plot, rating, writer,
premieredate, runtime, director, season, episode, title,
2018-02-11 22:06:04 +11:00
airs_before_season, airs_before_episode, playurl, pathid,
fileid, episodeid))
# Update parentid reference
plex_db.updateParentId(itemid, seasonid)
2017-02-03 01:23:54 +11:00
# OR ADD THE EPISODE #####
else:
2018-02-11 22:06:04 +11:00
LOG.info("ADD episode itemid: %s - Title: %s", itemid, title)
# Create the episode entry
2017-02-03 01:23:54 +11:00
if v.KODIVERSION >= 17:
# add new ratings Kodi 17
rating_id = self.kodi_db.get_ratingid(episodeid,
v.KODI_TYPE_EPISODE)
2017-02-18 05:35:51 +11:00
self.kodi_db.add_ratings(rating_id,
episodeid,
v.KODI_TYPE_EPISODE,
"default",
rating,
votecount)
# add new uniqueid Kodi 17
uniqueid = self.kodi_db.get_uniqueid(episodeid,
v.KODI_TYPE_EPISODE)
self.kodi_db.add_uniqueid(uniqueid,
episodeid,
v.KODI_TYPE_EPISODE,
tvdb,
"tvdb")
2017-02-03 01:23:54 +11:00
query = '''
INSERT INTO episode( idEpisode, idFile, c00, c01, c03, c04,
c05, c09, c10, c12, c13, c14, idShow, c15, c16, c18,
c19, idSeason, userrating)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,
?, ?)
'''
kodicursor.execute(query, (episodeid, fileid, title, plot,
2017-02-18 05:35:51 +11:00
rating_id, writer, premieredate, runtime, director, season,
2018-02-11 22:06:04 +11:00
episode, title, showid, airs_before_season,
airs_before_episode, playurl, pathid, seasonid,
2017-02-03 01:23:54 +11:00
userdata['UserRating']))
elif v.KODIVERSION == 16:
# Kodi Jarvis
query = '''
INSERT INTO episode( idEpisode, idFile, c00, c01, c03, c04,
c05, c09, c10, c12, c13, c14, idShow, c15, c16, c18,
c19, idSeason)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,
?)
'''
2017-02-03 01:23:54 +11:00
kodicursor.execute(query, (episodeid, fileid, title, plot,
rating, writer, premieredate, runtime, director, season,
2018-02-11 22:06:04 +11:00
episode, title, showid, airs_before_season,
airs_before_episode, playurl, pathid, seasonid))
else:
query = (
'''
INSERT INTO episode(
idEpisode, idFile, c00, c01, c03, c04, c05, c09, c10, c12, c13, c14,
idShow, c15, c16, c18, c19)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
'''
)
2018-02-11 22:06:04 +11:00
kodicursor.execute(query, (episodeid, fileid, title, plot,
rating, writer, premieredate, runtime, director, season,
episode, title, showid, airs_before_season,
airs_before_episode, playurl, pathid))
# Create or update the reference in plex table Add reference is
# idempotent; the call here updates also fileid and pathid when item is
# moved or renamed
plex_db.addReference(itemid,
v.PLEX_TYPE_EPISODE,
episodeid,
v.KODI_TYPE_EPISODE,
kodi_fileid=fileid,
kodi_pathid=pathid,
parent_id=seasonid,
checksum=checksum,
view_id=viewid)
2018-02-22 18:05:07 +11:00
# Update the path for Direct Paths only
if not do_indirect:
query = '''
UPDATE path
SET strPath = ?, strContent = ?, strScraper = ?, noUpdate = ?,
idParentPath = ?
WHERE idPath = ?
'''
kodicursor.execute(query, (path, None, None, 1, parent_path_id,
pathid))
# Update the file
query = ' '.join((
"UPDATE files",
"SET idPath = ?, strFilename = ?, dateAdded = ?",
"WHERE idFile = ?"
))
kodicursor.execute(query, (pathid, filename, dateadded, fileid))
# Process cast
self.kodi_db.modify_people(episodeid,
v.KODI_TYPE_EPISODE,
api.people_list())
# Process artwork
# Wide "screenshot" of particular episode
poster = item.attrib.get('thumb')
if poster:
2018-02-12 00:42:49 +11:00
poster = api.attach_plex_token_to_url(
"%s%s" % (self.server, poster))
2018-03-04 23:39:18 +11:00
artwork.modify_art(
poster, episodeid, v.KODI_TYPE_EPISODE, "thumb", kodicursor)
# Process stream details
2018-02-12 00:42:49 +11:00
streams = api.mediastreams()
2018-02-26 19:18:44 +11:00
self.kodi_db.modify_streams(fileid, streams, runtime)
# Process playstates
2018-02-11 22:06:04 +11:00
self.kodi_db.addPlaystate(fileid,
resume,
runtime,
playcount,
dateplayed)
def remove(self, itemid):
2018-02-11 22:06:04 +11:00
"""
Remove showid, fileid, pathid, plex reference
"""
plex_db = self.plex_db
kodicursor = self.kodicursor
plex_dbitem = plex_db.getItem_byId(itemid)
try:
kodiid = plex_dbitem[0]
fileid = plex_dbitem[1]
parentid = plex_dbitem[3]
mediatype = plex_dbitem[4]
2018-02-11 22:06:04 +11:00
LOG.info("Removing %s kodiid: %s fileid: %s",
mediatype, kodiid, fileid)
except TypeError:
return
##### PROCESS ITEM #####
# Remove the plex reference
plex_db.removeItem(itemid)
##### IF EPISODE #####
if mediatype == v.KODI_TYPE_EPISODE:
# Delete kodi episode and file, verify season and tvshow
self.removeEpisode(kodiid, fileid)
# Season verification
season = plex_db.getItem_byKodiId(parentid, v.KODI_TYPE_SEASON)
try:
showid = season[1]
except TypeError:
return
season_episodes = plex_db.getItem_byParentId(parentid,
v.KODI_TYPE_EPISODE)
if not season_episodes:
self.removeSeason(parentid)
plex_db.removeItem(season[0])
# Show verification
show = plex_db.getItem_byKodiId(showid, v.KODI_TYPE_SHOW)
query = ' '.join((
"SELECT totalCount",
"FROM tvshowcounts",
"WHERE idShow = ?"
))
kodicursor.execute(query, (showid,))
result = kodicursor.fetchone()
if result and result[0] is None:
# There's no episodes left, delete show and any possible remaining seasons
seasons = plex_db.getItem_byParentId(showid,
v.KODI_TYPE_SEASON)
for season in seasons:
self.removeSeason(season[1])
2017-05-09 03:32:12 +10:00
# Delete plex season entries
plex_db.removeItems_byParentId(showid,
v.KODI_TYPE_SEASON)
self.removeShow(showid)
plex_db.removeItem(show[0])
##### IF TVSHOW #####
elif mediatype == v.KODI_TYPE_SHOW:
# Remove episodes, seasons, tvshow
seasons = plex_db.getItem_byParentId(kodiid,
v.KODI_TYPE_SEASON)
for season in seasons:
seasonid = season[1]
season_episodes = plex_db.getItem_byParentId(
seasonid, v.KODI_TYPE_EPISODE)
for episode in season_episodes:
self.removeEpisode(episode[1], episode[2])
2017-05-09 03:32:12 +10:00
# Remove plex episodes
plex_db.removeItems_byParentId(seasonid,
v.KODI_TYPE_EPISODE)
# Remove plex seasons
plex_db.removeItems_byParentId(kodiid,
v.KODI_TYPE_SEASON)
# Remove tvshow
self.removeShow(kodiid)
##### IF SEASON #####
elif mediatype == v.KODI_TYPE_SEASON:
# Remove episodes, season, verify tvshow
season_episodes = plex_db.getItem_byParentId(kodiid,
v.KODI_TYPE_EPISODE)
for episode in season_episodes:
self.removeEpisode(episode[1], episode[2])
2017-05-09 03:32:12 +10:00
# Remove plex episodes
plex_db.removeItems_byParentId(kodiid, v.KODI_TYPE_EPISODE)
2018-02-11 22:06:04 +11:00
# Remove season
self.removeSeason(kodiid)
# Show verification
seasons = plex_db.getItem_byParentId(parentid, v.KODI_TYPE_SEASON)
if not seasons:
# There's no seasons, delete the show
self.removeShow(parentid)
plex_db.removeItem_byKodiId(parentid, v.KODI_TYPE_SHOW)
2018-02-11 22:06:04 +11:00
LOG.debug("Deleted %s: %s from kodi database", mediatype, itemid)
def removeShow(self, kodi_id):
2018-02-11 22:06:04 +11:00
"""
Remove a TV show, and only the show, no seasons or episodes
"""
kodicursor = self.kodicursor
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)
2018-03-04 23:39:18 +11:00
self.artwork.delete_artwork(kodi_id, v.KODI_TYPE_SHOW, kodicursor)
kodicursor.execute("DELETE FROM tvshow WHERE idShow = ?", (kodi_id,))
if v.KODIVERSION >= 17:
2017-02-03 03:09:20 +11:00
self.kodi_db.remove_uniqueid(kodi_id, v.KODI_TYPE_SHOW)
self.kodi_db.remove_ratings(kodi_id, v.KODI_TYPE_SHOW)
2018-02-11 22:06:04 +11:00
LOG.info("Removed tvshow: %s.", kodi_id)
def removeSeason(self, kodi_id):
2018-02-11 22:06:04 +11:00
"""
Remove a season, and only a season, not the show or episodes
"""
kodicursor = self.kodicursor
2018-03-04 23:39:18 +11:00
self.artwork.delete_artwork(kodi_id, "season", kodicursor)
kodicursor.execute("DELETE FROM seasons WHERE idSeason = ?",
(kodi_id,))
2018-02-11 22:06:04 +11:00
LOG.info("Removed season: %s.", kodi_id)
2018-02-26 19:33:13 +11:00
def removeEpisode(self, kodi_id, file_id):
2018-02-11 22:06:04 +11:00
"""
Remove an episode, and episode only
"""
kodicursor = self.kodicursor
self.kodi_db.modify_people(kodi_id, v.KODI_TYPE_EPISODE)
2018-02-26 19:33:13 +11:00
self.kodi_db.modify_streams(file_id)
self.kodi_db.delete_playstate(file_id)
2018-03-04 23:39:18 +11:00
self.artwork.delete_artwork(kodi_id, "episode", kodicursor)
kodicursor.execute("DELETE FROM episode WHERE idEpisode = ?",
(kodi_id,))
2018-02-26 19:33:13 +11:00
kodicursor.execute("DELETE FROM files WHERE idFile = ?", (file_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)
2018-02-11 22:06:04 +11:00
LOG.info("Removed episode: %s.", kodi_id)
class Music(Items):
2018-02-11 22:06:04 +11:00
"""
For Plex library-type music. Also works for premium music libraries
"""
def __enter__(self):
"""
OVERWRITE this method, because we need to open another DB.
Open DB connections and cursors
"""
2018-02-11 22:59:04 +11:00
self.plexconn = kodi_sql('plex')
self.plexcursor = self.plexconn.cursor()
# Here it is, not 'video' but 'music'
2018-02-11 22:59:04 +11:00
self.kodiconn = kodi_sql('music')
self.kodicursor = self.kodiconn.cursor()
self.plex_db = plexdb.Plex_DB_Functions(self.plexcursor)
2018-02-25 23:42:20 +11:00
self.kodi_db = kodidb.KodiDBMethods(self.kodicursor)
return self
2018-02-11 23:24:00 +11:00
@catch_exceptions(warnuser=True)
2018-02-11 22:06:04 +11:00
def add_updateArtist(self, item, viewtag=None, viewid=None):
"""
Adds a single artist
"""
kodicursor = self.kodicursor
plex_db = self.plex_db
artwork = self.artwork
2018-02-11 22:06:04 +11:00
api = API(item)
update_item = True
2018-02-12 00:42:49 +11:00
itemid = api.plex_id()
plex_dbitem = plex_db.getItem_byId(itemid)
try:
artistid = plex_dbitem[0]
except TypeError:
update_item = False
# The artist details #####
lastScraped = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
2018-02-12 00:42:49 +11:00
dateadded = api.date_created()
checksum = api.checksum()
2018-02-12 00:42:49 +11:00
name, _ = api.titles()
# musicBrainzId = api.provider('MusicBrainzArtist')
musicBrainzId = None
2018-02-12 00:42:49 +11:00
genres = ' / '.join(api.genre_list())
bio = api.plot()
# Associate artwork
2018-03-04 00:40:12 +11:00
artworks = api.artwork()
if 'poster' in artworks:
thumb = "<thumb>%s</thumb>" % artworks['poster']
else:
2018-03-04 00:40:12 +11:00
thumb = None
2018-03-05 00:22:39 +11:00
if 'fanart' in artworks:
fanart = "<fanart>%s</fanart>" % artworks['fanart']
2018-03-04 00:40:12 +11:00
else:
fanart = None
# UPDATE THE ARTIST #####
if update_item:
2018-02-11 22:06:04 +11:00
LOG.info("UPDATE artist itemid: %s - Name: %s", itemid, name)
# Update the checksum in plex table
plex_db.updateReference(itemid, checksum)
# OR ADD THE ARTIST #####
else:
2018-02-11 22:06:04 +11:00
LOG.info("ADD artist itemid: %s - Name: %s", itemid, name)
# safety checks: It looks like plex supports the same artist
# multiple times.
# Kodi doesn't allow that. In case that happens we just merge the
# artist entries.
artistid = self.kodi_db.addArtist(name, musicBrainzId)
# Create the reference in plex table
plex_db.addReference(itemid,
v.PLEX_TYPE_ARTIST,
artistid,
v.KODI_TYPE_ARTIST,
view_id=viewid,
checksum=checksum)
# Process the artist
2017-01-25 02:54:51 +11:00
if v.KODIVERSION >= 16:
2017-04-03 01:02:41 +10:00
query = '''
UPDATE artist
SET strGenres = ?, strBiography = ?, strImage = ?,
strFanart = ?, lastScraped = ?
WHERE idArtist = ?
'''
kodicursor.execute(query, (genres, bio, thumb, fanart,
lastScraped, artistid))
else:
2017-04-03 01:02:41 +10:00
query = '''
UPDATE artist
SET strGenres = ?, strBiography = ?, strImage = ?,
strFanart = ?, lastScraped = ?, dateAdded = ?
WHERE idArtist = ?
'''
kodicursor.execute(query, (genres, bio, thumb, fanart, lastScraped,
dateadded, artistid))
# Update artwork
2018-03-04 23:39:18 +11:00
artwork.modify_artwork(artworks,
artistid,
v.KODI_TYPE_ARTIST,
kodicursor)
2018-02-11 23:24:00 +11:00
@catch_exceptions(warnuser=True)
def add_updateAlbum(self, item, viewtag=None, viewid=None, children=None,
scan_children=True):
2017-04-03 01:02:41 +10:00
"""
2018-02-11 22:06:04 +11:00
Adds a single music album
children: list of child xml's, so in this case songs
2017-04-03 01:02:41 +10:00
"""
kodicursor = self.kodicursor
plex_db = self.plex_db
artwork = self.artwork
2018-02-11 22:06:04 +11:00
api = API(item)
update_item = True
2018-02-12 00:42:49 +11:00
itemid = api.plex_id()
if not itemid:
2018-02-11 22:06:04 +11:00
LOG.error('Error processing Album, skipping')
return
plex_dbitem = plex_db.getItem_byId(itemid)
try:
albumid = plex_dbitem[0]
except TypeError:
# Albumid not found
update_item = False
# The album details #####
lastScraped = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
2018-02-12 00:42:49 +11:00
dateadded = api.date_created()
userdata = api.userdata()
checksum = api.checksum()
2018-02-12 00:42:49 +11:00
name, _ = api.titles()
# musicBrainzId = api.provider('MusicBrainzAlbum')
musicBrainzId = None
2018-02-12 00:42:49 +11:00
year = api.year()
self.genres = api.genre_list()
2017-04-03 01:02:41 +10:00
self.genre = ' / '.join(self.genres)
2018-02-12 00:42:49 +11:00
bio = api.plot()
rating = userdata['UserRating']
2018-02-12 00:42:49 +11:00
studio = api.music_studio()
artistname = item.attrib.get('parentTitle')
if not artistname:
artistname = item.attrib.get('originalTitle')
2017-04-03 01:02:41 +10:00
# See if we have a compilation - Plex does NOT feature a compilation
# flag for albums
self.compilation = 0
for child in children:
if child.attrib.get('originalTitle') is not None:
self.compilation = 1
break
# Associate artwork
2018-03-04 00:40:12 +11:00
artworks = api.artwork()
if 'poster' in artworks:
thumb = "<thumb>%s</thumb>" % artworks['poster']
else:
thumb = None
# UPDATE THE ALBUM #####
if update_item:
2018-02-11 22:06:04 +11:00
LOG.info("UPDATE album itemid: %s - Name: %s", itemid, name)
# Update the checksum in plex table
plex_db.updateReference(itemid, checksum)
# OR ADD THE ALBUM #####
else:
2018-02-11 22:06:04 +11:00
LOG.info("ADD album itemid: %s - Name: %s", itemid, name)
# safety checks: It looks like plex supports the same artist
# multiple times.
# Kodi doesn't allow that. In case that happens we just merge the
# artist entries.
albumid = self.kodi_db.addAlbum(name, musicBrainzId)
# Create the reference in plex table
plex_db.addReference(itemid,
v.PLEX_TYPE_ALBUM,
albumid,
v.KODI_TYPE_ALBUM,
view_id=viewid,
checksum=checksum)
# Process the album info
2017-01-25 02:54:51 +11:00
if v.KODIVERSION >= 17:
# Kodi Krypton
2017-04-03 01:02:41 +10:00
query = '''
UPDATE album
SET strArtists = ?, iYear = ?, strGenres = ?, strReview = ?,
strImage = ?, iUserrating = ?, lastScraped = ?,
strReleaseType = ?, strLabel = ?, bCompilation = ?
WHERE idAlbum = ?
'''
kodicursor.execute(query, (artistname, year, self.genre, bio,
thumb, rating, lastScraped,
v.KODI_TYPE_ALBUM, studio,
self.compilation, albumid))
2017-01-25 02:54:51 +11:00
elif v.KODIVERSION == 16:
# Kodi Jarvis
2017-04-03 01:02:41 +10:00
query = '''
UPDATE album
SET strArtists = ?, iYear = ?, strGenres = ?, strReview = ?,
strImage = ?, iRating = ?, lastScraped = ?,
strReleaseType = ?, strLabel = ?, bCompilation = ?
WHERE idAlbum = ?
'''
kodicursor.execute(query, (artistname, year, self.genre, bio,
thumb, rating, lastScraped,
v.KODI_TYPE_ALBUM, studio,
self.compilation, albumid))
2017-01-25 02:54:51 +11:00
elif v.KODIVERSION == 15:
# Kodi Isengard
2017-04-03 01:02:41 +10:00
query = '''
UPDATE album
SET strArtists = ?, iYear = ?, strGenres = ?, strReview = ?,
strImage = ?, iRating = ?, lastScraped = ?, dateAdded = ?,
strReleaseType = ?, strLabel = ?
WHERE idAlbum = ?
'''
kodicursor.execute(query, (artistname, year, self.genre, bio,
thumb, rating, lastScraped, dateadded,
v.KODI_TYPE_ALBUM, studio, albumid))
else:
# Kodi Helix
2017-04-03 01:02:41 +10:00
query = '''
UPDATE album
SET strArtists = ?, iYear = ?, strGenres = ?, strReview = ?,
strImage = ?, iRating = ?, lastScraped = ?, dateAdded = ?,
strLabel = ?
WHERE idAlbum = ?
'''
kodicursor.execute(query, (artistname, year, self.genre, bio,
thumb, rating, lastScraped, dateadded,
studio, albumid))
# Associate the parentid for plex reference
2018-02-11 22:06:04 +11:00
parent_id = item.attrib.get('parentRatingKey')
if parent_id is not None:
plex_dbartist = plex_db.getItem_byId(parent_id)
try:
artistid = plex_dbartist[0]
except TypeError:
2018-02-11 22:06:04 +11:00
LOG.info('Artist %s does not exist in plex database',
parent_id)
artist = GetPlexMetadata(parent_id)
# Item may not be an artist, verification necessary.
if artist is not None and artist != 401:
2017-04-03 01:02:41 +10:00
if artist[0].attrib.get('type') == v.PLEX_TYPE_ARTIST:
2018-02-11 22:06:04 +11:00
# Update with the parent_id, for remove reference
plex_db.addReference(parent_id,
v.PLEX_TYPE_ARTIST,
2018-02-11 22:06:04 +11:00
parent_id,
v.KODI_TYPE_ARTIST,
view_id=viewid)
2018-02-11 22:06:04 +11:00
plex_db.updateParentId(itemid, parent_id)
else:
# Update plex reference with the artistid
plex_db.updateParentId(itemid, artistid)
# Assign main artists to album
# Plex unfortunately only supports 1 artist :-(
2018-02-11 22:06:04 +11:00
artist_id = parent_id
plex_dbartist = plex_db.getItem_byId(artist_id)
try:
artistid = plex_dbartist[0]
except TypeError:
# Artist does not exist in plex database, create the reference
2018-02-11 22:06:04 +11:00
LOG.info('Artist %s does not exist in Plex database', artist_id)
artist = GetPlexMetadata(artist_id)
if artist is not None and artist != 401:
2018-02-11 22:06:04 +11:00
self.add_updateArtist(artist[0])
plex_dbartist = plex_db.getItem_byId(artist_id)
artistid = plex_dbartist[0]
else:
# Best take this name over anything else.
query = "UPDATE artist SET strArtist = ? WHERE idArtist = ?"
kodicursor.execute(query, (artistname, artistid,))
2018-02-11 22:06:04 +11:00
LOG.info("UPDATE artist: strArtist: %s, idArtist: %s",
artistname, artistid)
# Add artist to album
2017-04-03 01:02:41 +10:00
query = '''
INSERT OR REPLACE INTO album_artist(idArtist, idAlbum, strArtist)
VALUES (?, ?, ?)
2017-04-03 01:02:41 +10:00
'''
kodicursor.execute(query, (artistid, albumid, artistname))
# Update discography
2017-04-03 01:02:41 +10:00
query = '''
INSERT OR REPLACE INTO discography(idArtist, strAlbum, strYear)
VALUES (?, ?, ?)
2017-04-03 01:02:41 +10:00
'''
kodicursor.execute(query, (artistid, name, year))
# Update plex reference with parentid
2018-02-11 22:06:04 +11:00
plex_db.updateParentId(artist_id, albumid)
# Add genres
2017-04-03 01:02:41 +10:00
self.kodi_db.addMusicGenres(albumid, self.genres, v.KODI_TYPE_ALBUM)
# Update artwork
2018-03-04 23:39:18 +11:00
artwork.modify_artwork(artworks, albumid, v.KODI_TYPE_ALBUM, kodicursor)
2017-04-03 01:02:41 +10:00
# Add all children - all tracks
if scan_children:
for child in children:
self.add_updateSong(child, viewtag, viewid)
2018-02-11 23:24:00 +11:00
@catch_exceptions(warnuser=True)
def add_updateSong(self, item, viewtag=None, viewid=None):
2018-02-11 22:06:04 +11:00
"""
Process single song
"""
kodicursor = self.kodicursor
plex_db = self.plex_db
artwork = self.artwork
2018-02-11 22:06:04 +11:00
api = API(item)
update_item = True
2018-02-12 00:42:49 +11:00
itemid = api.plex_id()
if not itemid:
2018-02-11 22:06:04 +11:00
LOG.error('Error processing Song; skipping')
return
plex_dbitem = plex_db.getItem_byId(itemid)
try:
songid = plex_dbitem[0]
pathid = plex_dbitem[2]
albumid = plex_dbitem[3]
except TypeError:
# Songid not found
update_item = False
kodicursor.execute("select coalesce(max(idSong),0) from song")
songid = kodicursor.fetchone()[0] + 1
# The song details #####
2018-02-12 00:42:49 +11:00
checksum = api.checksum()
dateadded = api.date_created()
userdata = api.userdata()
playcount = userdata['PlayCount']
2016-04-08 22:48:47 +10:00
if playcount is None:
# This is different to Video DB!
playcount = 0
dateplayed = userdata['LastPlayedDate']
# item details
2018-02-12 00:42:49 +11:00
title, _ = api.titles()
# musicBrainzId = api.provider('MusicBrainzTrackId')
musicBrainzId = None
2017-04-03 01:02:41 +10:00
try:
genres = self.genres
genre = self.genre
except AttributeError:
# No parent album - hence no genre information from Plex
genres = None
genre = None
try:
if self.compilation == 0:
artists = item.attrib.get('grandparentTitle')
else:
artists = item.attrib.get('originalTitle')
except AttributeError:
# compilation not set
artists = item.attrib.get('originalTitle',
item.attrib.get('grandparentTitle'))
tracknumber = int(item.attrib.get('index', 0))
disc = int(item.attrib.get('parentIndex', 1))
if disc == 1:
track = tracknumber
else:
track = disc*2**16 + tracknumber
2018-02-12 00:42:49 +11:00
year = api.year()
_, duration = api.resume_runtime()
2017-02-03 01:23:54 +11:00
rating = userdata['UserRating']
comment = None
2017-04-03 01:02:41 +10:00
# Moods
moods = []
for entry in item:
if entry.tag == 'Mood':
moods.append(entry.attrib['tag'])
mood = ' / '.join(moods)
# GET THE FILE AND PATH #####
2018-02-11 22:06:04 +11:00
do_indirect = not state.DIRECT_PATHS
2017-05-17 23:42:12 +10:00
if state.DIRECT_PATHS:
# Direct paths is set the Kodi way
2018-02-12 00:42:49 +11:00
playurl = api.file_path(force_first_media=True)
if playurl is None:
# Something went wrong, trying to use non-direct paths
2018-02-11 22:06:04 +11:00
do_indirect = True
else:
2018-02-12 00:42:49 +11:00
playurl = api.validate_playurl(playurl, api.plex_type())
if playurl is None:
return False
if "\\" in playurl:
# Local path
filename = playurl.rsplit("\\", 1)[1]
else:
# Network share
filename = playurl.rsplit("/", 1)[1]
path = playurl.replace(filename, "")
2018-02-11 22:06:04 +11:00
if do_indirect:
# Plex works a bit differently
path = "%s%s" % (self.server, item[0][0].attrib.get('key'))
2018-02-12 00:42:49 +11:00
path = api.attach_plex_token_to_url(path)
filename = path.rsplit('/', 1)[1]
path = path.replace(filename, '')
# UPDATE THE SONG #####
if update_item:
2018-02-11 22:06:04 +11:00
LOG.info("UPDATE song itemid: %s - Title: %s with path: %s",
itemid, title, path)
# Update path
# Use dummy strHash '123' for Kodi
query = "UPDATE path SET strPath = ?, strHash = ? WHERE idPath = ?"
kodicursor.execute(query, (path, '123', pathid))
# Update the song entry
2017-04-03 01:02:41 +10:00
query = '''
UPDATE song
SET idAlbum = ?, strArtists = ?, strGenres = ?, strTitle = ?,
iTrack = ?, iDuration = ?, iYear = ?, strFilename = ?,
iTimesPlayed = ?, lastplayed = ?, rating = ?, comment = ?,
mood = ?
WHERE idSong = ?
'''
kodicursor.execute(query, (albumid, artists, genre, title, track,
duration, year, filename, playcount,
2017-04-03 01:02:41 +10:00
dateplayed, rating, comment, mood,
songid))
# Update the checksum in plex table
plex_db.updateReference(itemid, checksum)
# OR ADD THE SONG #####
else:
2018-02-11 22:06:04 +11:00
LOG.info("ADD song itemid: %s - Title: %s", itemid, title)
# Add path
2018-03-05 01:29:45 +11:00
pathid = self.kodi_db.add_music_path(path, strHash="123")
try:
2016-01-01 15:19:36 +11:00
# Get the album
plex_dbalbum = plex_db.getItem_byId(
item.attrib.get('parentRatingKey'))
albumid = plex_dbalbum[0]
2016-01-01 15:19:36 +11:00
except KeyError:
2016-03-16 22:13:47 +11:00
# Verify if there's an album associated.
2016-03-17 21:17:30 +11:00
album_name = item.get('parentTitle')
2016-03-16 22:13:47 +11:00
if album_name:
2018-02-11 22:06:04 +11:00
LOG.info("Creating virtual music album for song: %s.",
itemid)
2017-04-03 01:02:41 +10:00
albumid = self.kodi_db.addAlbum(
album_name,
2018-02-12 00:42:49 +11:00
api.provider('MusicBrainzAlbum'))
plex_db.addReference("%salbum%s" % (itemid, albumid),
v.PLEX_TYPE_ALBUM,
albumid,
v.KODI_TYPE_ALBUM,
view_id=viewid)
2016-03-16 22:13:47 +11:00
else:
# No album Id associated to the song.
2018-02-11 22:06:04 +11:00
LOG.error("Song itemid: %s has no albumId associated.",
itemid)
2016-03-16 22:13:47 +11:00
return False
except TypeError:
# No album found. Let's create it
2018-02-11 22:06:04 +11:00
LOG.info("Album database entry missing.")
plex_album_id = item.attrib.get('parentRatingKey')
album = GetPlexMetadata(plex_album_id)
if album is None or album == 401:
2018-02-11 22:06:04 +11:00
LOG.error('Could not download album, abort')
return
self.add_updateAlbum(album[0],
children=[item],
scan_children=False)
2018-02-11 22:06:04 +11:00
plex_dbalbum = plex_db.getItem_byId(plex_album_id)
try:
albumid = plex_dbalbum[0]
2018-02-11 22:06:04 +11:00
LOG.debug("Found albumid: %s", albumid)
except TypeError:
# No album found, create a single's album
2018-02-11 22:06:04 +11:00
LOG.info("Failed to add album. Creating singles.")
2017-04-03 01:02:41 +10:00
kodicursor.execute(
"select coalesce(max(idAlbum),0) from album")
albumid = kodicursor.fetchone()[0] + 1
2017-01-25 02:54:51 +11:00
if v.KODIVERSION >= 16:
# Kodi Jarvis
2017-04-03 01:02:41 +10:00
query = '''
INSERT INTO album(
idAlbum, strGenres, iYear, strReleaseType)
VALUES (?, ?, ?, ?)
2017-04-03 01:02:41 +10:00
'''
kodicursor.execute(query,
(albumid, genre, year, "single"))
2017-01-25 02:54:51 +11:00
elif v.KODIVERSION == 15:
# Kodi Isengard
2017-04-03 01:02:41 +10:00
query = '''
INSERT INTO album(
idAlbum, strGenres, iYear, dateAdded,
strReleaseType)
VALUES (?, ?, ?, ?, ?)
2017-04-03 01:02:41 +10:00
'''
kodicursor.execute(query, (albumid, genre, year,
dateadded, "single"))
else:
# Kodi Helix
2017-04-03 01:02:41 +10:00
query = '''
INSERT INTO album(
idAlbum, strGenres, iYear, dateAdded)
VALUES (?, ?, ?, ?)
2017-04-03 01:02:41 +10:00
'''
kodicursor.execute(query, (albumid, genre, year,
dateadded))
# Create the song entry
2017-04-03 01:02:41 +10:00
query = '''
INSERT INTO song(
2017-04-03 01:02:41 +10:00
idSong, idAlbum, idPath, strArtists, strGenres, strTitle,
iTrack, iDuration, iYear, strFileName,
strMusicBrainzTrackID, iTimesPlayed, lastplayed,
rating, iStartOffset, iEndOffset, mood)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
'''
kodicursor.execute(
query, (songid, albumid, pathid, artists, genre, title, track,
duration, year, filename, musicBrainzId, playcount,
2017-04-03 01:02:41 +10:00
dateplayed, rating, 0, 0, mood))
# Create the reference in plex table
plex_db.addReference(itemid,
v.PLEX_TYPE_SONG,
songid,
v.KODI_TYPE_SONG,
kodi_pathid=pathid,
parent_id=albumid,
checksum=checksum,
view_id=viewid)
# Link song to album
2017-04-03 01:02:41 +10:00
query = '''
INSERT OR REPLACE INTO albuminfosong(
idAlbumInfoSong, idAlbumInfo, iTrack, strTitle, iDuration)
VALUES (?, ?, ?, ?, ?)
2017-04-03 01:02:41 +10:00
'''
kodicursor.execute(query, (songid, albumid, track, title, duration))
2016-03-17 21:17:30 +11:00
2016-03-16 22:13:47 +11:00
# Link song to artists
2018-02-11 22:06:04 +11:00
artist_loop = [{
2016-03-17 21:17:30 +11:00
'Name': item.attrib.get('grandparentTitle'),
'Id': item.attrib.get('grandparentRatingKey')
}]
# for index, artist in enumerate(item['ArtistItems']):
2018-02-11 22:06:04 +11:00
for index, artist in enumerate(artist_loop):
2016-03-16 22:13:47 +11:00
artist_name = artist['Name']
artist_eid = artist['Id']
artist_edb = plex_db.getItem_byId(artist_eid)
2016-03-16 22:13:47 +11:00
try:
artistid = artist_edb[0]
except TypeError:
# Artist is missing from plex database, add it.
2018-02-11 22:06:04 +11:00
artist_xml = GetPlexMetadata(artist_eid)
if artist_xml is None or artist_xml == 401:
LOG.error('Error getting artist, abort')
return
2018-02-11 22:06:04 +11:00
self.add_updateArtist(artist_xml[0])
artist_edb = plex_db.getItem_byId(artist_eid)
2016-03-16 22:13:47 +11:00
artistid = artist_edb[0]
finally:
2017-01-25 02:54:51 +11:00
if v.KODIVERSION >= 17:
# Kodi Krypton
2017-04-03 01:02:41 +10:00
query = '''
INSERT OR REPLACE INTO song_artist(
idArtist, idSong, idRole, iOrder, strArtist)
VALUES (?, ?, ?, ?, ?)
2017-04-03 01:02:41 +10:00
'''
kodicursor.execute(query, (artistid, songid, 1, index,
artist_name))
# May want to look into only doing this once?
2017-04-03 01:02:41 +10:00
query = '''
INSERT OR REPLACE INTO role(idRole, strRole)
VALUES (?, ?)
2017-04-03 01:02:41 +10:00
'''
kodicursor.execute(query, (1, 'Composer'))
else:
2017-04-03 01:02:41 +10:00
query = '''
INSERT OR REPLACE INTO song_artist(
idArtist, idSong, iOrder, strArtist)
VALUES (?, ?, ?, ?)
2017-04-03 01:02:41 +10:00
'''
kodicursor.execute(query, (artistid, songid, index,
artist_name))
# Add genres
2017-04-03 01:02:41 +10:00
if genres:
self.kodi_db.addMusicGenres(songid, genres, v.KODI_TYPE_SONG)
2018-03-04 23:39:18 +11:00
artworks = api.artwork()
artwork.modify_artwork(artworks, songid, v.KODI_TYPE_SONG, kodicursor)
2016-03-17 21:17:30 +11:00
if item.get('parentKey') is None:
2016-03-16 22:13:47 +11:00
# Update album artwork
2018-03-04 23:39:18 +11:00
artwork.modify_artwork(artworks, albumid, v.KODI_TYPE_ALBUM, kodicursor)
2016-03-16 22:13:47 +11:00
def remove(self, itemid):
2018-02-11 22:06:04 +11:00
"""
Remove kodiid, fileid, pathid, plex reference
"""
plex_db = self.plex_db
plex_dbitem = plex_db.getItem_byId(itemid)
try:
kodiid = plex_dbitem[0]
mediatype = plex_dbitem[4]
2018-02-11 22:06:04 +11:00
LOG.info("Removing %s kodiid: %s", mediatype, kodiid)
except TypeError:
return
##### PROCESS ITEM #####
# Remove the plex reference
plex_db.removeItem(itemid)
##### IF SONG #####
if mediatype == v.KODI_TYPE_SONG:
# Delete song
self.removeSong(kodiid)
2016-03-16 22:13:47 +11:00
# This should only address single song scenario, where server doesn't actually
2018-02-11 22:06:04 +11:00
# create an album for the song.
plex_db.removeWildItem(itemid)
2016-03-16 22:13:47 +11:00
for item in plex_db.getItem_byWildId(itemid):
2016-03-16 22:13:47 +11:00
item_kid = item[0]
item_mediatype = item[1]
if item_mediatype == v.KODI_TYPE_ALBUM:
childs = plex_db.getItem_byParentId(item_kid,
v.KODI_TYPE_SONG)
2016-03-16 22:13:47 +11:00
if not childs:
# Delete album
self.removeAlbum(item_kid)
##### IF ALBUM #####
elif mediatype == v.KODI_TYPE_ALBUM:
# Delete songs, album
album_songs = plex_db.getItem_byParentId(kodiid,
v.KODI_TYPE_SONG)
for song in album_songs:
self.removeSong(song[1])
2018-02-11 22:06:04 +11:00
# Remove plex songs
plex_db.removeItems_byParentId(kodiid,
v.KODI_TYPE_SONG)
# Remove the album
self.removeAlbum(kodiid)
##### IF ARTIST #####
elif mediatype == v.KODI_TYPE_ARTIST:
# Delete songs, album, artist
albums = plex_db.getItem_byParentId(kodiid,
v.KODI_TYPE_ALBUM)
for album in albums:
albumid = album[1]
album_songs = plex_db.getItem_byParentId(albumid,
v.KODI_TYPE_SONG)
for song in album_songs:
self.removeSong(song[1])
2018-02-11 22:06:04 +11:00
# Remove plex song
plex_db.removeItems_byParentId(albumid,
v.KODI_TYPE_SONG)
# Remove plex artist
plex_db.removeItems_byParentId(albumid,
v.KODI_TYPE_ARTIST)
# Remove kodi album
self.removeAlbum(albumid)
# Remove plex albums
plex_db.removeItems_byParentId(kodiid,
v.KODI_TYPE_ALBUM)
# Remove artist
self.removeArtist(kodiid)
2018-02-11 22:06:04 +11:00
LOG.info("Deleted %s: %s from kodi database", mediatype, itemid)
def removeSong(self, kodiid):
2018-02-11 22:06:04 +11:00
"""
Remove song, and only the song
"""
2018-03-04 23:39:18 +11:00
self.artwork.delete_artwork(kodiid, v.KODI_TYPE_SONG, self.kodicursor)
2016-08-31 00:40:11 +10:00
self.kodicursor.execute("DELETE FROM song WHERE idSong = ?",
(kodiid,))
def removeAlbum(self, kodiid):
2018-02-11 22:06:04 +11:00
"""
Remove an album, and only the album
"""
2018-03-04 23:39:18 +11:00
self.artwork.delete_artwork(kodiid, v.KODI_TYPE_ALBUM, self.kodicursor)
2016-08-31 00:40:11 +10:00
self.kodicursor.execute("DELETE FROM album WHERE idAlbum = ?",
(kodiid,))
def removeArtist(self, kodiid):
2018-02-11 22:06:04 +11:00
"""
Remove an artist, and only the artist
"""
2018-03-04 23:39:18 +11:00
self.artwork.delete_artwork(kodiid,
v.KODI_TYPE_ARTIST,
self.kodicursor)
2016-08-31 00:40:11 +10:00
self.kodicursor.execute("DELETE FROM artist WHERE idArtist = ?",
(kodiid,))