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)) + + + +