From 8cc94e694e9e797764206e71e674bebd953adddc Mon Sep 17 00:00:00 2001 From: smfontes Date: Fri, 10 Feb 2023 17:28:20 -0500 Subject: [PATCH] Support mysql along with sqlite, and provide some info labels Modified queries as needed based on which database type the My Pictures Database is using. Set some window properties based on tags in the image files. Provide the option to display the tag information on each slide. --- README.md | 4 + lib/getfilternames.py | 4 +- lib/screensaver.py | 136 ++++++++++++++---- .../resource.language.en_gb/strings.po | 18 ++- resources/settings.xml | 6 + .../1080i/screensaver.mypicsdb2.slideshow.xml | 98 +++++++++---- 6 files changed, 199 insertions(+), 67 deletions(-) diff --git a/README.md b/README.md index cf470eb..4ff7b81 100644 --- a/README.md +++ b/README.md @@ -6,3 +6,7 @@ This Screensaver uses the database from the plugin.image.mypicsdb2 addon. Filters can be used to select which pictures will be shown in the slideshow. + The values of some image tags are set in Window properties. There is an option to display the values overlayed on the images. The values that can be displayed are: + + Headline, Caption, Location, Date and Time, and Folder and File name. + diff --git a/lib/getfilternames.py b/lib/getfilternames.py index c4a1e38..771edfb 100644 --- a/lib/getfilternames.py +++ b/lib/getfilternames.py @@ -52,6 +52,6 @@ tree.write(settings_file) # Notify that you must exit from settings and return to see any new filter names -heading = xbmcaddon.Addon().getLocalizedString(30009) -message = xbmcaddon.Addon().getLocalizedString(30010) +heading = xbmcaddon.Addon().getLocalizedString(30010) +message = xbmcaddon.Addon().getLocalizedString(30011) xbmc.executebuiltin('Notification('+heading+','+message+',10000)') diff --git a/lib/screensaver.py b/lib/screensaver.py index f11971c..133c09f 100644 --- a/lib/screensaver.py +++ b/lib/screensaver.py @@ -18,11 +18,15 @@ # The screensaver uses the picture database created by the plugin.image.mypicsdb2 addon. # You can also use Filters created in the plugin.image.mypicsdb2 addon to select which # pictures are shown in the slideshow. +# The values of some image tags are set in Window properties. There is an option +# to display the values overlayed on the images. The values displayed are +# Headline, Caption, Location, Date and Time, and Folder and File name. import os.path import sys import random import urllib.parse +import time import xbmc import xbmcgui @@ -32,32 +36,41 @@ ADDON = xbmcaddon.Addon() -SETTINGS_ERROR = ADDON.getLocalizedString(30005) -NO_FILTER_NAME_ERROR = ADDON.getLocalizedString(30006) -BAD_FILTER_NAME_ERROR = ADDON.getLocalizedString(30007) -NO_FILES_MATCH_FILTER = ADDON.getLocalizedString(30008) +SETTINGS_ERROR = ADDON.getLocalizedString(30006) +NO_FILTER_NAME_ERROR = ADDON.getLocalizedString(30007) +BAD_FILTER_NAME_ERROR = ADDON.getLocalizedString(30008) +NO_FILES_MATCH_FILTER = ADDON.getLocalizedString(30009) def log(msg, level=xbmc.LOGINFO): filename = os.path.basename(sys._getframe(1).f_code.co_filename) lineno = str(sys._getframe(1).f_lineno) xbmc.log(str("[%s] line %5d in %s >> %s"%(ADDON.getAddonInfo('name'), int(lineno), filename, msg.__str__())), level) +DB_BACKEND = xbmcaddon.Addon('plugin.image.mypicsdb2').getSetting('db_backend').lower() +# The random function is different in mysql and sqlite +DB_RANDOM = {"mysql" :"RAND()","sqlite":"RANDOM()"} +# DateTimes are stored and retreived differently between mysql and sqlite. +IMGDATE = {"mysql" :"DATE_FORMAT(ImageDateTime,'%Y-%m-%d')", + "sqlite":"SUBSTR(ImageDateTime, 0, 11)"} +IMGDATETIME = {"mysql" :"DATE_FORMAT(ImageDateTime,'%Y-%m-%d %T')", + "sqlite":"ImageDateTime"} + # Formats that can be displayed in a slideshow PICTURE_FORMATS = ('jpg', 'jpeg', 'tiff', 'gif', 'png', 'bmp', 'mng', 'ico', 'pcx', 'tga') -SINGLE_PICTURE_QUERY = """ SELECT strPath, strFilename FROM Files """ -SINGLE_PICTURE_QUERY += """ WHERE strFilename LIKE '%s' """ -SINGLE_PICTURE_QUERY += """ OR strFilename LIKE '%s' """ -SINGLE_PICTURE_QUERY += """ OR strFilename LIKE '%s' """ -SINGLE_PICTURE_QUERY += """ OR strFilename LIKE '%s' """ -SINGLE_PICTURE_QUERY += """ OR strFilename LIKE '%s' """ -SINGLE_PICTURE_QUERY += """ OR strFilename LIKE '%s' """ -SINGLE_PICTURE_QUERY += """ OR strFilename LIKE '%s' """ -SINGLE_PICTURE_QUERY += """ OR strFilename LIKE '%s' """ -SINGLE_PICTURE_QUERY += """ OR strFilename LIKE '%s' """ -SINGLE_PICTURE_QUERY += """ OR strFilename LIKE '%s' """ -SINGLE_PICTURE_QUERY += """ ORDER BY RANDOM() LIMIT 1 """ +SINGLE_PICTURE_QUERY = " SELECT strPath, strFilename FROM Files " +SINGLE_PICTURE_QUERY += " WHERE strFilename LIKE '%s' " +SINGLE_PICTURE_QUERY += " OR strFilename LIKE '%s' " +SINGLE_PICTURE_QUERY += " OR strFilename LIKE '%s' " +SINGLE_PICTURE_QUERY += " OR strFilename LIKE '%s' " +SINGLE_PICTURE_QUERY += " OR strFilename LIKE '%s' " +SINGLE_PICTURE_QUERY += " OR strFilename LIKE '%s' " +SINGLE_PICTURE_QUERY += " OR strFilename LIKE '%s' " +SINGLE_PICTURE_QUERY += " OR strFilename LIKE '%s' " +SINGLE_PICTURE_QUERY += " OR strFilename LIKE '%s' " +SINGLE_PICTURE_QUERY += " OR strFilename LIKE '%s' " +SINGLE_PICTURE_QUERY += " ORDER BY " + DB_RANDOM[DB_BACKEND] + " LIMIT 1 " SINGLE_PICTURE_QUERY = SINGLE_PICTURE_QUERY % PICTURE_FORMATS -SINGLE_PICTURE_QUERY = SINGLE_PICTURE_QUERY.replace("LIKE '", "LIKE '%") +SINGLE_PICTURE_QUERY = SINGLE_PICTURE_QUERY.replace("LIKE '", "LIKE '%") # Get the Database from the My Pictures Database addon MPDB = MypicsDB.MyPictureDB() @@ -67,6 +80,7 @@ def __init__(self, *args, **kwargs): pass def onInit(self): + self.db_backend = xbmcaddon.Addon('plugin.image.mypicsdb2').getSetting('db_backend').lower() # Get the screensaver window id self.winid = xbmcgui.Window(xbmcgui.getCurrentWindowDialogId()) # Init the monitor class to catch onscreensaverdeactivated calls @@ -80,13 +94,32 @@ def onInit(self): def _get_settings(self): # read addon settings - self.anim_time = 101000 self.slideshow_time = ADDON.getSettingInt('time') self.slideshow_filter = ADDON.getSettingBool('filter') self.slideshow_filtername = ADDON.getSettingString('filtername') + self.slideshow_showinfo = ADDON.getSettingBool('tags') # Set the image controls from the xml we are going to use self.image1 = self.getControl(1) self.image2 = self.getControl(2) + # Get MyPicsDB tagids for the information that can be displayed for each slide + _query = " Select idTagType FROM TagTypes WHERE TagType = 'Headline'; " + _ids = self._exec_query(_query) + self.headline_tagid = _ids[0][0] + _query = " Select idTagType FROM TagTypes WHERE TagType = 'Caption/abstract'; " + _ids = self._exec_query(_query) + self.caption_tagid = _ids[0][0] + _query = " Select idTagType FROM TagTypes WHERE TagType = 'Sub-location'; " + _ids = self._exec_query(_query) + self.sublocation_tagid = _ids[0][0] + _query = " Select idTagType FROM TagTypes WHERE TagType = 'City'; " + _ids = self._exec_query(_query) + self.city_tagid= _ids[0][0] + _query = " Select idTagType FROM TagTypes WHERE TagType = 'Province/state'; " + _ids = self._exec_query(_query) + self.state_tagid= _ids[0][0] + _query = " Select idTagType FROM TagTypes WHERE TagType = 'Country/primary location name'; " + _ids = self._exec_query(_query) + self.country_tagid= _ids[0][0] def _get_filtered_pictures(self): # If we are going to use a MyPicsDB filter, then get all of the possible pictures we could use to match the filter @@ -100,9 +133,9 @@ def _get_filtered_pictures(self): else: # Use filter selected, and filter name specified # Make sure the specified filter exists - query = """SELECT pkFilter FROM FilterWizard""" - query += """ WHERE strFilterName IS '%s'; """ %(self.slideshow_filtername.replace("'","''")) - filter_ids = self.exec_query(query) + query = "Select pkFilter FROM FilterWizard" + query += " WHERE strFilterName = '%s'; " %(self.slideshow_filtername.replace("'","''")) + filter_ids = self._exec_query(query) if len(filter_ids) != 1: # Filter name was not found in the My Pictures Database. message = 'Notification(' + SETTINGS_ERROR + ', ' + BAD_FILTER_NAME_ERROR%(self.slideshow_filtername) + ', 15000, DefaultIconError.png)' @@ -133,10 +166,14 @@ def _start_show(self): # loop until onScreensaverDeactivated is called while (not self.Monitor.abortRequested()) and (not self.stop): # Get the next picture - img_name = self._get_item() + picture = self._get_item() + img_name = os.path.join(picture[0], picture[1]) current_image_control.setImage(img_name, False) + xbmc.sleep(1000) self._set_prop('Fade%d' % order[0], '0') self._set_prop('Fade%d' % order[1], '1') + if (self.slideshow_showinfo): + self._set_info_fields(picture) # define next image if current_image_control == self.image1: current_image_control = self.image2 @@ -146,7 +183,7 @@ def _start_show(self): order = [1,2] # display the image for the specified amount of time - count = timetowait + count = timetowait - 1000 while (not self.Monitor.abortRequested()) and (not self.stop) and count > 0: count -= 1000 xbmc.sleep(1000) @@ -167,20 +204,61 @@ def _get_item(self, update=False): self.filtered_results_index = 0 else: # Not using a filter - result_list = self.exec_query(SINGLE_PICTURE_QUERY) + result_list = self._exec_query(SINGLE_PICTURE_QUERY) result = result_list[0] - (folder, file) = result - return os.path.join(folder, file) + return result + + def _set_info_fields(self, picture): + self._clear_prop('Headline') + self._clear_prop('Caption') + self._clear_prop('Sublocation') + self._clear_prop('City') + self._clear_prop('State') + self._clear_prop('Country') + self._clear_prop('Date') + self._clear_prop('Time') + # Get info to set in window properties + (folder,file) = picture + self._set_prop('Folder',folder) + self._set_prop('File',file) + query = " Select idFile, " + IMGDATETIME[self.db_backend]+ " FROM Files WHERE strPath = '%s' AND strFilename = '%s'; " \ + %(folder.replace("'","''"), file.replace("'","''")) + file_info = self._exec_query(query) + if len(file_info) > 0: + self._set_prop('Date',time.strftime('%A %B %e, %Y',time.strptime(file_info[0][1], '%Y-%m-%d %H:%M:%S'))) + self._set_prop('Time',time.strftime('%I:%M:%S %p',time.strptime(file_info[0][1], '%Y-%m-%d %H:%M:%S'))) + image_id=file_info[0][0] + # Get all of the tags that are on this image + query = " Select idTagContent FROM TagsInFiles WHERE idFile = '%s'; " %(image_id) + content_ids = self._exec_query(query) + for content_id in content_ids: + # Go through each of the tags, and store the ones of interest + query = " Select idTagtype, TagContent FROM TagContents WHERE idTagContent = '%s'; " %(content_id[0]) + tags = self._exec_query(query) + tag_id = tags[0][0] + tag_value = tags[0][1] + if tag_id == self.headline_tagid: + self._set_prop('Headline',tag_value) + elif tag_id == self.caption_tagid: + self._set_prop('Caption',tag_value) + elif tag_id == self.sublocation_tagid: + self._set_prop('Sublocation',tag_value) + elif tag_id == self.city_tagid: + self._set_prop('City',tag_value) + elif tag_id == self.state_tagid: + self._set_prop('State',tag_value) + elif tag_id == self.country_tagid: + self._set_prop('Country',tag_value) # Utility functions - def exec_query(self,query): + def _exec_query(self,query): return MPDB.cur.request(query) def _set_prop(self, name, value): - self.winid.setProperty('SlideView.%s' % name, value) + self.winid.setProperty('Screensaver.%s' % name, value) def _clear_prop(self, name): - self.winid.clearProperty('SlideView.%s' % name) + self.winid.clearProperty('Screensaver.%s' % name) def _exit(self): # exit when onScreensaverDeactivated gets called diff --git a/resources/language/resource.language.en_gb/strings.po b/resources/language/resource.language.en_gb/strings.po index 7cb3098..c312e8b 100644 --- a/resources/language/resource.language.en_gb/strings.po +++ b/resources/language/resource.language.en_gb/strings.po @@ -32,26 +32,30 @@ msgid "Update Filter Names" msgstr "Update Filter Names" msgctxt "#30005" +msgid "Show Picture Information on Slides" +msgstr "Show Picture Information on Slides" + +msgctxt "#30006" msgid "Slideshow settings error" msgstr "Slideshow settings error" -msgctxt "#30006" +msgctxt "#30007" msgid "Filter name was not specified" msgstr "Filter name was not specified" -msgctxt "#30007" +msgctxt "#30008" msgid "Filtername '%s' not found in MyPictures Database" msgstr "Filtername '%s' not found in MyPictures Database" -msgctxt "#30008" +msgctxt "#30009" msgid "No files match filter '%s'in MyPictures Database" msgstr "No files match filter '%s'in MyPictures Database" -msgctxt "#30009" +msgctxt "#30010" msgid "Filter Names Updated" msgstr "Filter Names Updated" -msgctxt "#30010" +msgctxt "#30011" msgid "Exit from 'Settings' and return to see new Filter Names" msgstr "Exit from 'Settings' and return to see new Filter Names" @@ -70,3 +74,7 @@ msgid "The name of the Filter to use for matching." msgctxt "#30104" msgstr "Help for Update Filter Names" msgid "Select this if the list of Filters to choose from is not up-to-date. After updating the Filter Names, you must exit from 'Settings' and return in order to see the updated Filter names." + +msgctxt "#30105" +msgstr "Help for Ahow Picture Inforamtion on Slides" +msgid "Select this to have information about the picture overlayed on top of the picture." diff --git a/resources/settings.xml b/resources/settings.xml index 360f1a6..8371839 100644 --- a/resources/settings.xml +++ b/resources/settings.xml @@ -50,6 +50,12 @@ + + Display picture information + 0 + false + + diff --git a/resources/skins/default/1080i/screensaver.mypicsdb2.slideshow.xml b/resources/skins/default/1080i/screensaver.mypicsdb2.slideshow.xml index f6747ba..b6d3e84 100644 --- a/resources/skins/default/1080i/screensaver.mypicsdb2.slideshow.xml +++ b/resources/skins/default/1080i/screensaver.mypicsdb2.slideshow.xml @@ -1,45 +1,81 @@ - - 0 - 0 + + 0 + 0 1920 1080 - screensaver-black.png - WindowOpen - - - + + screensaver-black.png + WindowOpen + stretch + + image 1 - - + + - - 0 - 0 - 1920 - 1080 - - keep - 0 - + keep - + image 2 - - + + - - 0 - 0 - 1920 - 1080 - - keep - 0 - + keep + + Picture Information + 15 + 20 + 1620 + 180 + bottom + FFFFFFFF + FF000000 + + headline + 30 + !String.IsEmpty(Window.Property(Screensaver.Headline)) + + + + caption + 30 + !String.IsEmpty(Window.Property(Screensaver.Caption)) + + + + location + 30 + + !String.IsEmpty(Window.Property(Screensaver.Sublocation)) | + !String.IsEmpty(Window.Property(Screensaver.City)) | + !String.IsEmpty(Window.Property(Screensaver.State)) | + !String.IsEmpty(Window.Property(Screensaver.Country)) + + + + + date and time + 30 + + !String.IsEmpty(Window.Property(Screensaver.Date)) | + !String.IsEmpty(Window.Property(Screensaver.Time)) + + + + + folder and filename + 30 + + !String.IsEmpty(Window.Property(Screensaver.Folder)) | + !IsEmpty(Window.Property(Screensaver.File)) + + + +