mirror of
https://github.com/jellyfin/jellyfin-kodi.git
synced 2024-12-27 03:06:10 +00:00
407 lines
14 KiB
Python
407 lines
14 KiB
Python
# -*- coding: utf-8 -*-
|
|
|
|
##################################################################################################
|
|
|
|
import logging
|
|
import urllib
|
|
|
|
import api
|
|
import common
|
|
import embydb_functions as embydb
|
|
import kodidb_functions as kodidb
|
|
from utils import window, language as lang, catch_except
|
|
|
|
##################################################################################################
|
|
|
|
log = logging.getLogger("EMBY."+__name__)
|
|
|
|
##################################################################################################
|
|
|
|
|
|
class MusicVideos(common.Items):
|
|
|
|
|
|
def __init__(self, embycursor, kodicursor, pdialog=None):
|
|
|
|
self.embycursor = embycursor
|
|
self.emby_db = embydb.Embydb_Functions(self.embycursor)
|
|
self.kodicursor = kodicursor
|
|
self.kodi_db = kodidb.Kodidb_Functions(self.kodicursor)
|
|
self.pdialog = pdialog
|
|
|
|
common.Items.__init__(self)
|
|
|
|
def _get_func(self, item_type, action):
|
|
|
|
if item_type == "MusicVideo":
|
|
actions = {
|
|
'added': self.added,
|
|
'update': self.add_update,
|
|
'userdata': self.updateUserdata,
|
|
'remove': self.remove
|
|
}
|
|
else:
|
|
log.info("Unsupported item_type: %s", item_type)
|
|
actions = {}
|
|
|
|
return actions.get(action)
|
|
|
|
def compare_all(self):
|
|
pdialog = self.pdialog
|
|
# Pull the list of musicvideos in Kodi
|
|
views = self.emby_db.getView_byType('musicvideos')
|
|
log.info("Media folders: %s", views)
|
|
|
|
try:
|
|
all_kodimvideos = dict(self.emby_db.get_checksum('MusicVideo'))
|
|
except ValueError:
|
|
all_kodimvideos = {}
|
|
|
|
all_embymvideosIds = set()
|
|
updatelist = []
|
|
|
|
for view in views:
|
|
|
|
if self.should_stop():
|
|
return False
|
|
|
|
# Get items per view
|
|
viewId = view['id']
|
|
viewName = view['name']
|
|
|
|
if pdialog:
|
|
pdialog.update(
|
|
heading=lang(29999),
|
|
message="%s %s..." % (lang(33028), viewName))
|
|
|
|
all_embymvideos = self.emby.getMusicVideos(viewId, basic=True, dialog=pdialog)
|
|
for embymvideo in all_embymvideos['Items']:
|
|
|
|
if self.should_stop():
|
|
return False
|
|
|
|
API = api.API(embymvideo)
|
|
itemid = embymvideo['Id']
|
|
all_embymvideosIds.add(itemid)
|
|
|
|
|
|
if all_kodimvideos.get(itemid) != API.get_checksum():
|
|
# Only update if musicvideo is not in Kodi or checksum is different
|
|
updatelist.append(itemid)
|
|
|
|
log.info("MusicVideos to update for %s: %s", viewName, updatelist)
|
|
embymvideos = self.emby.getFullItems(updatelist)
|
|
self.total = len(updatelist)
|
|
del updatelist[:]
|
|
|
|
|
|
if pdialog:
|
|
pdialog.update(heading="Processing %s / %s items" % (viewName, self.total))
|
|
|
|
self.count = 0
|
|
for embymvideo in embymvideos:
|
|
# Process individual musicvideo
|
|
if self.should_stop():
|
|
return False
|
|
self.title = embymvideo['Name']
|
|
self.update_pdialog()
|
|
self.add_update(embymvideo, view)
|
|
self.count += 1
|
|
|
|
##### PROCESS DELETES #####
|
|
|
|
for kodimvideo in all_kodimvideos:
|
|
if kodimvideo not in all_embymvideosIds:
|
|
self.remove(kodimvideo)
|
|
|
|
log.info("MusicVideos compare finished.")
|
|
return True
|
|
|
|
|
|
def added(self, items, total=None, view=None):
|
|
for item in super(MusicVideos, self).added(items, total, True):
|
|
if self.add_update(item, view):
|
|
self.content_pop(item.get('Name', "unknown"))
|
|
|
|
@catch_except
|
|
def add_update(self, item, view=None):
|
|
# Process single music video
|
|
kodicursor = self.kodicursor
|
|
emby_db = self.emby_db
|
|
artwork = self.artwork
|
|
API = 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
|
|
itemid = item['Id']
|
|
emby_dbitem = emby_db.getItem_byId(itemid)
|
|
try:
|
|
mvideoid = emby_dbitem[0]
|
|
fileid = emby_dbitem[1]
|
|
pathid = emby_dbitem[2]
|
|
log.info("mvideoid: %s fileid: %s pathid: %s", mvideoid, fileid, pathid)
|
|
|
|
except TypeError:
|
|
update_item = False
|
|
log.debug("mvideoid: %s not found", itemid)
|
|
# mvideoid
|
|
kodicursor.execute("select coalesce(max(idMVideo),0) from musicvideo")
|
|
mvideoid = kodicursor.fetchone()[0] + 1
|
|
|
|
else:
|
|
# Verification the item is still in Kodi
|
|
query = "SELECT * FROM musicvideo WHERE idMVideo = ?"
|
|
kodicursor.execute(query, (mvideoid,))
|
|
try:
|
|
kodicursor.fetchone()[0]
|
|
except TypeError:
|
|
# item is not found, let's recreate it.
|
|
update_item = False
|
|
log.info("mvideoid: %s missing from Kodi, repairing the entry.", mvideoid)
|
|
|
|
if not view:
|
|
# Get view tag from emby
|
|
viewtag, viewid, mediatype = self.emby.getView_embyId(itemid)
|
|
log.debug("View tag found: %s", viewtag)
|
|
else:
|
|
viewtag = view['name']
|
|
viewid = view['id']
|
|
|
|
# fileId information
|
|
checksum = API.get_checksum()
|
|
dateadded = API.get_date_created()
|
|
userdata = API.get_userdata()
|
|
playcount = userdata['PlayCount']
|
|
dateplayed = userdata['LastPlayedDate']
|
|
|
|
# item details
|
|
runtime = API.get_runtime()
|
|
plot = API.get_overview()
|
|
title = item['Name']
|
|
year = item.get('ProductionYear')
|
|
genres = item['Genres']
|
|
genre = " / ".join(genres)
|
|
studios = API.get_studios()
|
|
studio = " / ".join(studios)
|
|
artist = " / ".join(item.get('Artists'))
|
|
album = item.get('Album')
|
|
track = item.get('Track')
|
|
people = API.get_people()
|
|
director = " / ".join(people['Director'])
|
|
|
|
|
|
##### GET THE FILE AND PATH #####
|
|
playurl = API.get_file_path()
|
|
|
|
if "\\" in playurl:
|
|
# Local path
|
|
filename = playurl.rsplit("\\", 1)[1]
|
|
else: # Network share
|
|
filename = playurl.rsplit("/", 1)[1]
|
|
|
|
if self.direct_path:
|
|
# Direct paths is set the Kodi way
|
|
if not self.path_validation(playurl):
|
|
return False
|
|
|
|
path = playurl.replace(filename, "")
|
|
window('emby_pathverified', value="true")
|
|
else:
|
|
# Set plugin path and media flags using real filename
|
|
path = "plugin://plugin.video.emby.musicvideos/"
|
|
params = {
|
|
|
|
'filename': filename.encode('utf-8'),
|
|
'id': itemid,
|
|
'dbid': mvideoid,
|
|
'mode': "play"
|
|
}
|
|
filename = "%s?%s" % (path, urllib.urlencode(params))
|
|
|
|
|
|
##### UPDATE THE MUSIC VIDEO #####
|
|
if update_item:
|
|
log.info("UPDATE mvideo itemid: %s - Title: %s", itemid, title)
|
|
|
|
# Update path
|
|
query = "UPDATE path SET strPath = ? WHERE idPath = ?"
|
|
kodicursor.execute(query, (path, pathid))
|
|
|
|
# Update the filename
|
|
query = "UPDATE files SET strFilename = ?, dateAdded = ? WHERE idFile = ?"
|
|
kodicursor.execute(query, (filename, dateadded, fileid))
|
|
|
|
# Update the music video entry
|
|
query = ' '.join((
|
|
|
|
"UPDATE musicvideo",
|
|
"SET c00 = ?, c04 = ?, c05 = ?, c06 = ?, c07 = ?, c08 = ?, c09 = ?, c10 = ?,",
|
|
"c11 = ?, c12 = ?"
|
|
"WHERE idMVideo = ?"
|
|
))
|
|
kodicursor.execute(query, (title, runtime, director, studio, year, plot, album,
|
|
artist, genre, track, mvideoid))
|
|
# Update the checksum in emby table
|
|
emby_db.updateReference(itemid, checksum)
|
|
|
|
##### OR ADD THE MUSIC VIDEO #####
|
|
else:
|
|
log.info("ADD mvideo itemid: %s - Title: %s", itemid, title)
|
|
|
|
# Add path
|
|
query = ' '.join((
|
|
|
|
"SELECT idPath",
|
|
"FROM path",
|
|
"WHERE strPath = ?"
|
|
))
|
|
kodicursor.execute(query, (path,))
|
|
try:
|
|
pathid = kodicursor.fetchone()[0]
|
|
except TypeError:
|
|
kodicursor.execute("select coalesce(max(idPath),0) from path")
|
|
pathid = kodicursor.fetchone()[0] + 1
|
|
query = (
|
|
'''
|
|
INSERT OR REPLACE INTO path(
|
|
idPath, strPath, strContent, strScraper, noUpdate)
|
|
|
|
VALUES (?, ?, ?, ?, ?)
|
|
'''
|
|
)
|
|
kodicursor.execute(query, (pathid, path, "musicvideos", "metadata.local", 1))
|
|
|
|
# Add the file
|
|
kodicursor.execute("select coalesce(max(idFile),0) from files")
|
|
fileid = kodicursor.fetchone()[0] + 1
|
|
query = (
|
|
'''
|
|
INSERT INTO files(
|
|
idFile, idPath, strFilename, dateAdded)
|
|
|
|
VALUES (?, ?, ?, ?)
|
|
'''
|
|
)
|
|
kodicursor.execute(query, (fileid, pathid, filename, dateadded))
|
|
|
|
# Create the musicvideo entry
|
|
query = (
|
|
'''
|
|
INSERT INTO musicvideo(
|
|
idMVideo, idFile, c00, c04, c05, c06, c07, c08, c09, c10, c11, c12)
|
|
|
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
'''
|
|
)
|
|
kodicursor.execute(query, (mvideoid, fileid, title, runtime, director, studio,
|
|
year, plot, album, artist, genre, track))
|
|
|
|
# Create the reference in emby table
|
|
emby_db.addReference(itemid, mvideoid, "MusicVideo", "musicvideo", fileid, pathid,
|
|
checksum=checksum, mediafolderid=viewid)
|
|
|
|
# Process cast
|
|
people = item['People']
|
|
artists = item['ArtistItems']
|
|
for artist in artists:
|
|
artist['Type'] = "Artist"
|
|
people.extend(artists)
|
|
people = artwork.get_people_artwork(people)
|
|
self.kodi_db.addPeople(mvideoid, people, "musicvideo")
|
|
# Process genres
|
|
self.kodi_db.addGenres(mvideoid, genres, "musicvideo")
|
|
# Process artwork
|
|
artwork.add_artwork(artwork.get_all_artwork(item), mvideoid, "musicvideo", kodicursor)
|
|
# Process stream details
|
|
streams = API.get_media_streams()
|
|
self.kodi_db.addStreams(fileid, streams, runtime)
|
|
# Process studios
|
|
self.kodi_db.addStudios(mvideoid, studios, "musicvideo")
|
|
# Process tags: view, emby tags
|
|
tags = [viewtag]
|
|
tags.extend(item['Tags'])
|
|
if userdata['Favorite']:
|
|
tags.append("Favorite musicvideos")
|
|
self.kodi_db.addTags(mvideoid, tags, "musicvideo")
|
|
# Process playstates
|
|
resume = API.adjust_resume(userdata['Resume'])
|
|
total = round(float(runtime), 6)
|
|
self.kodi_db.addPlaystate(fileid, resume, total, playcount, dateplayed)
|
|
|
|
return True
|
|
|
|
def updateUserdata(self, item):
|
|
# This updates: Favorite, LastPlayedDate, Playcount, PlaybackPositionTicks
|
|
# Poster with progress bar
|
|
emby_db = self.emby_db
|
|
API = api.API(item)
|
|
|
|
# Get emby information
|
|
itemid = item['Id']
|
|
checksum = API.get_checksum()
|
|
userdata = API.get_userdata()
|
|
runtime = API.get_runtime()
|
|
|
|
# Get Kodi information
|
|
emby_dbitem = emby_db.getItem_byId(itemid)
|
|
try:
|
|
mvideoid = emby_dbitem[0]
|
|
fileid = emby_dbitem[1]
|
|
log.info("Update playstate for musicvideo: %s fileid: %s", item['Name'], fileid)
|
|
except TypeError:
|
|
return
|
|
|
|
# Process favorite tags
|
|
if userdata['Favorite']:
|
|
self.kodi_db.addTag(mvideoid, "Favorite musicvideos", "musicvideo")
|
|
else:
|
|
self.kodi_db.removeTag(mvideoid, "Favorite musicvideos", "musicvideo")
|
|
|
|
# Process playstates
|
|
playcount = userdata['PlayCount']
|
|
dateplayed = userdata['LastPlayedDate']
|
|
resume = API.adjust_resume(userdata['Resume'])
|
|
total = round(float(runtime), 6)
|
|
|
|
self.kodi_db.addPlaystate(fileid, resume, total, playcount, dateplayed)
|
|
emby_db.updateReference(itemid, checksum)
|
|
|
|
def remove(self, itemid):
|
|
# Remove mvideoid, fileid, pathid, emby reference
|
|
emby_db = self.emby_db
|
|
kodicursor = self.kodicursor
|
|
artwork = self.artwork
|
|
|
|
emby_dbitem = emby_db.getItem_byId(itemid)
|
|
try:
|
|
mvideoid = emby_dbitem[0]
|
|
fileid = emby_dbitem[1]
|
|
pathid = emby_dbitem[2]
|
|
log.info("Removing mvideoid: %s fileid: %s pathid: %s", mvideoid, fileid, pathid)
|
|
except TypeError:
|
|
return
|
|
|
|
# Remove artwork
|
|
query = ' '.join((
|
|
|
|
"SELECT url, type",
|
|
"FROM art",
|
|
"WHERE media_id = ?",
|
|
"AND media_type = 'musicvideo'"
|
|
))
|
|
kodicursor.execute(query, (mvideoid,))
|
|
for row in kodicursor.fetchall():
|
|
|
|
url = row[0]
|
|
imagetype = row[1]
|
|
if imagetype in ("poster", "fanart"):
|
|
artwork.delete_cached_artwork(url)
|
|
|
|
kodicursor.execute("DELETE FROM musicvideo WHERE idMVideo = ?", (mvideoid,))
|
|
kodicursor.execute("DELETE FROM files WHERE idFile = ?", (fileid,))
|
|
if self.direct_path:
|
|
kodicursor.execute("DELETE FROM path WHERE idPath = ?", (pathid,))
|
|
self.embycursor.execute("DELETE FROM emby WHERE emby_id = ?", (itemid,))
|
|
|
|
log.info("Deleted musicvideo %s from kodi database", itemid)
|