Merge remote-tracking branch 'MediaBrowser/master' into develop

This commit is contained in:
tomkat83 2016-03-17 10:03:00 +01:00
commit a16b2bdeb3
10 changed files with 528 additions and 344 deletions

View file

@ -94,15 +94,15 @@ if __name__ == '__main__':
ret = xbmcgui.Dialog().select(header, options)
if ret != -1:
if options[ret] == utils.language(30402):
API.updateUserRating(embyid, deletelike=True)
emby.updateUserRating(embyid, deletelike=True)
if options[ret] == utils.language(30403):
API.updateUserRating(embyid, like=True)
emby.updateUserRating(embyid, like=True)
if options[ret] == utils.language(30404):
API.updateUserRating(embyid, like=False)
emby.updateUserRating(embyid, like=False)
if options[ret] == utils.language(30405):
API.updateUserRating(embyid, favourite=True)
emby.updateUserRating(embyid, favourite=True)
if options[ret] == utils.language(30406):
API.updateUserRating(embyid, favourite=False)
emby.updateUserRating(embyid, favourite=False)
if options[ret] == utils.language(30407):
kodiconn = utils.kodiSQL('music')
kodicursor = kodiconn.cursor()
@ -117,7 +117,7 @@ if __name__ == '__main__':
musicutils.updateRatingToFile(newvalue, API.getFilePath())
if utils.settings('enableExportSongRating') == "true":
like, favourite, deletelike = musicutils.getEmbyRatingFromKodiRating(newvalue)
API.updateUserRating(embyid, like, favourite, deletelike)
emby.updateUserRating(embyid, like, favourite, deletelike)
query = ' '.join(( "UPDATE song","SET rating = ?", "WHERE idSong = ?" ))
kodicursor.execute(query, (newvalue,itemid,))
kodiconn.commit()

View file

@ -1,240 +0,0 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<strings>
<string id="30000">Primaire server adres:</string>
<string id="30001">Enkele mappen automatisch openen:</string>
<string id="30002">Afspelen van stream ipv SMB:</string>
<string id="30004">Log niveau:</string>
<string id="30005">Gebruikersnaam: </string>
<string id="30006">Wachtwoord: </string>
<string id="30007">Samba gebruikersnaam: </string>
<string id="30008">Samba wachtwoord: </string>
<string id="30009">Transcode: </string>
<string id="30010">Prestatie profilering inschakelen:</string>
<string id="30011">Lokale cache systeem</string>
<string id="30014">Emby</string>
<string id="30015">Netwerk</string>
<string id="30016">Apparaatnaam</string>
<string id="30022">Geavanceerd</string>
<string id="30024">Gebruikersnaam:</string>
<string id="30025">Wachtwoord:</string>
<string id="30026">Gebruik SIMPLEJSON ipv JSON</string>
<string id="30030">Poortnummer:</string>
<string id="30036">Aantal recente films die getoond worden:</string>
<string id="30037">Aantal recente TV-series die getoond worden:</string>
<string id="30035">Aantal recente muziekalbums die getoond worden:</string>
<string id="30038">Markeer als bekeken bij starten van afspelen:</string>
<string id="30039">Gebruik seizoen poster bij afleveringen</string>
<string id="30040">Genre filter ...</string>
<string id="30041">Speel alles vanaf hier</string>
<string id="30042">Vernieuwen</string>
<string id="30043">Wissen</string>
<string id="30046">Voeg film toe aan CouchPotato</string>
<string id="30044">Ongeldige gebruikersnaam/wachtwoord</string>
<string id="30045">Gebruikersnaam niet gevonden</string>
<string id="30052">Wissen...</string>
<string id="30053">Wacht op server voor wissen</string>
<string id="30059">Server standaard</string>
<string id="30060">Titel</string>
<string id="30061">Jaar</string>
<string id="30062">Premiere datum</string>
<string id="30063">Datum toegevoegd</string>
<string id="30064">Critici beoordeling</string>
<string id="30065">Community beoordeling</string>
<string id="30066">Aantal keer bekeken</string>
<string id="30067">Budget</string>
<string id="30068">Sorteer op</string>
<string id="30069">Geen</string>
<string id="30070">Actie</string>
<string id="30071">Avontuur</string>
<string id="30072">Animatie</string>
<string id="30073">Misdaad</string>
<string id="30074">Comedy</string>
<string id="30075">Documentaire</string>
<string id="30076">Drama</string>
<string id="30077">Fantasie</string>
<string id="30078">Nederlands</string>
<string id="30079">Historie</string>
<string id="30080">Horror</string>
<string id="30081">Muziek</string>
<string id="30082">Musical</string>
<string id="30083">Mysterie</string>
<string id="30084">Romantiek</string>
<string id="30085">Science Fiction</string>
<string id="30086">Kort</string>
<string id="30087">Spanning</string>
<string id="30088">Thriller</string>
<string id="30089">Western</string>
<string id="30090">Genre filter</string>
<string id="30091">Bevestig wissen</string>
<string id="30092">Dit item wissen ? Dit zal het bestand volledig verwijderen.</string>
<string id="30093">Markeer als bekeken</string>
<string id="30094">Mark als onbekeken</string>
<string id="30095">Voeg toe aan favorieten</string>
<string id="30096">Verwijder uit favorieten</string>
<string id="30097">Sorteer op...</string>
<string id="30098">Sorteer oplopend</string>
<string id="30099">Sorteer aflopend</string>
<string id="30100">Toon acteurs</string>
<!-- resume dialog -->
<string id="30105">Hervatten</string>
<string id="30106">Hervatten vanaf</string>
<string id="30107">Start vanaf begin</string>
<string id="30110">Interface</string>
<string id="30111">Inclusief stream info</string>
<string id="30112">Inclusief personen</string>
<string id="30113">Inclusief filminfo</string>
<string id="30114">Bij hervatten aantal seconden terugspringen</string>
<string id="30115">Markeer als bekeken wanneer na percentage gestopt</string>
<string id="30116">Inclusief aantal en afspeel tellers</string>
<string id="30117"> - Achtergrond plaatjes verversen (secondes)</string>
<string id="30118">Inclusief hervat-percentage</string>
<string id="30119">Afleveringnummer tonen in titel</string>
<string id="30120">Toon voortgang</string>
<string id="30121">Laden van content</string>
<string id="30122">Retrieving Data</string>
<string id="30123">Parsing Jason Data</string>
<string id="30124">Downloading Jason Data</string>
<string id="30125">Done</string>
<string id="30126">Processing Item : </string>
<string id="30127">Toon wismogelijkheid na bekijken van aflevering</string>
<string id="30128">Afspeelfout!</string>
<string id="30129">Dit item kan niet worden afgespeeld</string>
<string id="30130">Lockaal pad gedetecteerd</string>
<string id="30131">De MB3 bibliotheek bevat lokale paden. U moet UNC-paden gebruiken of afspelen van stream inschakelen. Pad: </string>
<string id="30132">Waarschuwing</string>
<string id="30133">Debug logging ingeschakeld.</string>
<string id="30134">Dit heeft effect op de performance.</string>
<string id="30135">Fout</string>
<string id="30136">XBMB3C service werkt niet</string>
<string id="30137">Herstart XBMC aub</string>
<string id="30138">Zoeken</string>
<string id="30139">Schakel Themamuziek in (vereist herstart)</string>
<string id="30140"> - Herhalen van themamuziek</string>
<string id="30141">Activeer achtergrondafbeelding (vereist herstart)</string>
<string id="30142">Services</string>
<string id="30143">Activeer Info Loader (vereist herstart)</string>
<string id="30144">Activeer Menu Loader (vereist herstart)</string>
<string id="30145">Activeer WebSocket Remote (vereist herstart)</string>
<string id="30146">Activeer In Progress Loader (vereist herstart)</string>
<string id="30147">Activeer Recent Info Loader (vereist herstart)</string>
<string id="30148">Activeer Random Loader (vereist herstart)</string>
<string id="30149">Activeer Next Up Loader (vereist herstart)</string>
<string id="30150">Skin ondersteund het vastleggen van views niet</string>
<string id="30151">Selecteer item actie (vereist herstart)</string>
<string id="30152">Toon indactors</string>
<string id="30153"> - Toon bekeken indator</string>
<string id="30154"> - Toon aantal onbekeken indicator</string>
<string id="30155"> - Toon afspeel-percentage indicator</string>
<string id="30156">Sorteer volgende (NextUp) op titel</string>
<string id="30157">Deactiveer speciale afbeeldingen (bv CoverArt)</string>
<string id="30158">Metadata</string>
<string id="30159">Afbeeldingen</string>
<string id="30160">Video kwaliteit</string>
<string id="30161">Activeer Suggested Loader (vereist herstart)</string>
<string id="30162">Seizoen tonen in titel</string>
<string id="30163">Seizoenen verbergen</string>
<string id="30164">Direct Play - HTTP</string>
<string id="30165">Direct Play</string>
<string id="30166">Transcoding</string>
<string id="30167">Server Detection Succeeded</string>
<string id="30168">Found server</string>
<string id="30169">Address : </string>
<string id="30170">Recent toegevoegde TV-series</string>
<string id="30171">Niet afgekeken TV-series</string>
<string id="30172">Alle Muziek</string>
<string id="30173">Kanalen</string>
<string id="30174">Recent toegevoegde films</string>
<string id="30175">Recent toegevoegde afleveringen</string>
<string id="30176">Recent toegevoegde albums</string>
<string id="30177">Niet afgekeken films</string>
<string id="30178">Niet afgekeken afleveringen</string>
<string id="30179">NextUp afleveringen</string>
<string id="30180">Favoriete films</string>
<string id="30181">Favoriete TV-series</string>
<string id="30182">Favoriete afleveringen</string>
<string id="30183">Vaak afgespeelde albums</string>
<string id="30184">Upcoming TV</string>
<string id="30185">BoxSets</string>
<string id="30186">Trailers</string>
<string id="30187">Muziek videos</string>
<string id="30188">Fotos</string>
<string id="30189">Onbekeken films</string>
<string id="30191">Film Studios</string>
<string id="30192">Film Acteurs</string>
<string id="30193">Onbekeken afleveringen</string>
<string id="30194">TV Genres</string>
<string id="30195">TV Networks</string>
<string id="30196">TV Acteurs</string>
<string id="30197">Afspeellijsten</string>
<string id="30198">Zoeken</string>
<string id="30199">Views instellen</string>
<string id="30200">Selecteer gebruiker</string>
<string id="30201">Profilering ingeschakeld.</string>
<string id="30202">Svp onthouden om weer uit te schakelen na het testen.</string>
<string id="30203">Error in ArtworkRotationThread</string>
<string id="30204">Kan niet verbinden met server</string>
<string id="30205">Error in LoadMenuOptionsThread</string>
<string id="30206">Activeer Playlists Loader (vereist herstart)</string>
<string id="30207">Liedjes</string>
<string id="30208">Albums</string>
<string id="30209">Album artiesten</string>
<string id="30210">Artiesten</string>
<string id="30211">Muziek Genres</string>
<string id="30212">Schakel Themavideos in (vereist herstart)</string>
<string id="30213"> - Herhalen van themavideos</string>
<string id="30214">Schakel het forceren van view uit</string>
<string id="30215">Schakel snelle modus in (beta)</string>
<string id="30216">Automatisch resterende afleveringen in een seizoen afspelen</string>
<string id="30217">Boxsets tonen in de overzichten (vereist herstart)</string>
<string id="30218">Afbeeldingen comprimeren</string>
<string id="30219">Activeer Skin Helper (vereust herstart)</string>
<string id="30220">Laatste </string>
<string id="30221">Bezig </string>
<string id="30222">Volgende </string>
<string id="30223">Gebruikerweergaven </string>
<!-- Default views -->
<string id="30300">Actief</string>
<string id="30301">Herstel standaard</string>
<string id="30302">Films</string>
<string id="30303">BoxSets</string>
<string id="30304">Trailers</string>
<string id="30305">Series</string>
<string id="30306">Seizoenen</string>
<string id="30307">Afleveringen</string>
<string id="30308">Muziek - artiesten</string>
<string id="30309">Muziek - albums</string>
<string id="30310">Muziekvideos</string>
<string id="30311">Muziek - liedjes</string>
<string id="30312">Kanalen</string>
</strings>

View file

@ -500,7 +500,7 @@ def getAllArtwork(self, item, parentInfo=False):
server = self.server
id = item['Id']
itemid = item['Id']
artworks = item['ImageTags']
backdrops = item.get('BackdropImageTags',[])
@ -526,15 +526,12 @@ def getAllArtwork(self, item, parentInfo=False):
}
# Process backdrops
backdropIndex = 0
for backdroptag in backdrops:
for index, tag in enumerate(backdrops):
artwork = (
"%s/emby/Items/%s/Images/Backdrop/%s?"
"MaxWidth=%s&MaxHeight=%s&Format=original&Tag=%s%s"
% (server, id, backdropIndex,
maxWidth, maxHeight, backdroptag, customquery))
% (server, itemid, index, maxWidth, maxHeight, tag, customquery))
allartworks['Backdrop'].append(artwork)
backdropIndex += 1
# Process the rest of the artwork
for art in artworks:
@ -544,7 +541,7 @@ def getAllArtwork(self, item, parentInfo=False):
artwork = (
"%s/emby/Items/%s/Images/%s/0?"
"MaxWidth=%s&MaxHeight=%s&Format=original&Tag=%s%s"
% (server, id, art, maxWidth, maxHeight, tag, customquery))
% (server, itemid, art, maxWidth, maxHeight, tag, customquery))
allartworks[art] = artwork
# Process parent items if the main item is missing artwork
@ -558,15 +555,12 @@ def getAllArtwork(self, item, parentInfo=False):
# If there is a parentId, go through the parent backdrop list
parentbackdrops = item['ParentBackdropImageTags']
backdropIndex = 0
for parentbackdroptag in parentbackdrops:
for index, tag in enumerate(parentbackdrops):
artwork = (
"%s/emby/Items/%s/Images/Backdrop/%s?"
"MaxWidth=%s&MaxHeight=%s&Format=original&Tag=%s%s"
% (server, parentId, backdropIndex,
maxWidth, maxHeight, parentbackdroptag, customquery))
% (server, parentId, index, maxWidth, maxHeight, tag, customquery))
allartworks['Backdrop'].append(artwork)
backdropIndex += 1
# Process the rest of the artwork
parentartwork = ['Logo', 'Art', 'Thumb']

269
resources/lib/connect.py Normal file
View file

@ -0,0 +1,269 @@
# -*- coding: utf-8 -*-
##################################################################################################
import json
import requests
import logging
import utils
import clientinfo
##################################################################################################
# Disable requests logging
from requests.packages.urllib3.exceptions import InsecureRequestWarning, InsecurePlatformWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
requests.packages.urllib3.disable_warnings(InsecurePlatformWarning)
#logging.getLogger('requests').setLevel(logging.WARNING)
##################################################################################################
class ConnectUtils():
# Borg - multiple instances, shared state
_shared_state = {}
clientInfo = clientinfo.ClientInfo()
addonName = clientInfo.getAddonName()
# Requests session
c = None
timeout = 30
def __init__(self):
self.__dict__ = self._shared_state
def logMsg(self, msg, lvl=1):
className = self.__class__.__name__
utils.logMsg("%s %s" % (self.addonName, className), msg, lvl)
def setUserId(self, userId):
# Reserved for userclient only
self.userId = userId
self.logMsg("Set connect userId: %s" % userId, 2)
def setServer(self, server):
# Reserved for userclient only
self.server = server
self.logMsg("Set connect server: %s" % server, 2)
def setToken(self, token):
# Reserved for userclient only
self.token = token
self.logMsg("Set connect token: %s" % token, 2)
def startSession(self):
log = self.logMsg
self.deviceId = self.clientInfo.getDeviceId()
# User is identified from this point
# Attach authenticated header to the session
verify = False
header = self.getHeader()
# If user enabled host certificate verification
try:
verify = self.sslverify
if self.sslclient is not None:
verify = self.sslclient
except:
log("Could not load SSL settings.", 1)
# Start session
self.c = requests.Session()
self.c.headers = header
self.c.verify = verify
# Retry connections to the server
self.c.mount("http://", requests.adapters.HTTPAdapter(max_retries=1))
self.c.mount("https://", requests.adapters.HTTPAdapter(max_retries=1))
log("Requests session started on: %s" % self.server, 1)
def stopSession(self):
try:
self.c.close()
except Exception as e:
self.logMsg("Requests session could not be terminated: %s" % e, 1)
def getHeader(self, authenticate=True):
clientInfo = self.clientInfo
version = clientInfo.getVersion()
if not authenticate:
# If user is not authenticated
header = {
'X-Application': "Kodi/%s" % version,
'Content-type': 'application/x-www-form-urlencoded; charset=UTF-8',
'Accept': "application/json"
}
self.logMsg("Header: %s" % header, 1)
else:
token = self.token
# Attached to the requests session
header = {
'Content-type': 'application/x-www-form-urlencoded; charset=UTF-8',
'Accept': "application/json",
'X-Application': "Kodi/%s" % version,
'X-Connect-UserToken': token
}
self.logMsg("Header: %s" % header, 1)
return header
def doUrl(self, url, data=None, postBody=None, rtype="GET",
parameters=None, authenticate=True, timeout=None):
log = self.logMsg
window = utils.window
log("=== ENTER connectUrl ===", 2)
default_link = ""
if timeout is None:
timeout = self.timeout
# Get requests session
try:
# If connect user is authenticated
if authenticate:
try:
c = self.c
# Replace for the real values
url = url.replace("{server}", self.server)
url = url.replace("{UserId}", self.userId)
# Prepare request
if rtype == "GET":
r = c.get(url, json=postBody, params=parameters, timeout=timeout)
elif rtype == "POST":
r = c.post(url, data=data, timeout=timeout)
elif rtype == "DELETE":
r = c.delete(url, json=postBody, timeout=timeout)
except AttributeError:
# request session does not exists
self.server = "https://connect.emby.media/service"
self.userId = window('embyco_currUser')
self.token = window('embyco_accessToken%s' % self.userId)
header = self.getHeader()
verifyssl = False
# If user enables ssl verification
try:
verifyssl = self.sslverify
if self.sslclient is not None:
verifyssl = self.sslclient
except AttributeError:
pass
# Prepare request
if rtype == "GET":
r = requests.get(url,
json=postBody,
params=parameters,
headers=header,
timeout=timeout,
verify=verifyssl)
elif rtype == "POST":
r = requests.post(url,
data=data,
headers=header,
timeout=timeout,
verify=verifyssl)
# If user is not authenticated
else:
header = self.getHeader(authenticate=False)
verifyssl = False
# If user enables ssl verification
try:
verifyssl = self.sslverify
if self.sslclient is not None:
verifyssl = self.sslclient
except AttributeError:
pass
# Prepare request
if rtype == "GET":
r = requests.get(url,
json=postBody,
params=parameters,
headers=header,
timeout=timeout,
verify=verifyssl)
elif rtype == "POST":
r = requests.post(url,
data=data,
headers=header,
timeout=timeout,
verify=verifyssl)
##### THE RESPONSE #####
log(r.url, 1)
log(r, 1)
if r.status_code == 204:
# No body in the response
log("====== 204 Success ======", 1)
elif r.status_code == requests.codes.ok:
try:
# UNICODE - JSON object
r = r.json()
log("====== 200 Success ======", 1)
log("Response: %s" % r, 1)
return r
except:
if r.headers.get('content-type') != "text/html":
log("Unable to convert the response for: %s" % url, 1)
else:
r.raise_for_status()
##### EXCEPTIONS #####
except requests.exceptions.ConnectionError as e:
# Make the addon aware of status
pass
except requests.exceptions.ConnectTimeout as e:
log("Server timeout at: %s" % url, 0)
log(e, 1)
except requests.exceptions.HTTPError as e:
if r.status_code == 401:
# Unauthorized
pass
elif r.status_code in (301, 302):
# Redirects
pass
elif r.status_code == 400:
# Bad requests
pass
except requests.exceptions.SSLError as e:
log("Invalid SSL certificate for: %s" % url, 0)
log(e, 1)
except requests.exceptions.RequestException as e:
log("Unknown error connecting to: %s" % url, 0)
log(e, 1)
return default_link

View file

@ -184,6 +184,21 @@ class Embydb_Functions():
return item
except: return None
def getItem_byWildId(self, embyid):
embycursor = self.embycursor
query = ' '.join((
"SELECT kodi_id, media_type",
"FROM emby",
"WHERE emby_id LIKE ?"
))
embycursor.execute(query, (embyid+"%",))
items = embycursor.fetchall()
return items
def getItem_byView(self, mediafolderid):
embycursor = self.embycursor
@ -358,3 +373,9 @@ class Embydb_Functions():
query = "DELETE FROM emby WHERE emby_id = ?"
self.embycursor.execute(query, (embyid,))
def removeWildItem(self, embyid):
query = "DELETE FROM emby WHERE emby_id LIKE ?"
self.embycursor.execute(query, (embyid+"%",))

View file

@ -2008,6 +2008,7 @@ class Music(Items):
# Process single song
kodiversion = self.kodiversion
kodicursor = self.kodicursor
emby = self.emby
emby_db = self.emby_db
kodi_db = self.kodi_db
artwork = self.artwork
@ -2132,14 +2133,22 @@ class Music(Items):
item.attrib.get('parentRatingKey'))
albumid = emby_dbalbum[0]
except KeyError:
# No album Id associated to the song.
self.logMsg("Song itemid: %s has no albumId." % itemid, 1)
return
# Verify if there's an album associated.
album_name = item.get('Album')
if album_name:
self.logMsg("Creating virtual music album for song: %s." % itemid, 1)
albumid = kodi_db.addAlbum(album_name, API.getProvider('MusicBrainzAlbum'))
emby_db.addReference("%salbum%s" % (itemid, albumid), albumid, "MusicAlbum_", "album")
else:
# No album Id associated to the song.
self.logMsg("Song itemid: %s has no albumId associated." % itemid, 1)
return False
except TypeError:
# No album found. Let's create it
self.logMsg("Album database entry missing.", 1)
emby_albumId = item.attrib.get('parentRatingKey')
album = GetPlexMetadata(emby_albumId)
album = emby.getItem(emby_albumId)
self.add_updateAlbum(album)
emby_dbalbum = emby_db.getItem_byId(emby_albumId)
try:
@ -2214,43 +2223,47 @@ class Music(Items):
'''
)
kodicursor.execute(query, (songid, albumid, track, title, duration))
# Verify if album has artists
addArtist = False
query = ' '.join((
# Link song to artists
for index, artist in enumerate(item['ArtistItems']):
"SELECT strArtists",
"FROM album",
"WHERE idAlbum = ?"
))
kodicursor.execute(query, (albumid,))
result = kodicursor.fetchone()
if result and result[0] == "":
addArtist = True
artist_name = artist['Name']
artist_eid = artist['Id']
artist_edb = emby_db.getItem_byId(artist_eid)
try:
artistid = artist_edb[0]
except TypeError:
# Artist is missing from emby database, add it.
artist_full = emby.getItem(artist_eid)
self.add_updateArtist(artist_full)
artist_edb = emby_db.getItem_byId(artist_eid)
artistid = artist_edb[0]
finally:
query = (
'''
INSERT OR REPLACE INTO song_artist(idArtist, idSong, iOrder, strArtist)
# if item['AlbumArtists']:
# album_artists = item['AlbumArtists']
# else:
# album_artists = item['ArtistItems']
VALUES (?, ?, ?, ?)
'''
)
kodicursor.execute(query, (artistid, songid, index, artist_name))
# Link song to artist
artist_name = item.attrib.get('grandparentTitle')
emby_dbartist = emby_db.getItem_byId(
item.attrib.get('grandparentRatingKey'))
try:
artistid = emby_dbartist[0]
except:
pass
else:
query = (
'''
INSERT OR REPLACE INTO song_artist(idArtist, idSong, strArtist)
# Verify if album artist exists
album_artists = []
for artist in item['AlbumArtists']:
VALUES (?, ?, ?)
'''
)
kodicursor.execute(query, (artistid, songid, artist_name))
if addArtist:
artist_name = artist['Name']
album_artists.append(artist_name)
artist_eid = artist['Id']
artist_edb = emby_db.getItem_byId(artist_eid)
try:
artistid = artist_edb[0]
except TypeError:
# Artist is missing from emby database, add it.
artist_full = emby.getItem(artist_eid)
self.add_updateArtist(artist_full)
artist_edb = emby_db.getItem_byId(artist_eid)
artistid = artist_edb[0]
finally:
query = (
'''
INSERT OR REPLACE INTO album_artist(idArtist, idAlbum, strArtist)
@ -2259,17 +2272,101 @@ class Music(Items):
'''
)
kodicursor.execute(query, (artistid, albumid, artist_name))
# Update discography
if item.get('Album'):
query = (
'''
INSERT OR REPLACE INTO discography(idArtist, strAlbum, strYear)
if addArtist:
query = "UPDATE album SET strArtists = ? WHERE idAlbum = ?"
kodicursor.execute(query, (artist_name, albumid))
VALUES (?, ?, ?)
'''
)
kodicursor.execute(query, (artistid, item['Album'], 0))
else:
album_artists = " / ".join(album_artists)
query = ' '.join((
"SELECT strArtists",
"FROM album",
"WHERE idAlbum = ?"
))
kodicursor.execute(query, (albumid,))
result = kodicursor.fetchone()
if result and result[0] != album_artists:
# Field is empty
if kodiversion in (16, 17):
# Kodi Jarvis, Krypton
query = "UPDATE album SET strArtists = ? WHERE idAlbum = ?"
kodicursor.execute(query, (album_artists, albumid))
elif kodiversion == 15:
# Kodi Isengard
query = "UPDATE album SET strArtists = ? WHERE idAlbum = ?"
kodicursor.execute(query, (album_artists, albumid))
else:
# Kodi Helix
query = "UPDATE album SET strArtists = ? WHERE idAlbum = ?"
kodicursor.execute(query, (album_artists, albumid))
# Add genres
kodi_db.addMusicGenres(songid, genres, "song")
# Update artwork
allart = API.getAllArtwork(parentInfo=True)
artwork.addArtwork(allart, songid, "song", kodicursor)
if item.get('AlbumId') is None:
# Update album artwork
artwork.addArtwork(allart, albumid, "album", kodicursor)
def updateUserdata(self, item):
# This updates: Favorite, LastPlayedDate, Playcount, PlaybackPositionTicks
# Poster with progress bar
kodicursor = self.kodicursor
emby_db = self.emby_db
kodi_db = self.kodi_db
API = api.API(item)
# Get emby information
itemid = item['Id']
checksum = API.getChecksum()
userdata = API.getUserData()
runtime = API.getRuntime()
rating = userdata['UserRating']
# Get Kodi information
emby_dbitem = emby_db.getItem_byId(itemid)
try:
kodiid = emby_dbitem[0]
mediatype = emby_dbitem[4]
self.logMsg("Update playstate for %s: %s" % (mediatype, item['Name']), 1)
except TypeError:
return
if mediatype == "song":
#should we ignore this item ?
#happens when userdata updated by ratings method
if utils.window("ignore-update-%s" %itemid):
utils.window("ignore-update-%s" %itemid,clear=True)
return
# Process playstates
playcount = userdata['PlayCount']
dateplayed = userdata['LastPlayedDate']
#process item ratings
rating, comment, hasEmbeddedCover = musicutils.getAdditionalSongTags(itemid, rating, API, kodicursor, emby_db, self.enableimportsongrating, self.enableexportsongrating, self.enableupdatesongrating)
query = "UPDATE song SET iTimesPlayed = ?, lastplayed = ?, rating = ? WHERE idSong = ?"
kodicursor.execute(query, (playcount, dateplayed, rating, kodiid))
elif mediatype == "album":
# Process playstates
query = "UPDATE album SET iRating = ? WHERE idAlbum = ?"
kodicursor.execute(query, (rating, kodiid))
emby_db.updateReference(itemid, checksum)
def remove(self, itemid):
# Remove kodiid, fileid, pathid, emby reference
emby_db = self.emby_db
@ -2295,6 +2392,21 @@ class Music(Items):
if mediatype == "song":
# Delete song
self.removeSong(kodiid)
# This should only address single song scenario, where server doesn't actually
# create an album for the song.
customitems = emby_db.getItem_byWildId(itemid)
emby_db.removeWildItem(itemid)
for item in customitems:
item_kid = item[0]
item_mediatype = item[1]
if item_mediatype == "album":
childs = emby_db.getItem_byParentId(item_kid, "song")
if not childs:
# Delete album
self.removeAlbum(item_kid)
##### IF ALBUM #####

View file

@ -1157,6 +1157,7 @@ class Kodidb_Functions():
def addAlbum(self, name, musicbrainz):
kodiversion = self.kodiversion
cursor = self.cursor
query = ' '.join((
@ -1172,14 +1173,24 @@ class Kodidb_Functions():
# Create the album
cursor.execute("select coalesce(max(idAlbum),0) from album")
albumid = cursor.fetchone()[0] + 1
query = (
'''
INSERT INTO album(idAlbum, strAlbum, strMusicBrainzAlbumID)
if kodiversion in (15, 16, 17):
query = (
'''
INSERT INTO album(idAlbum, strAlbum, strMusicBrainzAlbumID, strReleaseType)
VALUES (?, ?, ?)
'''
)
cursor.execute(query, (albumid, name, musicbrainz))
VALUES (?, ?, ?, ?)
'''
)
cursor.execute(query, (albumid, name, musicbrainz, "album"))
else: # Helix
query = (
'''
INSERT INTO album(idAlbum, strAlbum, strMusicBrainzAlbumID)
VALUES (?, ?, ?)
'''
)
cursor.execute(query, (albumid, name, musicbrainz))
return albumid

View file

@ -3,13 +3,19 @@
#################################################################################################
import os
import xbmc, xbmcaddon, xbmcvfs
import utils
import xbmc
import xbmcaddon
import xbmcvfs
from mutagen.flac import FLAC, Picture
from mutagen.id3 import ID3
from mutagen import id3
import base64
import read_embyserver as embyserver
import utils
#################################################################################################
# Helper for the music library, intended to fix missing song ID3 tags on Emby
@ -62,6 +68,9 @@ def getEmbyRatingFromKodiRating(rating):
return(like, favourite, deletelike)
def getAdditionalSongTags(embyid, emby_rating, API, kodicursor, emby_db, enableimportsongrating, enableexportsongrating, enableupdatesongrating):
emby = embyserver.Read_EmbyServer()
previous_values = None
filename = API.getFilePath()
rating = 0
@ -163,7 +172,7 @@ def getAdditionalSongTags(embyid, emby_rating, API, kodicursor, emby_db, enablei
# sync details to emby server. Translation needed between ID3 rating and emby likes/favourites:
like, favourite, deletelike = getEmbyRatingFromKodiRating(rating)
utils.window("ignore-update-%s" %embyid, "true") #set temp windows prop to ignore the update from webclient update
API.updateUserRating(embyid, like, favourite, deletelike)
emby.updateUserRating(embyid, like, favourite, deletelike)
return (rating, comment, hasEmbeddedCover)

View file

@ -562,4 +562,29 @@ class Read_EmbyServer():
if mediatype:
sorted_items.setdefault(mediatype, []).append(item)
return sorted_items
return sorted_items
def updateUserRating(self, itemid, like=None, favourite=None, deletelike=False):
# Updates the user rating to Emby
doUtils = self.doUtils
if favourite:
url = "{server}/emby/Users/{UserId}/FavoriteItems/%s?format=json" % itemid
doUtils(url, type="POST")
elif favourite == False:
url = "{server}/emby/Users/{UserId}/FavoriteItems/%s?format=json" % itemid
doUtils(url, type="DELETE")
if not deletelike and like:
url = "{server}/emby/Users/{UserId}/Items/%s/Rating?Likes=true&format=json" % itemid
doUtils(url, type="POST")
elif not deletelike and like == False:
url = "{server}/emby/Users/{UserId}/Items/%s/Rating?Likes=false&format=json" % itemid
doUtil(url, type="POST")
elif deletelike:
url = "{server}/emby/Users/{UserId}/Items/%s/Rating?format=json" % itemid
doUtils(url, type="DELETE")
self.logMsg("Update user rating to emby for itemid: %s "
"| like: %s | favourite: %s | deletelike: %s"
% (itemid, like, favourite, deletelike), 1)

View file

@ -8,6 +8,7 @@ import json
import pstats
import sqlite3
from datetime import datetime, timedelta
import StringIO
import time
import unicodedata
import xml.etree.ElementTree as etree
@ -538,44 +539,26 @@ def reset():
line1="Database reset has completed, Kodi will now restart to apply the changes.")
xbmc.executebuiltin('RestartApp')
def startProfiling():
pr = cProfile.Profile()
pr.enable()
return pr
def profiling(sortby="cumulative"):
# Will print results to Kodi log
def decorator(func):
def wrapper(*args, **kwargs):
pr = cProfile.Profile()
def stopProfiling(pr, profileName):
from datetime import time
pr.disable()
ps = pstats.Stats(pr)
profiles = xbmc.translatePath("%sprofiles/"
% xbmcaddon.Addon().getAddonInfo('profile')).decode('utf-8')
pr.enable()
result = func(*args, **kwargs)
pr.disable()
if not xbmcvfs.exists(profiles):
# Create the profiles folder
xbmcvfs.mkdir(profiles)
s = StringIO.StringIO()
ps = pstats.Stats(pr, stream=s).sort_stats(sortby)
ps.print_stats()
logMsg("EMBY Profiling", s.getvalue(), 1)
timestamp = time.strftime("%Y-%m-%d %H-%M-%S")
profile = "%s%s_profile_(%s).tab" % (profiles, profileName, timestamp)
f = xbmcvfs.File(profile, 'w')
f.write("NumbCalls\tTotalTime\tCumulativeTime\tFunctionName\tFileName\r\n")
for (key, value) in ps.stats.items():
(filename, count, func_name) = key
(ccalls, ncalls, total_time, cumulative_time, callers) = value
try:
f.write(
"%s\t%s\t%s\t%s\t%s\r\n"
% (ncalls, "{:10.4f}".format(total_time),
"{:10.4f}".format(cumulative_time), func_name, filename))
except ValueError:
f.write(
"%s\t%s\t%s\t%s\t%s\r\n"
% (ncalls, "{0}".format(total_time),
"{0}".format(cumulative_time), func_name, filename))
f.close()
return result
return wrapper
return decorator
def convertdate(date):
try: