Skip to content

Commit

Permalink
script.copacetic.helper-1.1.5
Browse files Browse the repository at this point in the history
  • Loading branch information
realcopacetic committed Aug 5, 2024
1 parent a98850c commit b2e33ee
Show file tree
Hide file tree
Showing 6 changed files with 175 additions and 105 deletions.
16 changes: 16 additions & 0 deletions script.copacetic.helper/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,22 @@ All code contained in this project is licensed under GPL 3.0.
* __jurialmunkey__ for all the best-practice code examples from [plugin.video.themoviedb.helper](https://github.com/jurialmunkey/plugin.video.themoviedb.helper) and forum support.

### Changelog
---
**1.1.5**
- Fixed bug in actor_credits() where the current infoscreen item was not being removed from the 'More from X' actor credits widget if the infoscreen was for an episode, because it was expecting to find the TV show title in ListItem.Label and instead receiving the episode name, which wouldn't ever match.

**1.1.4**
- Fixed bug with infoscreen widgets not updating when navigating between infoscreens by ensuring director and genre properties update each time the infoscreen is loaded, even if the underlying list hasn't been scrolled
- Added season info monitoring
- Added a window property that is set to true while set progress is being calculated in get_collection_status()

**1.1.3**
- Fixed conditional that was preventing cropped clearlogo paths from being fetched for home widgets

**.1.1.2**
- Support for more edge case conversions of different image modes in clearlogo_cropper().
- Added method to service monitor to calculate watched percentage of sets and return as a property

**.1.1.1**
- Fixed bug in previous version causing dark cropped clearlogos to always be served in certain scenarios

Expand Down
2 changes: 1 addition & 1 deletion script.copacetic.helper/addon.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<addon id="script.copacetic.helper" name="Copacetic Helper" version="1.1.1" provider-name="realcopacetic">
<addon id="script.copacetic.helper" name="Copacetic Helper" version="1.1.5" provider-name="realcopacetic">
<requires>
<import addon="xbmc.python" version="3.0.1" />
<import addon="script.module.pil" version="5.1.0" />
Expand Down
15 changes: 10 additions & 5 deletions script.copacetic.helper/resources/lib/plugin/content.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from resources.lib.plugin.json_map import JSON_MAP
from resources.lib.plugin.library import *
from resources.lib.utilities import (ADDON, infolabel, json_call, log,
from resources.lib.utilities import (ADDON, condition, infolabel, json_call, log,
set_plugincontent)


Expand Down Expand Up @@ -224,8 +224,12 @@ def director_credits(self):

def actor_credits(self):
filters = [self.filter_actor]
current_item = infolabel('ListItem.Label')

# grab current movie or tvshow name
if condition('String.IsEqual(ListItem.DBType,episode)'):
current_item = infolabel('ListItem.TVShowTitle')
else:
current_item = infolabel('ListItem.Label')
# json lookup for movies and tvshows by given actor
movies_json_query = json_call('VideoLibrary.GetMovies',
properties=JSON_MAP['movie_properties'],
sort=self.sort_year,
Expand All @@ -239,10 +243,11 @@ def actor_credits(self):
query_filter={'and': filters},
parent='actor_credits'
)

# work out combined number of movie/tvshow credits
total_items = int(movies_json_query['result']['limits']['total']) + int(
tvshows_json_query['result']['limits']['total'])

# if there are movie results, remove the current item if it is in the list, then add the remaining to the plugin directory
try:
movies_json_query = movies_json_query['result']['movies']
except Exception:
Expand All @@ -253,7 +258,7 @@ def actor_credits(self):
movies_json_query.remove(
dict_to_remove) if dict_to_remove is not None and total_items > 1 else None
add_items(self.li, movies_json_query, type='movie')

# if there are tvshow results, remove the current item if it is in the list, then add the remaining to the plugin directory
try:
tvshows_json_query = tvshows_json_query['result']['tvshows']
except Exception:
Expand Down
33 changes: 33 additions & 0 deletions script.copacetic.helper/resources/lib/script/actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,39 @@ def dialog_yesno(heading, message, **kwargs):
log_and_execute(action)


def get_collection_status(dbid, **kwargs):
window_property('collection_watched_calculating', set='true')
watched = 0
query = json_call(
'VideoLibrary.GetMovieSetDetails',
params={'setid': int(dbid)},
parent='get_set_movies'
)
try:
total = query['result']['setdetails']['limits']['total']
movies = query['result']['setdetails']['movies']
except KeyError:
return
else:
for movie in movies:
query = json_call(
'VideoLibrary.GetMovieDetails',
params={'properties': [
'playcount'], 'movieid': movie['movieid']},
parent='get_movie_playcounts'
)
playcount = query['result']['moviedetails'].get('playcount')
if playcount:
watched += 1
finally:
# https://stackoverflow.com/a/68118106/21112145
percentage = (total and watched / total or 0) * 100
unwatched = total - watched
window_property('collection_watched_calculating', clear=True)
window_property('collection_watched_dbid', set=dbid)
window_property('collection_watched_percentage', set=percentage)
window_property('collection_unwatched', set=unwatched)

def globalsearch_input(**kwargs):
kb = xbmc.Keyboard(
infolabel('$INFO[Skin.String(globalsearch)]'), infolabel('$LOCALIZE[137]'))
Expand Down
9 changes: 4 additions & 5 deletions script.copacetic.helper/resources/lib/service/art.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,9 @@ def crop_image(self, url):
log(
f'ImageEditor: Error - could not open cached image --> {error}', force=True)
else:
if image.mode == 'LA': # Convert if mode == 'LA'
converted_image = Image.new("RGBA", image.size)
converted_image.paste(image)
image = converted_image
converted_image = Image.new("RGBA", image.size)
converted_image.paste(image)
image = converted_image
try:
image = image.crop(image.convert('RGBa').getbbox())
except ValueError as error:
Expand Down Expand Up @@ -418,7 +417,7 @@ def _set_art(self, key, items):
clearlogo = art.get('clearlogo-billboard', False)
if not clearlogo:
clearlogo = art.get('clearlogo', False)
if clearlogo and condition('!Skin.HasSetting(Experiment_Disable_Transitions)'):
if clearlogo and condition('!Skin.HasSetting(Quick_Transitions)'):
clearlogo = url_decode_path(clearlogo)
clearlogo = self._crop_clearlogo(clearlogo)
window_property(f'{key}_clearlogo', set=clearlogo)
Expand Down
205 changes: 111 additions & 94 deletions script.copacetic.helper/resources/lib/service/monitor.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from resources.lib.service.settings import SettingsMonitor
from resources.lib.utilities import (CROPPED_FOLDERPATH, LOOKUP_XML,
TEMP_FOLDERPATH, condition, create_dir,
get_cache_size, infolabel, log,
get_cache_size, infolabel, json_call, log,
log_and_execute, split,
split_random_return, validate_path,
window_property)
Expand Down Expand Up @@ -42,6 +42,15 @@ def __init__(self):
self._create_dirs()
self._on_start()

def _conditions_met(self):
return (
self._get_skindir() and not self.idle
)

def _container_scrolling(self, key='ListItem'):
container = 'Container' if key == 'ListItem' else f'Container({key})'
return condition(f'{container}.Scrolling')

def _create_dirs(self):
if not validate_path(self.cropped_folder):
create_dir(self.cropped_folder)
Expand All @@ -52,6 +61,73 @@ def _create_dirs(self):
ET.ElementTree(root).write(
self.lookup, xml_declaration=True, encoding="utf-8")

def _current_item(self, key='ListItem'):
container = 'Container' if key == 'ListItem' else f'Container({key})'
item = infolabel(f'{container}.CurrentItem')
dbid = infolabel(f'{container}.ListItem.DBID')
dbtype = infolabel(f'{container}.ListItem.DBType')
return (container, item, dbid, dbtype)

def _get_info(self):
split_random_return(
infolabel('ListItem.Director'), name='RandomDirector')
split_random_return(
infolabel('ListItem.Genre'), name='RandomGenre')
split(infolabel('ListItem.Writer'), name='WriterSplit')
split(infolabel('ListItem.Studio'), name='StudioSplit')

def _get_season_info(self, container):
window_property('Season_Number', infolabel(
f'{container}.ListItem.Season'))
window_property('Season_Year', infolabel(
f'{container}.ListItem.Year'))
window_property('Season_Fanart', infolabel(
f'{container}.ListItem.Art(fanart)'))

def _get_skindir(self):
skindir = xbmc.getSkinDir()
if 'skin.copacetic' in skindir:
return True

def _on_recommendedsettings(self):
if condition('Window.Is(skinsettings)') and self.check_settings:
self.settings_monitor.get_default()
self.check_settings = False
elif not condition('Window.Is(skinsettings)'):
self.check_settings = True
if condition('Skin.HasSetting(run_set_default)'):
self.settings_monitor.set_default()
self.check_settings = True
log_and_execute('Skin.ToggleSetting(run_set_default)')

def _on_scroll_functions(self, key='ListItem', crop=True, return_color=True, get_info=False, get_season_info=True):
path, current_item, current_dbid, current_dbtype = self._current_item(
key)
if (
current_item != self.position or
current_dbid != self.dbid or
current_dbtype != self.dbtype
) and not self._container_scrolling(key):
if crop and condition(
'Skin.HasSetting(Crop_Clearlogos)'
):
self._clearlogo_cropper(
source=key, return_color=return_color, reporting=window_property)
if get_info:
self._get_info()
if get_season_info:
self._get_season_info(path)
self.position = current_item
self.dbid = current_dbid
self.dbtype = current_dbtype

def _on_skinsettings(self):
if condition('Window.Is(skinsettings)') and self.check_cache:
get_cache_size()
self.check_cache = False
elif condition('!Window.Is(skinsettings)'):
self.check_cach = True

def _on_start(self):
if self.start:
log('Monitor started', force=True)
Expand All @@ -64,23 +140,18 @@ def _on_start(self):
self.poller()
self._on_stop()

def _conditions_met(self):
return (
self._get_skindir() and not self.idle
)

def _get_skindir(self):
skindir = xbmc.getSkinDir()
if 'skin.copacetic' in skindir:
return True

def _get_info(self):
split_random_return(
infolabel('ListItem.Director'), name='RandomDirector')
split_random_return(
infolabel('ListItem.Genre'), name='RandomGenre')
split(infolabel('ListItem.Writer'), name='WriterSplit')
split(infolabel('ListItem.Studio'), name='StudioSplit')
def _on_stop(self):
log(f'Monitor idle', force=True)
while not self.abortRequested() and not self._conditions_met():
self.waitForAbort(2)
if not self.abortRequested():
self._on_start()
else:
self.art_monitor.fanart_write()
del self.player_monitor
del self.settings_monitor
del self.art_monitor
log(f'Monitor stopped', force=True)

def poller(self):
# video playing fullscreen
Expand All @@ -104,26 +175,31 @@ def poller(self):
'Control.HasFocus(3208) | '
'Control.HasFocus(3209)]'
):
self._on_scroll(crop=False, return_color=False, get_info=True)
self._get_info()
self._on_scroll_functions(
crop=False, return_color=False, get_info=True, get_season_info=False)
self.waitForAbort(0.2)

# secondary list has focus and clearlogo view visible
# media view is visible and container content type not empty
elif condition(
'Skin.HasSetting(Crop_Clearlogos) + '
'Control.HasFocus(3100) + ['
'Control.IsVisible(501) | Control.IsVisible(502) | Control.IsVisible(504)]'
):
self._on_scroll(key='3100', return_color=False)
self.waitForAbort(0.2)

# clearlogo view visible
elif condition(
'Skin.HasSetting(Crop_Clearlogos) + ['
'Control.IsVisible(501) | '
'Control.IsVisible(502) | '
'Control.IsVisible(504)]'
'[Window.Is(videos) | Window.Is(music)] + '
'[Container.Content(movies) | '
'Container.Content(sets) | '
'Container.Content(tvshows) | '
'Container.Content(seasons) | '
'Container.Content(episodes) | '
'Container.Content(videos) | '
'Container.Content(artists) | '
'Container.Content(albums) | '
'Container.Content(songs) | '
'Container.Content(musicvideos)]'
):
self._on_scroll()
# secondary
if condition('Control.HasFocus(3100)'):
self._on_scroll_functions(key='3100', return_color=False)
# primary
else:
self._on_scroll_functions()
self.waitForAbort(0.2)

# home widgets has clearlogo visible
Expand All @@ -141,7 +217,7 @@ def poller(self):
'Control.HasFocus(3209)]'
):
widget = infolabel('System.CurrentControlID')
self._on_scroll(key=widget)
self._on_scroll_functions(key=widget)
self.waitForAbort(0.2)

# slideshow window is visible run SlideshowMonitor()
Expand Down Expand Up @@ -187,65 +263,6 @@ def poller(self):
self.check_settings = True
self.waitForAbort(1)

def _on_scroll(self, key='ListItem', crop=True, return_color=True, get_info=False):
path, current_item, current_dbid, current_dbtype = self._current_item(
key)
if (
current_item != self.position or
current_dbid != self.dbid or
current_dbtype != self.dbtype
) and not self._container_scrolling(key):
if crop and condition('!Skin.HasSetting(Experiment_Disable_Transitions)'):
self._clearlogo_cropper(
source=key, return_color=return_color, reporting=window_property)
if get_info:
self._get_info()
self.position = current_item
self.dbid = current_dbid
self.dbtype = current_dbtype

def _on_skinsettings(self):
if condition('Window.Is(skinsettings)') and self.check_cache:
get_cache_size()
self.check_cache = False
elif condition('!Window.Is(skinsettings)'):
self.check_cach = True

def _on_recommendedsettings(self):
if condition('Window.Is(skinsettings)') and self.check_settings:
self.settings_monitor.get_default()
self.check_settings = False
elif not condition('Window.Is(skinsettings)'):
self.check_settings = True
if condition('Skin.HasSetting(run_set_default)'):
self.settings_monitor.set_default()
self.check_settings = True
log_and_execute('Skin.ToggleSetting(run_set_default)')

def _on_stop(self):
log(f'Monitor idle', force=True)
while not self.abortRequested() and not self._conditions_met():
self.waitForAbort(2)
if not self.abortRequested():
self._on_start()
else:
self.art_monitor.fanart_write()
del self.player_monitor
del self.settings_monitor
del self.art_monitor
log(f'Monitor stopped', force=True)

def _current_item(self, key='ListItem'):
container = 'Container' if key == 'ListItem' else f'Container({key})'
item = infolabel(f'{container}.CurrentItem')
dbid = infolabel(f'{container}.ListItem.DBID')
dbtype = infolabel(f'{container}.ListItem.DBType')
return (container, item, dbid, dbtype)

def _container_scrolling(self, key='ListItem'):
container = 'Container' if key == 'ListItem' else f'Container({key})'
return condition(f'{container}.Scrolling')

def onScreensaverActivated(self):
self.idle = True

Expand Down

0 comments on commit b2e33ee

Please sign in to comment.