Get Last 4 Characters of Filename, File Extension is Unknown Length

I had some code:

action: input_select.select_option
metadata: {}
data:
  option: "{{ \"AR \" ~ trigger.json.PlaybackInfo.MediaSource.Path[-8:-4] }}"
target:
  entity_id: input_select.aspect_ratio

Worked fine when I was playing .mp4 and .mkv files. But falls apart if I play a .ts file, obviously. I could set it up as a Choose Action for each possible extension, but that’s clumsy and could fail if I have any other file extensions at any point in the future. Is there a way I can dispense with the file extension and go forward from there, so it runs the same thing no matter what the file extension is and gets the correct result?

To summarize what I’m doing: I have the aspect ratio of each of my videos at the end of the filename, eg

Barbie (2023) - 2.00.mkv

The automation grabs that at the start of playback and puts it into the helper, which is then used to control the projector and masking to set the screen correctly.

Not sure if this will work in all cases but in this case it seems to work.

{{ "Barbie (2023) - 2.00.mkv" | regex_findall("-\s*(\d*\.\d*)") }} 

If we want to be specific to what you are asking for that it should be the last four characters of the filename then this should do it:

{{ "Barbie (2023) - 2.00.mkv" | regex_findall("([\w\.]{4})\.\D{2,4}") }}

It assumes a dot and two to four characters is the extension, and the previous four characters is the format.

A third method:

{{ "Barbie (2023) - 2.10.MP4" | regex_findall("([\d\.]{4})\.\w+$") }}

The $ means it requires end of string.
So more than one character from end, find a dot.
The previous four characters is matched if they are digits and a dot.

I’m not particularly fluent in regex but it looks like the first fails if there’s a number in the correct format anywhere else in the filename, and the second fails if there’s a period anywhere else in the filename? So “Mrs. Doubtfire (1994) - 2.40.mkv” and “9.79 (2012) - 1.78.mkv” would both trip it up?

Both of those examples work on the first code as I can see.
I’m not at home anymore so I just tested it quickly on the phone.

The second code does have a bug, I thought of that when I left home.
It won’t work on MP4 file names since it has a digit in the extension.

But the first one only relies on the dash.

{% set name = "9.79 (2012) - 1.78.mkv" %}
{{ name[::-1].split('.',1)[1][:4][::-1] }}

Note that the Developer Tools / Template editor will incorrectly display e.g. “2.00” as 2, but the template is returning the correct characters. Add quotes to the second line if you want to see this: "{{ ... }}" will return "2.00". Template:

  • reverses the filename
  • takes the first four characters after the first dot
  • reverses it again
1 Like

Yeah, that’s why I’m appending “AR” to the front in my actual automation; I kept running into that issue and there’s no way to tell it to use all the decimal places or force it to treat it as a string.

Will give that one a go.

One character shorter:

"{{ ".".join(name.split('.')[:-1])[-4:] }}"
  • splits on the dots
  • rejoins everything up to and excluding the last split item
  • takes the last four characters

There is also an rsplit function, which gets things from the end:

{{ name.rsplit('.',1)[0][-4:] }}
2 Likes

Force it to string.
Example:

{{ ("Barbie (2023) - 2.00.MP4" | regex_findall("([\d\.]{4})\.\w+$"))[0] | string }}

rsplit is the route to go.

That doesn’t work with the resolver that runs after the template executes.

Only way to enforce a string (or any data type) on a field is to template the entire data section so the resolver see’s a complex type and doesn’t enforce simple typing.

action: input_select.select_option
metadata: {}
data: >
  {{ dict(option= "AR " ~ trigger.json.PlaybackInfo.MediaSource.Path.rsplit('.',1)[0][-4:]) }}
target:
  entity_id: input_select.aspect_ratio