mirror of
https://github.com/jellyfin/jellyfin-kodi.git
synced 2024-12-25 10:16:11 +00:00
content notification
This commit is contained in:
parent
969629ec37
commit
c63bfd1346
9 changed files with 79 additions and 21 deletions
|
@ -486,6 +486,10 @@ msgctxt "#33048"
|
||||||
msgid "You may need to verify your network credentials in the add-on settings or use the Emby path substitution to format your path correctly (Emby dashboard > library). Stop syncing?"
|
msgid "You may need to verify your network credentials in the add-on settings or use the Emby path substitution to format your path correctly (Emby dashboard > library). Stop syncing?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgctxt "#33049"
|
||||||
|
msgid "New"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgctxt "#33054"
|
msgctxt "#33054"
|
||||||
msgid "Add user to session"
|
msgid "Add user to session"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
|
@ -18,10 +18,10 @@ LOG = logging.getLogger("EMBY."+__name__)
|
||||||
class API(object):
|
class API(object):
|
||||||
|
|
||||||
|
|
||||||
def __init__(self, item, server):
|
def __init__(self, item, server=None):
|
||||||
|
|
||||||
''' Get item information in special cases.
|
''' Get item information in special cases.
|
||||||
server is the server address
|
server is the server address, provide if your functions requires it.
|
||||||
'''
|
'''
|
||||||
self.item = item
|
self.item = item
|
||||||
self.server = server
|
self.server = server
|
||||||
|
@ -33,6 +33,25 @@ class API(object):
|
||||||
'''
|
'''
|
||||||
return (playcount or 1) if played else None
|
return (playcount or 1) if played else None
|
||||||
|
|
||||||
|
def get_naming(self):
|
||||||
|
|
||||||
|
if self.item['Type'] == 'Episode':
|
||||||
|
|
||||||
|
if 'SeriesName' in self.item:
|
||||||
|
return "%s: %s" % (self.item['SeriesName'], self.item['Name'])
|
||||||
|
|
||||||
|
elif self.item['Type'] == 'MusicAlbum':
|
||||||
|
|
||||||
|
if 'AlbumArtist' in self.item:
|
||||||
|
return "%s: %s" % (self.item['AlbumArtist'], self.item['Name'])
|
||||||
|
|
||||||
|
elif self.item['Type'] == 'Audio':
|
||||||
|
|
||||||
|
if self.item.get('Artists'):
|
||||||
|
return "%s: %s" % (self.item['Artists'][0], self.item['Name'])
|
||||||
|
|
||||||
|
return self.item['Name']
|
||||||
|
|
||||||
def get_actors(self):
|
def get_actors(self):
|
||||||
cast = []
|
cast = []
|
||||||
|
|
||||||
|
|
|
@ -406,8 +406,9 @@ def copy_file(path, dest):
|
||||||
|
|
||||||
def normalize_string(text):
|
def normalize_string(text):
|
||||||
|
|
||||||
''' For theme media, do not modify unless
|
''' For theme media, do not modify unless modified in TV Tunes.
|
||||||
modified in TV Tunes.
|
Remove dots from the last character as windows can not have directories
|
||||||
|
with dots at the end
|
||||||
'''
|
'''
|
||||||
text = text.replace(":", "")
|
text = text.replace(":", "")
|
||||||
text = text.replace("/", "-")
|
text = text.replace("/", "-")
|
||||||
|
@ -418,13 +419,14 @@ def normalize_string(text):
|
||||||
text = text.replace("?", "")
|
text = text.replace("?", "")
|
||||||
text = text.replace('|', "")
|
text = text.replace('|', "")
|
||||||
text = text.strip()
|
text = text.strip()
|
||||||
# Remove dots from the last character as windows can not have directories
|
|
||||||
# with dots at the end
|
|
||||||
text = text.rstrip('.')
|
text = text.rstrip('.')
|
||||||
text = unicodedata.normalize('NFKD', unicode(text, 'utf-8')).encode('ascii', 'ignore')
|
text = unicodedata.normalize('NFKD', unicode(text, 'utf-8')).encode('ascii', 'ignore')
|
||||||
|
|
||||||
return text
|
return text
|
||||||
|
|
||||||
def split_list(itemlist, size):
|
def split_list(itemlist, size):
|
||||||
# Split up list in pieces of size. Will generate a list of lists
|
|
||||||
|
''' Split up list in pieces of size. Will generate a list of lists
|
||||||
|
'''
|
||||||
return [itemlist[i:i+size] for i in range(0, len(itemlist), size)]
|
return [itemlist[i:i+size] for i in range(0, len(itemlist), size)]
|
||||||
|
|
|
@ -16,7 +16,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, window, dialog, event, progress, LibraryException
|
from helper import _, api, stop, settings, window, dialog, event, progress, LibraryException
|
||||||
from helper.utils import split_list, set_screensaver, get_screensaver
|
from helper.utils import split_list, set_screensaver, get_screensaver
|
||||||
from emby import Emby
|
from emby import Emby
|
||||||
|
|
||||||
|
@ -58,6 +58,7 @@ class Library(threading.Thread):
|
||||||
self.direct_path = settings('useDirectPaths') == "1"
|
self.direct_path = settings('useDirectPaths') == "1"
|
||||||
self.progress_display = int(settings('syncProgress') or 50)
|
self.progress_display = int(settings('syncProgress') or 50)
|
||||||
self.monitor = monitor
|
self.monitor = monitor
|
||||||
|
self.player = monitor.monitor.player
|
||||||
self.server = Emby()
|
self.server = Emby()
|
||||||
self.updated_queue = Queue.Queue()
|
self.updated_queue = Queue.Queue()
|
||||||
self.userdata_queue = Queue.Queue()
|
self.userdata_queue = Queue.Queue()
|
||||||
|
@ -65,9 +66,11 @@ class Library(threading.Thread):
|
||||||
self.updated_output = self.__new_queues__()
|
self.updated_output = self.__new_queues__()
|
||||||
self.userdata_output = self.__new_queues__()
|
self.userdata_output = self.__new_queues__()
|
||||||
self.removed_output = self.__new_queues__()
|
self.removed_output = self.__new_queues__()
|
||||||
|
self.notify_output = Queue.Queue()
|
||||||
|
|
||||||
self.emby_threads = []
|
self.emby_threads = []
|
||||||
self.download_threads = []
|
self.download_threads = []
|
||||||
|
self.notify_threads = []
|
||||||
self.writer_threads = {'updated': [], 'userdata': [], 'removed': []}
|
self.writer_threads = {'updated': [], 'userdata': [], 'removed': []}
|
||||||
self.database_lock = threading.Lock()
|
self.database_lock = threading.Lock()
|
||||||
self.music_database_lock = threading.Lock()
|
self.music_database_lock = threading.Lock()
|
||||||
|
@ -132,10 +135,11 @@ class Library(threading.Thread):
|
||||||
self.worker_updates()
|
self.worker_updates()
|
||||||
self.worker_userdata()
|
self.worker_userdata()
|
||||||
self.worker_remove()
|
self.worker_remove()
|
||||||
|
self.worker_notify()
|
||||||
|
|
||||||
if self.pending_refresh:
|
if self.pending_refresh:
|
||||||
|
|
||||||
if self.total_updates > self.progress_display:
|
if self.total_updates > self.progress_display and (not self.player.isPlayingVideo() or xbmc.getCondVisibility('VideoPlayer.Content(livetv)')):
|
||||||
queue_size = self.worker_queue_size()
|
queue_size = self.worker_queue_size()
|
||||||
|
|
||||||
if self.progress_updates is None:
|
if self.progress_updates is None:
|
||||||
|
@ -227,9 +231,9 @@ class Library(threading.Thread):
|
||||||
if queue.qsize() and len(self.writer_threads['updated']) < 4:
|
if queue.qsize() and len(self.writer_threads['updated']) < 4:
|
||||||
|
|
||||||
if queues in ('Audio', 'MusicArtist', 'AlbumArtist', 'MusicAlbum'):
|
if queues in ('Audio', 'MusicArtist', 'AlbumArtist', 'MusicAlbum'):
|
||||||
new_thread = UpdatedWorker(queue, self.music_database_lock, "music", self.server, self.direct_path)
|
new_thread = UpdatedWorker(queue, self.notify_output, self.music_database_lock, "music", self.server, self.direct_path)
|
||||||
else:
|
else:
|
||||||
new_thread = UpdatedWorker(queue, self.database_lock, "video", self.server, self.direct_path)
|
new_thread = UpdatedWorker(queue, self.notify_output, self.database_lock, "video", self.server, self.direct_path)
|
||||||
|
|
||||||
new_thread.start()
|
new_thread.start()
|
||||||
LOG.info("-->[ q:updated/%s/%s ]", queues, id(new_thread))
|
LOG.info("-->[ q:updated/%s/%s ]", queues, id(new_thread))
|
||||||
|
@ -274,6 +278,17 @@ class Library(threading.Thread):
|
||||||
self.writer_threads['removed'].append(new_thread)
|
self.writer_threads['removed'].append(new_thread)
|
||||||
self.pending_refresh = True
|
self.pending_refresh = True
|
||||||
|
|
||||||
|
def worker_notify(self):
|
||||||
|
|
||||||
|
''' Notify the user of new additions.
|
||||||
|
'''
|
||||||
|
if self.notify_output.qsize() and len(self.notify_threads) < 1:
|
||||||
|
|
||||||
|
new_thread = NotifyWorker(self.notify_output, self.player)
|
||||||
|
new_thread.start()
|
||||||
|
LOG.info("-->[ q:notify/%s ]", id(new_thread))
|
||||||
|
self.notify_threads.append(new_thread)
|
||||||
|
|
||||||
|
|
||||||
def startup(self):
|
def startup(self):
|
||||||
|
|
||||||
|
@ -587,9 +602,11 @@ class UpdatedWorker(threading.Thread):
|
||||||
|
|
||||||
is_done = False
|
is_done = False
|
||||||
|
|
||||||
def __init__(self, queue, lock, database, *args):
|
def __init__(self, queue, notify, lock, database, *args):
|
||||||
|
|
||||||
self.queue = queue
|
self.queue = queue
|
||||||
|
self.notify_output = notify
|
||||||
|
self.notify = settings('newContent.bool')
|
||||||
self.lock = lock
|
self.lock = lock
|
||||||
self.database = Database(database)
|
self.database = Database(database)
|
||||||
self.args = args
|
self.args = args
|
||||||
|
@ -613,9 +630,10 @@ class UpdatedWorker(threading.Thread):
|
||||||
break
|
break
|
||||||
|
|
||||||
obj = MEDIA[item['Type']](self.args[0], embydb, kodidb, self.args[1])[item['Type']]
|
obj = MEDIA[item['Type']](self.args[0], embydb, kodidb, self.args[1])[item['Type']]
|
||||||
|
LOG.info(item['Type'])
|
||||||
try:
|
try:
|
||||||
obj(item)
|
if obj(item) and self.notify:
|
||||||
|
self.notify_output.put((item['Type'], api.API(item).get_naming()))
|
||||||
except LibraryException as error:
|
except LibraryException as error:
|
||||||
if error.status == 'StopCalled':
|
if error.status == 'StopCalled':
|
||||||
break
|
break
|
||||||
|
@ -763,8 +781,13 @@ class NotifyWorker(threading.Thread):
|
||||||
|
|
||||||
is_done = False
|
is_done = False
|
||||||
|
|
||||||
def __init__(self, queue):
|
def __init__(self, queue, player):
|
||||||
|
|
||||||
self.queue = queue
|
self.queue = queue
|
||||||
|
self.video_time = int(settings('newvideotime')) * 1000
|
||||||
|
self.music_time = int(settings('newmusictime')) * 1000
|
||||||
|
self.player = player
|
||||||
|
threading.Thread.__init__(self)
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
|
|
||||||
|
@ -779,11 +802,13 @@ class NotifyWorker(threading.Thread):
|
||||||
|
|
||||||
break
|
break
|
||||||
|
|
||||||
|
time = self.music_time if item[0] == 'Audio' else self.video_time
|
||||||
|
|
||||||
|
if time and (not self.player.isPlayingVideo() or xbmc.getCondVisibility('VideoPlayer.Content(livetv)')):
|
||||||
|
dialog("notification", heading="%s %s" % (_(33049), item[0]), message=item[1],
|
||||||
|
icon="{emby}", time=time, sound=False)
|
||||||
|
|
||||||
self.queue.task_done()
|
self.queue.task_done()
|
||||||
|
|
||||||
if xbmc.Monitor().abortRequested():
|
if window('emby_should_stop.bool'):
|
||||||
break
|
break
|
||||||
|
|
||||||
if not self.pdialog and self.content_msg and self.new_time and (not xbmc.Player().isPlayingVideo() or xbmc.getCondVisibility('VideoPlayer.Content(livetv)')):
|
|
||||||
dialog("notification", heading="{emby}", message="%s %s" % (lang(33049), name),
|
|
||||||
icon="{emby}", time=self.new_time, sound=False)
|
|
||||||
|
|
|
@ -129,6 +129,8 @@ class Movies(KodiDb):
|
||||||
|
|
||||||
self.item_ids.append(obj['Id'])
|
self.item_ids.append(obj['Id'])
|
||||||
|
|
||||||
|
return not update
|
||||||
|
|
||||||
def movie_add(self, obj):
|
def movie_add(self, obj):
|
||||||
|
|
||||||
''' Add object to kodi.
|
''' Add object to kodi.
|
||||||
|
|
|
@ -294,6 +294,8 @@ class Music(KodiDb):
|
||||||
if obj['SongAlbumId'] is None:
|
if obj['SongAlbumId'] is None:
|
||||||
self.artwork.add(obj['Artwork'], obj['AlbumId'], "album")
|
self.artwork.add(obj['Artwork'], obj['AlbumId'], "album")
|
||||||
|
|
||||||
|
return not update
|
||||||
|
|
||||||
def song_add(self, obj):
|
def song_add(self, obj):
|
||||||
|
|
||||||
''' Add object to kodi.
|
''' Add object to kodi.
|
||||||
|
|
|
@ -137,6 +137,8 @@ class MusicVideos(KodiDb):
|
||||||
self.add_streams(*values(obj, QU.add_streams_obj))
|
self.add_streams(*values(obj, QU.add_streams_obj))
|
||||||
self.artwork.add(obj['Artwork'], obj['MvideoId'], "musicvideo")
|
self.artwork.add(obj['Artwork'], obj['MvideoId'], "musicvideo")
|
||||||
|
|
||||||
|
return not update
|
||||||
|
|
||||||
def musicvideo_add(self, obj):
|
def musicvideo_add(self, obj):
|
||||||
|
|
||||||
''' Add object to kodi.
|
''' Add object to kodi.
|
||||||
|
|
|
@ -346,6 +346,8 @@ class TVShows(KodiDb):
|
||||||
self.update_file(*values(temp_obj, QU.update_file_obj))
|
self.update_file(*values(temp_obj, QU.update_file_obj))
|
||||||
self.add_playstate(*values(temp_obj, QU.add_bookmark_obj))
|
self.add_playstate(*values(temp_obj, QU.add_bookmark_obj))
|
||||||
|
|
||||||
|
return not update
|
||||||
|
|
||||||
def episode_add(self, obj):
|
def episode_add(self, obj):
|
||||||
|
|
||||||
''' Add object to kodi.
|
''' Add object to kodi.
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
<category label="30506"><!-- Sync Options -->
|
<category label="30506"><!-- Sync Options -->
|
||||||
<setting label="33137" id="kodiCompanion" type="bool" default="true" />
|
<setting label="33137" id="kodiCompanion" type="bool" default="true" />
|
||||||
<setting label="30507" id="syncIndicator" type="number" default="99" visible="eq(-1,true)" subsetting="true"/>
|
<setting label="30507" id="syncIndicator" type="number" default="99" visible="eq(-1,true)" subsetting="true"/>
|
||||||
<setting label="33177" id="syncProgress" type="number" default="15" visible="true" />
|
|
||||||
<setting label="30536" id="dbSyncScreensaver" type="bool" default="true" />
|
<setting label="30536" id="dbSyncScreensaver" type="bool" default="true" />
|
||||||
<setting label="33111" type="lsep" />
|
<setting label="33111" type="lsep" />
|
||||||
<setting label="30511" id="useDirectPaths" type="enum" lvalues="33036|33037" default="1" />
|
<setting label="30511" id="useDirectPaths" type="enum" lvalues="33036|33037" default="1" />
|
||||||
|
@ -75,6 +74,7 @@
|
||||||
<setting label="30530" id="restartMsg" type="bool" default="true" />
|
<setting label="30530" id="restartMsg" type="bool" default="true" />
|
||||||
<setting label="30547" id="displayMessage" type="slider" default="4" range="4,1,20" option="int" />
|
<setting label="30547" id="displayMessage" type="slider" default="4" range="4,1,20" option="int" />
|
||||||
<setting label="33108" type="lsep" />
|
<setting label="33108" type="lsep" />
|
||||||
|
<setting label="33177" id="syncProgress" type="number" default="15" visible="true" />
|
||||||
<setting label="30531" id="newContent" type="bool" default="false" />
|
<setting label="30531" id="newContent" type="bool" default="false" />
|
||||||
<setting label="30532" id="newvideotime" type="number" visible="eq(-1,true)" default="5" option="int" subsetting="true" />
|
<setting label="30532" id="newvideotime" type="number" visible="eq(-1,true)" default="5" option="int" subsetting="true" />
|
||||||
<setting label="30533" id="newmusictime" type="number" visible="eq(-2,true)" default="2" option="int" subsetting="true" />
|
<setting label="30533" id="newmusictime" type="number" visible="eq(-2,true)" default="2" option="int" subsetting="true" />
|
||||||
|
|
Loading…
Reference in a new issue