mirror of
https://github.com/jellyfin/jellyfin-kodi.git
synced 2024-12-26 02:36:10 +00:00
Generators
This commit is contained in:
parent
7af2df5ade
commit
4cd270a9d2
3 changed files with 216 additions and 13 deletions
204
resources/lib/emby.py
Normal file
204
resources/lib/emby.py
Normal file
|
@ -0,0 +1,204 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
|
||||||
|
''' The goal is to reduce memory usage.
|
||||||
|
Generators to prevent having to hold all the info in memory
|
||||||
|
while downloading from emby servers.
|
||||||
|
|
||||||
|
Working with json, so we can resume where we left off.
|
||||||
|
'''
|
||||||
|
#################################################################################################
|
||||||
|
|
||||||
|
import json
|
||||||
|
import logging
|
||||||
|
import hashlib
|
||||||
|
import threading
|
||||||
|
import Queue
|
||||||
|
|
||||||
|
import xbmc
|
||||||
|
|
||||||
|
import downloadutils
|
||||||
|
import database
|
||||||
|
from utils import window, settings
|
||||||
|
from contextlib import closing
|
||||||
|
|
||||||
|
#################################################################################################
|
||||||
|
|
||||||
|
log = logging.getLogger("EMBY."+__name__)
|
||||||
|
limit = min(int(settings('limitIndex')), 50)
|
||||||
|
do = downloadutils.DownloadUtils()
|
||||||
|
|
||||||
|
#################################################################################################
|
||||||
|
|
||||||
|
def get_embyserver_url(handler):
|
||||||
|
return "{server}/emby/%s" % handler
|
||||||
|
|
||||||
|
def basic_info():
|
||||||
|
return "Etag"
|
||||||
|
|
||||||
|
def complete_info():
|
||||||
|
return (
|
||||||
|
"Path,Genres,SortName,Studios,Writer,ProductionYear,Taglines,"
|
||||||
|
"CommunityRating,OfficialRating,CumulativeRunTimeTicks,"
|
||||||
|
"Metascore,AirTime,DateCreated,MediaStreams,People,Overview,"
|
||||||
|
"CriticRating,CriticRatingSummary,Etag,ShortOverview,ProductionLocations,"
|
||||||
|
"Tags,ProviderIds,ParentId,RemoteTrailers,SpecialEpisodeNumbers,"
|
||||||
|
"MediaSources,VoteCount,ItemCounts"
|
||||||
|
)
|
||||||
|
|
||||||
|
def _http(action, url, request={}):
|
||||||
|
#request.update({'type': action, 'url': url})
|
||||||
|
#return HTTP.request_url(request)
|
||||||
|
|
||||||
|
return do.downloadUrl(url, action_type=action, parameters=request['params'])
|
||||||
|
|
||||||
|
def _get(handler, params=None):
|
||||||
|
return _http("GET", get_embyserver_url(handler), {'params': params})
|
||||||
|
|
||||||
|
def _post(handler, json=None, params=None):
|
||||||
|
return _http("POST", get_embyserver_url(handler), {'params': params, 'json': json})
|
||||||
|
|
||||||
|
def _delete(handler, params=None):
|
||||||
|
return _http("DELETE", get_embyserver_url(handler), {'params': params})
|
||||||
|
|
||||||
|
|
||||||
|
def emby_session(handler="", params=None, action="GET", json=None):
|
||||||
|
|
||||||
|
if action == "POST":
|
||||||
|
return _post("Sessions%s" % handler, json, params)
|
||||||
|
elif action == "DELETE":
|
||||||
|
return _delete("Sessions%s" % handler, params)
|
||||||
|
else:
|
||||||
|
return _get("Sessions%s" % handler, params)
|
||||||
|
|
||||||
|
def user(handler="", params=None, action="GET", json=None):
|
||||||
|
|
||||||
|
if action == "POST":
|
||||||
|
return _post("Users/{UserId}%s" % handler, json, params)
|
||||||
|
elif action == "DELETE":
|
||||||
|
return _delete(session, "Users/{UserId}%s" % handler, params)
|
||||||
|
else:
|
||||||
|
return _get(session, "Users/{UserId}%s" % handler, params)
|
||||||
|
|
||||||
|
def item(handler="", params=None):
|
||||||
|
return user("/Items%s" % handler, params)
|
||||||
|
|
||||||
|
def show(handler, params):
|
||||||
|
return _get("Shows%s" % handler, params)
|
||||||
|
|
||||||
|
#################################################################################################
|
||||||
|
|
||||||
|
# Single item functions
|
||||||
|
|
||||||
|
#################################################################################################
|
||||||
|
|
||||||
|
def get_item(item_id, fields=None):
|
||||||
|
return item(params={
|
||||||
|
'Ids': item_id,
|
||||||
|
'EnableTotalRecordCount': False,
|
||||||
|
'Fields': fields
|
||||||
|
})
|
||||||
|
|
||||||
|
def get_seasons(self, show_id):
|
||||||
|
return show("/%s/Seasons?UserId={UserId}" % show_id, {
|
||||||
|
'IsVirtualUnaired': False,
|
||||||
|
'Fields': "Etag"
|
||||||
|
})
|
||||||
|
|
||||||
|
#################################################################################################
|
||||||
|
|
||||||
|
# Get multiple items (Generator)
|
||||||
|
|
||||||
|
''' This should help with memory issues.
|
||||||
|
for items in generator(...):
|
||||||
|
#do something
|
||||||
|
|
||||||
|
If all items are required at once:
|
||||||
|
a = (items['Items'] for items in generator(...))
|
||||||
|
'''
|
||||||
|
|
||||||
|
#################################################################################################
|
||||||
|
|
||||||
|
def get_items(parent_id, item_type, basic=False):
|
||||||
|
|
||||||
|
query = {
|
||||||
|
'url': "Users/{UserId}/Items",
|
||||||
|
'params': {
|
||||||
|
'ParentId': parent_id,
|
||||||
|
'IncludeItemTypes': item_type,
|
||||||
|
'SortBy': "SortName",
|
||||||
|
'Fields': basic_info() if basic else complete_info()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for items in _get_items(query):
|
||||||
|
yield items
|
||||||
|
|
||||||
|
def get_item_list(item_list, basic=False):
|
||||||
|
|
||||||
|
for item_ids in _split_list(item_list, limit):
|
||||||
|
query = {
|
||||||
|
'url': "Users/{UserId}/Items",
|
||||||
|
'params': {
|
||||||
|
"Ids": ",".join(item_ids),
|
||||||
|
'Fields': basic_info() if basic else complete_info()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for items in _get_items(query):
|
||||||
|
yield items
|
||||||
|
|
||||||
|
def _split_list(item_list, size):
|
||||||
|
# Split up list in pieces of size. Will generate a list of lists
|
||||||
|
return [item_list[i:i + size] for i in range(0, len(item_list), size)]
|
||||||
|
|
||||||
|
def _get_items(query):
|
||||||
|
|
||||||
|
''' query = {
|
||||||
|
'url': string,
|
||||||
|
'params': dict -- opt, include StartIndex to resume
|
||||||
|
}
|
||||||
|
'''
|
||||||
|
items = {
|
||||||
|
'Items': [],
|
||||||
|
'TotalRecordCount': 0,
|
||||||
|
'RestorePoint': {}
|
||||||
|
}
|
||||||
|
|
||||||
|
url = query['url']
|
||||||
|
params = query.get('params', {})
|
||||||
|
params.update({
|
||||||
|
'CollapseBoxSetItems': False,
|
||||||
|
'IsVirtualUnaired': False,
|
||||||
|
'EnableTotalRecordCount': False,
|
||||||
|
'LocationTypes': "FileSystem,Remote,Offline",
|
||||||
|
'IsMissing': False,
|
||||||
|
'Recursive': True,
|
||||||
|
'SortOrder': "Ascending"
|
||||||
|
})
|
||||||
|
|
||||||
|
try:
|
||||||
|
test_params = dict(params)
|
||||||
|
test_params['Limit'] = 1
|
||||||
|
test_params['EnableTotalRecordCount'] = True
|
||||||
|
|
||||||
|
items['TotalRecordCount'] = _get(url, test_params)['TotalRecordCount']
|
||||||
|
|
||||||
|
except Exception as error:
|
||||||
|
log.error("Failed to retrieve the server response %s: %s params:%s", url, error, params)
|
||||||
|
|
||||||
|
else:
|
||||||
|
index = params.get('StartIndex', 0)
|
||||||
|
total = items['TotalRecordCount']
|
||||||
|
|
||||||
|
while index < total:
|
||||||
|
|
||||||
|
params['StartIndex'] = index
|
||||||
|
params['Limit'] = limit
|
||||||
|
result = _get(url, params)
|
||||||
|
|
||||||
|
items['Items'].extend(result['Items'])
|
||||||
|
items['RestorePoint'] = query
|
||||||
|
yield items
|
||||||
|
|
||||||
|
del items['Items'][:]
|
||||||
|
index += limit
|
||||||
|
|
|
@ -17,6 +17,7 @@ import clientinfo
|
||||||
import database
|
import database
|
||||||
import downloadutils
|
import downloadutils
|
||||||
import itemtypes
|
import itemtypes
|
||||||
|
import emby as mb
|
||||||
import embydb_functions as embydb
|
import embydb_functions as embydb
|
||||||
import read_embyserver as embyserver
|
import read_embyserver as embyserver
|
||||||
import userclient
|
import userclient
|
||||||
|
@ -59,7 +60,6 @@ class LibrarySync(threading.Thread):
|
||||||
self.doUtils = downloadutils.DownloadUtils().downloadUrl
|
self.doUtils = downloadutils.DownloadUtils().downloadUrl
|
||||||
self.user = userclient.UserClient()
|
self.user = userclient.UserClient()
|
||||||
self.emby = embyserver.Read_EmbyServer()
|
self.emby = embyserver.Read_EmbyServer()
|
||||||
|
|
||||||
self.kodi_version = int(xbmc.getInfoLabel('System.BuildVersion')[:2])
|
self.kodi_version = int(xbmc.getInfoLabel('System.BuildVersion')[:2])
|
||||||
|
|
||||||
threading.Thread.__init__(self)
|
threading.Thread.__init__(self)
|
||||||
|
@ -402,8 +402,8 @@ class LibrarySync(threading.Thread):
|
||||||
heading=lang(29999),
|
heading=lang(29999),
|
||||||
message="%s %s..." % (lang(33017), view_name))
|
message="%s %s..." % (lang(33017), view_name))
|
||||||
|
|
||||||
all_movies = self.emby.getMovies(view['id'], dialog=pdialog)
|
for all_movies in mb.get_items(view['id'], "Movie"):
|
||||||
movies.add_all("Movie", all_movies, view)
|
movies.add_all("Movie", all_movies['Items'], view)
|
||||||
|
|
||||||
log.debug("Movies finished.")
|
log.debug("Movies finished.")
|
||||||
return True
|
return True
|
||||||
|
@ -415,7 +415,7 @@ class LibrarySync(threading.Thread):
|
||||||
if pdialog:
|
if pdialog:
|
||||||
pdialog.update(heading=lang(29999), message=lang(33018))
|
pdialog.update(heading=lang(29999), message=lang(33018))
|
||||||
|
|
||||||
boxsets = self.emby.getBoxset(dialog=pdialog)
|
for boxsets in mb.get_items(None, "BoxSet"):
|
||||||
movies.add_all("BoxSet", boxsets)
|
movies.add_all("BoxSet", boxsets)
|
||||||
|
|
||||||
log.debug("Boxsets finished.")
|
log.debug("Boxsets finished.")
|
||||||
|
@ -434,7 +434,6 @@ class LibrarySync(threading.Thread):
|
||||||
log.info("Processing: %s", view)
|
log.info("Processing: %s", view)
|
||||||
|
|
||||||
# Get items per view
|
# Get items per view
|
||||||
viewId = view['id']
|
|
||||||
viewName = view['name']
|
viewName = view['name']
|
||||||
|
|
||||||
if pdialog:
|
if pdialog:
|
||||||
|
@ -443,8 +442,8 @@ class LibrarySync(threading.Thread):
|
||||||
message="%s %s..." % (lang(33019), viewName))
|
message="%s %s..." % (lang(33019), viewName))
|
||||||
|
|
||||||
# Initial or repair sync
|
# Initial or repair sync
|
||||||
all_mvideos = self.emby.getMusicVideos(viewId, dialog=pdialog)
|
for all_mvideos in mb.get_items(view['id'], "MusicVideo"):
|
||||||
mvideos.add_all("MusicVideo", all_mvideos, view)
|
mvideos.add_all("MusicVideo", all_mvideos['Items'], view)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
log.debug("MusicVideos finished.")
|
log.debug("MusicVideos finished.")
|
||||||
|
@ -469,10 +468,8 @@ class LibrarySync(threading.Thread):
|
||||||
heading=lang(29999),
|
heading=lang(29999),
|
||||||
message="%s %s..." % (lang(33020), view['name']))
|
message="%s %s..." % (lang(33020), view['name']))
|
||||||
|
|
||||||
all_tvshows = self.emby.getShows(view['id'], dialog=pdialog)
|
for all_tvshows in mb.get_items(view['id'], "Series"):
|
||||||
#log.info([item['Id'] for item in all_tvshows['Items']])
|
tvshows.add_all("Series", all_tvshows['Items'], view)
|
||||||
#for all_tvshows in self.emby.get_parent_child(view['id'], "Series"):
|
|
||||||
tvshows.add_all("Series", all_tvshows, view)
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
log.debug("TVShows finished.")
|
log.debug("TVShows finished.")
|
||||||
|
|
|
@ -63,6 +63,8 @@ class TVShows(Items):
|
||||||
|
|
||||||
def compare_all(self):
|
def compare_all(self):
|
||||||
# Pull the list of movies and boxsets in Kodi
|
# Pull the list of movies and boxsets in Kodi
|
||||||
|
import emby as mb
|
||||||
|
|
||||||
pdialog = self.pdialog
|
pdialog = self.pdialog
|
||||||
views = self.emby_db.getView_byType('tvshows')
|
views = self.emby_db.getView_byType('tvshows')
|
||||||
views += self.emby_db.getView_byType('mixed')
|
views += self.emby_db.getView_byType('mixed')
|
||||||
|
@ -116,7 +118,7 @@ class TVShows(Items):
|
||||||
updatelist.append(itemid)
|
updatelist.append(itemid)
|
||||||
|
|
||||||
log.info("TVShows to update for %s: %s", viewName, updatelist)
|
log.info("TVShows to update for %s: %s", viewName, updatelist)
|
||||||
embytvshows = self.emby.getFullItems(updatelist)
|
embytvshows = (items['Items'] for items in mb.get_item_list(updatelist, True))
|
||||||
self.total = len(updatelist)
|
self.total = len(updatelist)
|
||||||
del updatelist[:]
|
del updatelist[:]
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue