mirror of
https://github.com/jellyfin/jellyfin-kodi.git
synced 2024-11-10 04:06:11 +00:00
Remember sync position for manual triggers
Allow to resume sync on restart for manual user triggers (update, repair). Automatically refresh boxsets if movie library is selected. use waitForAbort and emby_should_stop prop to terminate threads
This commit is contained in:
parent
00ee891952
commit
11f771ade2
9 changed files with 54 additions and 28 deletions
|
@ -845,3 +845,7 @@ msgstr ""
|
||||||
msgctxt "#33172"
|
msgctxt "#33172"
|
||||||
msgid "You have {number} updates pending. This may take a little while before seeing new content. It might be faster to update your libraries via launching the Emby add-on > update libraries. Proceed anyway?"
|
msgid "You have {number} updates pending. This may take a little while before seeing new content. It might be faster to update your libraries via launching the Emby add-on > update libraries. Proceed anyway?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgctxt "#33173"
|
||||||
|
msgid "Forget about the previous sync?"
|
||||||
|
msgstr ""
|
||||||
|
|
|
@ -262,7 +262,7 @@ class GetItemWorker(threading.Thread):
|
||||||
|
|
||||||
self.queue.task_done()
|
self.queue.task_done()
|
||||||
|
|
||||||
if xbmc.Monitor().abortRequested():
|
if window('emby_should_stop.bool'):
|
||||||
break
|
break
|
||||||
|
|
||||||
class TheVoid(object):
|
class TheVoid(object):
|
||||||
|
@ -282,10 +282,12 @@ class TheVoid(object):
|
||||||
event(method, data)
|
event(method, data)
|
||||||
self.method = method
|
self.method = method
|
||||||
self.data = data
|
self.data = data
|
||||||
|
self.monitor = xbmc.Monitor()
|
||||||
|
|
||||||
def get(self):
|
def get(self):
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
|
|
||||||
response = window('emby_%s.json' % self.data['VoidName'])
|
response = window('emby_%s.json' % self.data['VoidName'])
|
||||||
|
|
||||||
if response != "":
|
if response != "":
|
||||||
|
@ -295,7 +297,7 @@ class TheVoid(object):
|
||||||
|
|
||||||
return response
|
return response
|
||||||
|
|
||||||
if window('emby_should_stop.bool'):
|
if window('emby_should_stop.bool') or self.monitor.waitForAbort(0.2):
|
||||||
LOG.info("Abandon mission! A black hole just swallowed [ %s ]", self.data['VoidName'])
|
LOG.info("Abandon mission! A black hole just swallowed [ %s ]", self.data['VoidName'])
|
||||||
|
|
||||||
break
|
break
|
||||||
|
@ -306,7 +308,7 @@ def get_objects(src, filename):
|
||||||
'''
|
'''
|
||||||
temp = xbmc.translatePath('special://temp/emby').decode('utf-8')
|
temp = xbmc.translatePath('special://temp/emby').decode('utf-8')
|
||||||
restart = not xbmcvfs.exists(os.path.join(temp, "objects") + '/')
|
restart = not xbmcvfs.exists(os.path.join(temp, "objects") + '/')
|
||||||
path = os.path.join(temp, filename).decode('utf-8')
|
path = os.path.join(temp, filename).encode('utf-8')
|
||||||
|
|
||||||
if not xbmcvfs.exists(path):
|
if not xbmcvfs.exists(path):
|
||||||
delete_folder()
|
delete_folder()
|
||||||
|
|
|
@ -46,7 +46,7 @@ class HTTP(object):
|
||||||
return
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
LOG.warn("Closing session %s", id(self.session))
|
LOG.warn("--<[ session/%s ]", id(self.session))
|
||||||
self.session.close()
|
self.session.close()
|
||||||
except Exception as error:
|
except Exception as error:
|
||||||
LOG.warn("The requests session could not be terminated: %s", error)
|
LOG.warn("The requests session could not be terminated: %s", error)
|
||||||
|
|
|
@ -7,6 +7,8 @@ import logging
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
import xbmc
|
||||||
|
|
||||||
from ..resources import websocket
|
from ..resources import websocket
|
||||||
|
|
||||||
##################################################################################################
|
##################################################################################################
|
||||||
|
@ -46,6 +48,7 @@ class WSClient(threading.Thread):
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
|
|
||||||
|
monitor = xbmc.Monitor()
|
||||||
token = self.client['config/auth.token']
|
token = self.client['config/auth.token']
|
||||||
device_id = self.client['config/app.device_id']
|
device_id = self.client['config/app.device_id']
|
||||||
server = self.client['config/auth.server']
|
server = self.client['config/auth.server']
|
||||||
|
@ -63,8 +66,8 @@ class WSClient(threading.Thread):
|
||||||
|
|
||||||
self.wsc.run_forever(ping_interval=10)
|
self.wsc.run_forever(ping_interval=10)
|
||||||
|
|
||||||
if not self.stop:
|
if not self.stop and monitor.waitForAbort(5):
|
||||||
time.sleep(5)
|
break
|
||||||
|
|
||||||
LOG.info("---<[ websocket ]")
|
LOG.info("---<[ websocket ]")
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,8 @@ class Service(xbmc.Monitor):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|
||||||
|
window('emby_should_stop', clear=True)
|
||||||
|
|
||||||
self.settings['addon_version'] = client.get_version()
|
self.settings['addon_version'] = client.get_version()
|
||||||
self.settings['profile'] = xbmc.translatePath('special://profile')
|
self.settings['profile'] = xbmc.translatePath('special://profile')
|
||||||
self.settings['mode'] = settings('useDirectPaths')
|
self.settings['mode'] = settings('useDirectPaths')
|
||||||
|
@ -194,7 +196,7 @@ class Service(xbmc.Monitor):
|
||||||
|
|
||||||
data = json.loads(data)
|
data = json.loads(data)
|
||||||
|
|
||||||
LOG.debug("[ %s: %s ] %s", sender, method, json.dumps(data, indent=4))
|
LOG.info("[ %s: %s ] %s", sender, method, json.dumps(data, indent=4))
|
||||||
|
|
||||||
if method == 'ServerOnline':
|
if method == 'ServerOnline':
|
||||||
if data['ServerId'] is None:
|
if data['ServerId'] is None:
|
||||||
|
@ -410,7 +412,7 @@ class Service(xbmc.Monitor):
|
||||||
"emby_currUser", "emby_dbScan",
|
"emby_currUser", "emby_dbScan",
|
||||||
"emby_initialScan",
|
"emby_initialScan",
|
||||||
|
|
||||||
"emby_play", "emby_online", "emby.connected", "emby_should_stop", "emby.resume",
|
"emby_play", "emby_online", "emby.connected", "emby.resume",
|
||||||
"emby.external", "emby.external_check", "emby_deviceId", "emby_db_check", "emby_pathverified"
|
"emby.external", "emby.external_check", "emby_deviceId", "emby_db_check", "emby_pathverified"
|
||||||
]
|
]
|
||||||
for prop in properties:
|
for prop in properties:
|
||||||
|
|
|
@ -40,19 +40,24 @@ class FullSync(object):
|
||||||
libraries = library_id.split(',')
|
libraries = library_id.split(',')
|
||||||
|
|
||||||
for selected in libraries:
|
for selected in libraries:
|
||||||
|
|
||||||
if selected not in [x.replace('Mixed:', "") for x in self.sync['Libraries']]:
|
if selected not in [x.replace('Mixed:', "") for x in self.sync['Libraries']]:
|
||||||
library = self.get_libraries(selected)
|
library = self.get_libraries(selected)
|
||||||
|
|
||||||
if library and library[1] == 'mixed':
|
if library:
|
||||||
selected = "Mixed:%s" % selected
|
|
||||||
|
|
||||||
|
self.sync['Libraries'].append("Mixed:%s" % selected if library[1] == 'mixed' else selected)
|
||||||
|
|
||||||
|
if library[1] in ('mixed', 'movies'):
|
||||||
|
self.sync['Libraries'].append('Boxsets:%s' % selected)
|
||||||
|
else:
|
||||||
self.sync['Libraries'].append(selected)
|
self.sync['Libraries'].append(selected)
|
||||||
else:
|
else:
|
||||||
self.mapping()
|
self.mapping()
|
||||||
|
|
||||||
xmls.sources()
|
xmls.sources()
|
||||||
|
|
||||||
if not xmls.advanced_settings():
|
if not xmls.advanced_settings() and self.sync['Libraries']:
|
||||||
self.start()
|
self.start()
|
||||||
|
|
||||||
def get_libraries(self, library_id=None):
|
def get_libraries(self, library_id=None):
|
||||||
|
@ -71,10 +76,14 @@ class FullSync(object):
|
||||||
if self.sync['Libraries']:
|
if self.sync['Libraries']:
|
||||||
|
|
||||||
if not dialog("yesno", heading="{emby}", line1=_(33102)):
|
if not dialog("yesno", heading="{emby}", line1=_(33102)):
|
||||||
|
|
||||||
|
if not dialog("yesno", heading="{emby}", line1=_(33173)):
|
||||||
dialog("ok", heading="{emby}", line1=_(33122))
|
dialog("ok", heading="{emby}", line1=_(33122))
|
||||||
|
|
||||||
raise LibraryException("ProgressStopped")
|
raise LibraryException("ProgressStopped")
|
||||||
|
else:
|
||||||
|
self.sync['Libraries'] = []
|
||||||
|
self.sync['RestorePoint'] = {}
|
||||||
else:
|
else:
|
||||||
LOG.info("generate full sync")
|
LOG.info("generate full sync")
|
||||||
libraries = []
|
libraries = []
|
||||||
|
@ -168,7 +177,7 @@ class FullSync(object):
|
||||||
if library_id.endswith('Refresh'):
|
if library_id.endswith('Refresh'):
|
||||||
self.refresh_boxsets()
|
self.refresh_boxsets()
|
||||||
else:
|
else:
|
||||||
self.boxsets()
|
self.boxsets(library_id.split('Boxsets:')[1] if len(library_id) > len('Boxsets:') else None)
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -197,7 +206,7 @@ class FullSync(object):
|
||||||
|
|
||||||
dialog("ok", heading="{emby}", line1=_(33119))
|
dialog("ok", heading="{emby}", line1=_(33119))
|
||||||
LOG.error("full sync exited unexpectedly")
|
LOG.error("full sync exited unexpectedly")
|
||||||
|
else:
|
||||||
save_sync(self.sync)
|
save_sync(self.sync)
|
||||||
|
|
||||||
raise
|
raise
|
||||||
|
@ -306,7 +315,7 @@ class FullSync(object):
|
||||||
obj.song(song)
|
obj.song(song)
|
||||||
|
|
||||||
@progress(_(33018))
|
@progress(_(33018))
|
||||||
def boxsets(self, dialog):
|
def boxsets(self, library_id=None, dialog=None):
|
||||||
|
|
||||||
''' Process all boxsets.
|
''' Process all boxsets.
|
||||||
'''
|
'''
|
||||||
|
@ -314,7 +323,7 @@ class FullSync(object):
|
||||||
with Database('emby') as embydb:
|
with Database('emby') as embydb:
|
||||||
obj = Movies(self.server, embydb, videodb, self.direct_path)
|
obj = Movies(self.server, embydb, videodb, self.direct_path)
|
||||||
|
|
||||||
for items in server.get_items(None, "BoxSet", False, self.sync['RestorePoint'].get('params')):
|
for items in server.get_items(library_id, "BoxSet", False, self.sync['RestorePoint'].get('params')):
|
||||||
|
|
||||||
self.sync['RestorePoint'] = items['RestorePoint']
|
self.sync['RestorePoint'] = items['RestorePoint']
|
||||||
start_index = items['RestorePoint']['params']['StartIndex']
|
start_index = items['RestorePoint']['params']['StartIndex']
|
||||||
|
@ -336,4 +345,4 @@ class FullSync(object):
|
||||||
obj = Movies(self.server, embydb, videodb, self.direct_path)
|
obj = Movies(self.server, embydb, videodb, self.direct_path)
|
||||||
obj.boxsets_reset()
|
obj.boxsets_reset()
|
||||||
|
|
||||||
self.boxsets()
|
self.boxsets(None)
|
||||||
|
|
|
@ -160,7 +160,7 @@ def should_stop():
|
||||||
|
|
||||||
''' Checkpoint during the sync process.
|
''' Checkpoint during the sync process.
|
||||||
'''
|
'''
|
||||||
if xbmc.Monitor().abortRequested():
|
if xbmc.Monitor().waitForAbort(0.00001):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
if window('emby_should_stop.bool'):
|
if window('emby_should_stop.bool'):
|
||||||
|
|
|
@ -15,7 +15,7 @@ from database import Database, emby_db, get_sync, save_sync
|
||||||
from full_sync import FullSync
|
from full_sync import FullSync
|
||||||
from views import Views
|
from views import Views
|
||||||
from downloader import GetItemWorker
|
from downloader import GetItemWorker
|
||||||
from helper import _, stop, settings, dialog, event, progress, LibraryException
|
from helper import _, stop, settings, window, dialog, event, progress, LibraryException
|
||||||
from emby import Emby
|
from emby import Emby
|
||||||
|
|
||||||
##################################################################################################
|
##################################################################################################
|
||||||
|
@ -210,7 +210,13 @@ class Library(threading.Thread):
|
||||||
else:
|
else:
|
||||||
raise LibraryException('CompanionMissing')
|
raise LibraryException('CompanionMissing')
|
||||||
|
|
||||||
|
if get_sync()['Libraries']:
|
||||||
|
|
||||||
|
FullSync(self)
|
||||||
|
Views().get_nodes()
|
||||||
|
|
||||||
if settings('SyncInstallRunDone.bool'):
|
if settings('SyncInstallRunDone.bool'):
|
||||||
|
|
||||||
if fast_sync and not self.fast_sync():
|
if fast_sync and not self.fast_sync():
|
||||||
dialog("ok", heading="{emby}", line1=_(33128))
|
dialog("ok", heading="{emby}", line1=_(33128))
|
||||||
|
|
||||||
|
@ -537,7 +543,7 @@ class UpdatedWorker(threading.Thread):
|
||||||
except Exception as error:
|
except Exception as error:
|
||||||
LOG.exception(error)
|
LOG.exception(error)
|
||||||
|
|
||||||
if xbmc.Monitor().abortRequested():
|
if window('emby_should_stop.bool'):
|
||||||
break
|
break
|
||||||
|
|
||||||
class UserDataWorker(threading.Thread):
|
class UserDataWorker(threading.Thread):
|
||||||
|
@ -580,7 +586,7 @@ class UserDataWorker(threading.Thread):
|
||||||
except Exception as error:
|
except Exception as error:
|
||||||
LOG.exception(error)
|
LOG.exception(error)
|
||||||
|
|
||||||
if xbmc.Monitor().abortRequested():
|
if window('emby_should_stop.bool'):
|
||||||
break
|
break
|
||||||
|
|
||||||
class SortWorker(threading.Thread):
|
class SortWorker(threading.Thread):
|
||||||
|
@ -624,7 +630,7 @@ class SortWorker(threading.Thread):
|
||||||
|
|
||||||
self.queue.task_done()
|
self.queue.task_done()
|
||||||
|
|
||||||
if xbmc.Monitor().abortRequested():
|
if window('emby_should_stop.bool'):
|
||||||
break
|
break
|
||||||
|
|
||||||
class RemovedWorker(threading.Thread):
|
class RemovedWorker(threading.Thread):
|
||||||
|
@ -667,7 +673,7 @@ class RemovedWorker(threading.Thread):
|
||||||
except Exception as error:
|
except Exception as error:
|
||||||
LOG.exception(error)
|
LOG.exception(error)
|
||||||
|
|
||||||
if xbmc.Monitor().abortRequested():
|
if window('emby_should_stop.bool'):
|
||||||
break
|
break
|
||||||
|
|
||||||
class NotifyWorker(threading.Thread):
|
class NotifyWorker(threading.Thread):
|
||||||
|
|
|
@ -414,7 +414,7 @@ class Views(object):
|
||||||
rule = etree.SubElement(xml, 'rule', {'field': "tag", 'operator': "is"})
|
rule = etree.SubElement(xml, 'rule', {'field': "tag", 'operator': "is"})
|
||||||
etree.SubElement(rule, 'value').text = view['Tag']
|
etree.SubElement(rule, 'value').text = view['Tag']
|
||||||
|
|
||||||
getattr(self, 'node_' + node)(xml)
|
getattr(self, 'node_' + node)(xml) # get node function based on node type
|
||||||
indent(xml)
|
indent(xml)
|
||||||
write_xml(etree.tostring(xml, 'UTF-8'), file)
|
write_xml(etree.tostring(xml, 'UTF-8'), file)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue