@noggin I don’t know if this helps:
Thanks @Betatester - that’s interesting - not sure how it relates to what we get out the other side in terms of VideoPlayer InfoLabels - but it may show some mappings.
I think everything will have a Title - which will be the episode title in TVShows, the movie title in Movies and the filename if the playing item is video but not in a TV Show or Movie or Music Video Library. Only TV Shows in a series have a TVShowTitle - which is the actual name of the TV show each episode belongs to rather than episode titles. I get why Kodi works this way - as each Title should be pretty unique for each entry (which wouldn’t be the case if there was a Title that was the title of the TV Show, and rather than a TV Show Title field, there was instead a sub-field called TVEpisodeTitle - but that would have made rendering easier )
Ok, I think kodi_panel v1.12 should go at least part way in tackling this. Changes are as as follows:
-
The layout dictionary to use is determined once, in either
audio_screens()
orvideo_screens()
. Previously, the various rendering functions each independently looked up the entry to use. -
Per the commented-out text added to
example_setup_800x480.py
, one can set a newVLAYOUT_AUTOSELECT
flag in thesetup.toml
file. If that flag gets set totrue
, then the usual cycle-through-modes based on the touch interrupt does not occur.- Per @noggin’s remarks, not everyone is going to have a touch screen. Stepping through different layouts, if there are already non-trivial differences based upon different video types, also seems less needed.
- I thus decided to let the different layouts based on different video material all reside as different sub-dictionaries within
V_LAYOUT
. That decision can always be revisited later.
-
At present,
video_screens()
does not yet implement the selection heuristic. The spot at which it should be added is marked with a “NOTE” comment, though. -
Finally, I also added a few additional InfoLabels to the JSON-RPC call that is made for the VideoPlayer.
With these changes, and the auto-selection flag set, you can then experiment with picking a different layout
early in the execution flow of video_screens()
. For example:
if VIDEO_LAYOUT_AUTOSELECT:
if info["VideoPlayer.ChannelName"] != '':
layout = VIDEO_LAYOUT["LIVE_TV"]
elif info["VideoPlayer.TVShowTitle" != '']:
layout = VIDEO_LAYOUT["TV_FILE"]
else:
pass # leave as-is
where you’ve defined (in the setup TOML file) LIVE_TV
and TV_FILE
layouts to use.
That’s the idea, anyway. It should at least permit for more experimentation.
Matt
Wow - amazing Matt. Will have a test sometime this evening (UK time)
So looking at this - I need to setup areas in set-up.toml for PVR (LIVE_TV - though I think a recording in PVR will also be valid) and TV_SHOW (TV_FILE) alongside V_DEFAULT and add these to the VLAYOUT_NAMES array?
And then add the VIDEO_LAYOUT_AUTOSELECT code snippet above to kodi_panel_display.py
or am I misunderstanding the concept of sub-dictionaries within the V_LAYOUT area of setup.toml?
You have it correct, @noggin.
The idea is to make use of the different layouts that the data structures already permit. A bit of Python coding is needed in video_screens()
within kodi_panel_display.py to make the decision regarding which of the (new) layouts to use.
I don’t really have any means of testing, since I only have movies and have never experimented with Kodi’s video recording capabilities. So, you (and anyone else who has the capability) will have to see how best to differentiate the various video materials.
Note that the heuristic is free to “point” to the same layout multiple times, or just fall-through and use the default layout. The video_text_fields()
function still tests to make sure that fields exist, so non-populated InfoLabels work the same as before.
Finally, we still have the option of defining “special treatment” for some layout contents, if needed. Hopefully, the ability to pick among layouts eliminates some of that.
Cheers,
Matt
You’re free to make the names of the new layouts anything that makes sense – they’re just strings and the only requirement is that those strings match whatever lookups / selections the heuristic if-then-else makes.
So in setup.toml I could have :
[[V_LAYOUT.V_TVSHOW.fields]]
or
[[V_LAYOUT.V_PVR.fields]]
and in kodi_panel_display.py
if VIDEO_LAYOUT_AUTOSELECT:
if info["VideoPlayer.ChannelName"] != '':
layout = VIDEO_LAYOUT["V_PVR"]
elif info["VideoPlayer.TVShowTitle" != '']:
layout = VIDEO_LAYOUT["V_TVSHOW"]
else:
pass # leave as-is
?
Close.
The dictionary first gets defined when a new (hierarchical) name get specified between single brackets. For instance, the A_LAYOUT[“A_DEFAULT”] dictionary first gets “started” after parsing this excerpt of TOML code:
#
# Default audio info screen
#
[A_LAYOUT.A_DEFAULT.thumb] # Artwork
posx = 3
posy = 4
size = 405
# If artwork is smaller than the above size, should it be centered
# where the fullsize artwork would have been placed?
center_sm = 1
The result of the above is to populate three levels of dictionary – the variable A_LAYOUT containing a dictionary with the key “A_DEFAULT” that then contains just a dictionary with the key “thumb”. That final level then has all the keys listed above (posx, posy, etc).
The next excerpt from the TOML file:
[A_LAYOUT.A_DEFAULT.prog]
and the lines that follow serve to add a “prog” dictionary within the “A_DEFAULT” dictionary.
Finally, the double-bracket syntax in TOML serves to create an array. All of the text fields that a layout specifies thus gets dumped into the array that Python code ends up referencing via (essentially)
// Python <-> TOML
A_LAYOUT["A_DEFAULT"]["fields"] defined via [[A_LAYOUT.A_DEFAULT.fields]] entries
The double-brackets effectively inform TOML that it is appending to an array, rather then re-defining what was previously specified.
So, if all a layout needs to render is a set of text fields, then you would just have various double-bracket lines. If a progress bar or artwork is also needed, then you should first start out with a single-bracket entry.
A like having code that is guided by data structures, but getting those data structure built correctly can sometimes be tricky. The TOML syntax (and available Python parser) provided an alternative from using just a pure Python configuration/setup file. Hopefully the syntax isn’t too bad!
Regards,
Matt
The hierarchical structure of the layout can be observed by how the various functions make use of it. All of the artwork fetches, for example, just check for an entry in the “first level” of the layout dictionary:
# retrieve cover image from Kodi, if it exists and needs a refresh
if "thumb" in layout.keys():
The *_text_fields()
functions get their hands on the “fields” array and then step through it:
# Text fields (all except for MusicPlayer.Time)
txt_field = layout.get("fields", [])
for index in range(len(txt_field)):
Matt
Thanks Matt - just worked that out too! I now appear to have TV Show and PVR options
There was a ] in the wrong place in the checking code in kodi_panel_display.py which I found on my own
Let me know if used the if-then-else as suggested above or arrive at something different. If you provide your code, I can replace the NOTE:
and that will form v1.13 for kodi_panel.
Thanks,
Matt
Hi Matt
The two criteria for differentiating PVR and TV Shows seem to be working for my set-up and I now have three different display layouts - one for TV Shows in my TV Show library, one for PVR (Live and Recorded TV) and one for everything else. (Have added VideoResolution and Plot fields to VideoPlayer params list)
Is there a way of adding suffix/prefix texts to the JSON-queried results via setup.toml? For instance if I query episode number and series/season number - can I hard code S/Series or E/Episode as a pre-fix for these results - or just a “/” delimiter between them - or does that need to be a special case in kodi_panel_display ?
The two criteria for differentiating PVR and TV Shows seem to be working for my set-up and I now have three different display layouts - one for TV Shows in my TV Show library, one for PVR (Live and Recorded TV) and one for everything else. (Have added VideoResolution and Plot fields to VideoPlayer params list)
Great. I’ll add the previously-proposed if-then code.
Is there a way of adding suffix/prefix texts to the JSON-queried results via setup.toml? For instance if I query episode number and series/season number - can I hard code S/Series or E/Episode as a pre-fix for these results - or just a “/” delimiter between them - or does that need to be a special case in kodi_panel_display ?
I’ll look at allowing each text_field to specify prefix and suffix text, to be concatenated with the InfoLabel prior to rendering.
Having multiple InfoLabels in one display string would, at present, be a special case. If I were writing this in Perl, I would go down the path of letting Perl’s double-quoted string interpolation handle everything – the strings specified in the TOML file would just include InfoLabel references as lookups in a Perl hash (akin to a dictionary). I don’t presently know enough about Python to pursue a similar approach. Doing so also adds new corner cases – e.g., do all of the referenced InfoLabels in a display string need to be non-empty?
The prefix and suffix should be simple, though.
Matt
Thanks Matt
The only issue with the previously proposed code appears to be an errant ] in the wrong place.
I’m using :
if VIDEO_LAYOUT_AUTOSELECT:
if info["VideoPlayer.ChannelName"] != '':
layout = VIDEO_LAYOUT["V_PVR"]
elif info["VideoPlayer.TVShowTitle"] != '':
layout = VIDEO_LAYOUT["V_TV_SHOW"]
else:
pass # leave as-is
My video Infolabels are :
# Retrieve video InfoLabels in a single JSON-RPC call
payload = {
"jsonrpc": "2.0",
"method" : "XBMC.GetInfoLabels",
"params" : {"labels": ["VideoPlayer.Title",
"VideoPlayer.TVShowTitle",
"VideoPlayer.Season",
"VideoPlayer.Episode",
"VideoPlayer.EpisodeName",
"VideoPlayer.PlotOutline",
"VideoPlayer.Plot",
"VideoPlayer.Duration",
"VideoPlayer.Time",
"VideoPlayer.Genre",
"VideoPlayer.Year",
"VideoPlayer.VideoCodec",
"VideoPlayer.AudioCodec",
"VideoPlayer.VideoResolution",
"VideoPlayer.ChannelName",
"VideoPlayer.ChannelNumberLabel",
"VideoPlayer.Rating",
"VideoPlayer.ParentalRating",
"VideoPlayer.Cover",
]},
"id" : 4,
}
I have V_PVR and V_TV_SHOW layouts along with V_DEFAULT in my setup.toml
The only thing I think may be an issue with the ChannelName check is that some channels may have null names - but equally I think a null channel number is also valid. Not sure there is an easy solution and this PVR check works for me. (I use PVR to differentiate between PVR TV Shows and Library TV Shows)
Ok, kodi_panel v1.14 has the following updates:
Added (optional) prefix and suffix strings for each text InfoLabel within the “fields” array for screens (including the Status screen).
Provide at least preliminary heuristic for making video screen auto-selection based on populated VideoPlayer InfoLabels, selecting between PVR TV, Library TV, and Movies.
Added Plot and PlotOutline to InfoLabels retrieved from VideoPlayer.
Give it a try.
Are you making use of Plot and PlotOutline? I worry a little how much text that might be, and whether it slows things down at all.
It should support everything discussed above, other than a “combo” season/episode number (separated with a slash). I think you could make use of the prefix to place a slash ahead of whichever field you want to appear second (just requiring some care to place both fields with the same vertical position). Alternatively, we can add a special-case for that combination.
I’ll keep reading about Python strings and see if an interpolation approach might be worthwhile.
Matt
I’ve tried to document all of the key/value pairs that are available for text fields. All of the example_*.toml files have been updated.
The video-mode / screen requirements for making use of VLAYOUT_AUTOSELECT
are also documented in those example files.
So far Plot works OK on my test set-up (which is a Pi 4B 2GB with an 800x480 HyperPixel 4.0) but I haven’t been paying attention to speed of update of elapsed time so much. As for type size - one of my reasons behind a separate display is to not put it physically as far away as my Kodi player device, but to have it on the coffee table. (I quite like the idea of it not being physically tied to the media player).
Next thing to work on is dimming after a certain period (And coming back after a transport button change - which I think is probably trickier to detect)
And yes - get your points about Suffix and Prefix fields. I’m using a non-proportional font for my displays so layout spacing is probably a bit easier. (Bedstead aka Teletext was designed for a fixed 40 column character grid back in the day)
Verging far too much into Python territory rather than a Kodi or CoreELEC topic of general interest, but I just found this:
https://docs.python.org/3/library/stdtypes.html#str.format_map
which is just what the doctor ordered:
str.format_map(mapping)
Similar to
str.format(**mapping)
, except that mapping is used directly and not copied to a dict. This is useful if for example mapping is a dict subclass:class Default(dict): def __missing__(self, key): return key
'{name} was born in {country}'.format_map(Default(name='Guido'))
'Guido was born in country'
New in version 3.2.
I was thinking that Python’s format_map()
would immediately let me provide string interpolation (substitution) for available Kodi InfoLabels. Unfortunately, the presence of a dot (period) within all of the Kodi InfoLabels adds a bit of a wrinkle. Python’s string formatter approach wants to permit the ability to invoke methods or attributes on a variable. So, the presence of the dot in “System.” prevents using the whole identifier as a string. A key error gets thrown, since there is no “System” entry within the dictionary holding the InfoLabels.
I worked around the above by making my own format_InfoLabels()
function.
Version 1.1.5 now lets one specify a format_str
for fields(s), rather than prefix
and suffix
. For instance, one can get a text display showing both CPU temperature and CPU frequency on the status screen with a single entry such as this in the TOML setup file:
[[STATUS_LAYOUT.fields]]
name = "System.CPUTemperature"
posx = 5
posy = 250
format_str = "CPU: {System.CPUTemperature}, {System.CpuFrequency}"
font = "font_sm"
fill = "white"
The format_str
string is what gets used for display, after substituting the expressions within curly braces.
The above lets one combine more than one InfoLabel into a single string to display, as long as you’re content with whatever gets constructed should one or more of those InfoLabels be empty. As was the case previously, the "name"
label has to be non-empty for a text field to even get processed for display. So, that field is at least guaranteed to be available when format_str
gets processed.
Cheers,
Matt