Skip to content

Commit 9527f47

Browse files
authored
Merge pull request #2767 from bossanova808/script.module.bossanova808@matrix
[script.module.bossanova808@matrix] 1.0.2
2 parents 26686e9 + d1e5a22 commit 9527f47

File tree

3 files changed

+167
-5
lines changed

3 files changed

+167
-5
lines changed

script.module.bossanova808/addon.xml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
2-
<addon id="script.module.bossanova808" name="Bossanova808 Dependencies" version="1.0.1" provider-name="bossanova808">
2+
<addon id="script.module.bossanova808" name="Bossanova808 Dependencies" version="1.0.2" provider-name="bossanova808">
33
<requires>
44
<import addon="xbmc.python" version="3.0.0"/>
55
</requires>
@@ -10,8 +10,10 @@
1010
<license>GPL-3.0-only</license>
1111
<website>https://github.com/bossanova808/script.module.bossanova808</website>
1212
<source>https://github.com/bossanova808/script.module.bossanova808</source>
13-
<news>v1.0.1
14-
- Updates for Piers and some defensive programming</news>
13+
<news>v1.0.2
14+
- Fix for previous, for systems using older Python
15+
- Add some more helper functions
16+
</news>
1517
<assets>
1618
<icon>resources/icon.png</icon>
1719
</assets>

script.module.bossanova808/changelog.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
v1.0.2
2+
- Fix for previous, for systems using older Python
3+
- Add some more helper functions
4+
15
v1.0.1
26
- Updates for Piers and some defensive programming
37

script.module.bossanova808/resources/lib/bossanova808/utilities.py

Lines changed: 158 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
1+
from __future__ import annotations
12
import json
23
import re
34
import xbmc
5+
import xbmcaddon
46
import xbmcgui
57
import xbmcvfs
68
import xml.etree.ElementTree as ElementTree
79
from urllib.parse import unquote
810
from typing import Any
911

10-
# noinspection PyPackages
11-
from .constants import ADDON
12+
13+
# (TODO - once OzWeather 2.1.6 and all the other addons updates are released, the * here can just be ADDON again, sigh)
14+
# noinspection PyPackages,PyUnusedImports
15+
from .constants import *
1216
# noinspection PyPackages
1317
from .logger import Logger
1418

@@ -214,6 +218,131 @@ def is_playback_paused() -> bool:
214218
return bool(xbmc.getCondVisibility("Player.Paused"))
215219

216220

221+
def get_addon_version(addon_id: str) -> str | None:
222+
"""
223+
Helper function to return the currently installed version of Kodi addon by its ID.
224+
225+
:param addon_id: the ID of the addon, e.g. weather.ozweather
226+
:return: the version string (e.g. "0.0.1"), or None if the addon is not installed and enabled
227+
"""
228+
try:
229+
addon = xbmcaddon.Addon(id=addon_id)
230+
version = addon.getAddonInfo('version')
231+
except RuntimeError as e:
232+
Logger.error(f"Error getting version for {addon_id}")
233+
Logger.error(e)
234+
return None
235+
236+
return version
237+
238+
239+
def version_tuple(version_str: str) -> tuple:
240+
"""
241+
Helper function to return a version tuple from a version string "2.1.5" -> (2, 1 , 5)
242+
Useful for comparisons, e.g. if version_tuple(version) <= version_tuple('2.1.5')
243+
244+
:param version_str: the addon version string
245+
:return: version in tuple form (1, 2, 3)
246+
"""
247+
return tuple(map(int, version_str.split('.')))
248+
249+
250+
def get_resume_point(library_type: str, dbid: int) -> float | None:
251+
"""
252+
Get the resume point from the Kodi library for a given Kodi DB item
253+
254+
:param library_type: one of 'episode', 'movie' or 'musicvideo'
255+
:param dbid: the Kodi DB item ID
256+
:return: the resume point, or None if there isn't one set
257+
"""
258+
259+
params = _get_jsonrpc_video_lib_params(library_type)
260+
# Short circuit if there is an issue get the JSON RPC method etc.
261+
if not params:
262+
return None
263+
get_method, id_name, result_key = params
264+
265+
json_dict = {
266+
"jsonrpc":"2.0",
267+
"id":"getResumePoint",
268+
"method":get_method,
269+
"params":{
270+
id_name:dbid,
271+
"properties":["resume"],
272+
}
273+
}
274+
275+
query = json.dumps(json_dict)
276+
json_response = send_kodi_json(f'Get resume point for {library_type} with dbid: {dbid}', query)
277+
if not json_response:
278+
Logger.error("Nothing returned from JSON-RPC query")
279+
return None
280+
281+
result = json_response.get('result')
282+
if result:
283+
try:
284+
resume_point = result[result_key]['resume']['position']
285+
except (KeyError, TypeError) as e:
286+
Logger.error("Could not get resume point")
287+
Logger.error(e)
288+
resume_point = None
289+
else:
290+
Logger.error("No result returned from JSON-RPC query")
291+
resume_point = None
292+
293+
Logger.info(f"Resume point retrieved: {resume_point}")
294+
295+
return resume_point
296+
297+
298+
def get_playcount(library_type: str, dbid: int) -> int | None:
299+
"""
300+
Get the playcount for the given Kodi DB item
301+
302+
:param library_type: one of 'episode', 'movie' or 'musicvideo'
303+
:param dbid: the Kodi DB item ID
304+
:return: the playcount if there is one, or None
305+
"""
306+
307+
params = _get_jsonrpc_video_lib_params(library_type)
308+
# Short circuit if there is an issue get the JSON RPC method etc.
309+
if not params:
310+
return None
311+
get_method, id_name, result_key = params
312+
313+
json_dict = {
314+
"jsonrpc":"2.0",
315+
"id":"getPlayCount",
316+
"method":get_method,
317+
"params":{
318+
id_name:dbid,
319+
"properties":["playcount"],
320+
}
321+
}
322+
323+
query = json.dumps(json_dict)
324+
json_response = send_kodi_json(f'Get playcount for {library_type} with dbid: {dbid}', query)
325+
if not json_response:
326+
Logger.error("Nothing returned from JSON-RPC query")
327+
return None
328+
329+
result = json_response.get('result')
330+
if result:
331+
try:
332+
play_count = result[result_key]['playcount']
333+
except (KeyError, TypeError) as e:
334+
Logger.error("Could not get playcount")
335+
Logger.error(e)
336+
play_count = None
337+
else:
338+
Logger.error("No result returned from JSON-RPC query")
339+
play_count = None
340+
341+
Logger.info(f"Playcount retrieved: {play_count}")
342+
343+
return play_count
344+
345+
217346
def footprints(startup: bool = True) -> None:
218347
"""
219348
TODO - this has moved to Logger - update all addons to use Logger.start/.stop directly, then ultimately remove this!
@@ -225,3 +354,30 @@ def footprints(startup: bool = True) -> None:
225354
Logger.start()
226355
else:
227356
Logger.stop()
357+
358+
359+
def _get_jsonrpc_video_lib_params(library_type: str) -> tuple[str, str, str] | None:
360+
"""
361+
Given a Kodi library type, return the JSON RPC library parameters needed to get details
362+
363+
:param library_type: one of 'episode', 'movie' or 'musicvideo'
364+
:return: method for getting details, the name of the id, and the key for the results returned
365+
"""
366+
367+
if library_type == 'episode':
368+
get_method = 'VideoLibrary.GetEpisodeDetails'
369+
id_name = 'episodeid'
370+
result_key = 'episodedetails'
371+
elif library_type == 'movie':
372+
get_method = 'VideoLibrary.GetMovieDetails'
373+
id_name = 'movieid'
374+
result_key = 'moviedetails'
375+
elif library_type == 'musicvideo':
376+
get_method = 'VideoLibrary.GetMusicVideoDetails'
377+
id_name = 'musicvideoid'
378+
result_key = 'musicvideodetails'
379+
else:
380+
Logger.error(f"Unsupported library type: {library_type}")
381+
return None
382+
383+
return get_method, id_name, result_key

0 commit comments

Comments
 (0)