Page 1 of 1

Having a brainfart moment. (Get key from array match.)

Posted: 16 Aug 2025, 01:40
by Wolfie
Episodes (not movies).

Want to use an array (simple example):

Groovy: Select all

franchise = [
	"StarTrek" = "Star ?Trek",
	"StarWars" = "Star ?Wars|(The ?)?Mandelorian|Obi-?Wan ?Kenobi",
],
When looking at the title of the file, return the key of the value that matches (if any).

Goal is to allow put grouped shows into a folder other than the default TV shows folder. If there's no match, then the default will be used. That's not a problem (the 'any' feature is wonderful).

So what am I forgetting about here Noah? I'm sure I'll be doing a V8 retro reaction, unless it's a function that I haven't seen/used before.

Re: Having a brainfart moment. (Get key from array match.)

Posted: 16 Aug 2025, 02:00
by Wolfie
Nevermind. 🤦‍♂️

Decided to actually try using Google and found the answer.

Groovy: Select all

return franchise.find{k,v-> fn=~v }.key
At least I hope that's right.

Re: Having a brainfart moment. (Get key from array match.)

Posted: 16 Aug 2025, 05:24
by rednoah
Yep, that's how I'd do it. If you can't just do a lookup-by-key then you'll have to loop through the map and until you find the entry that matches your conditions.



EDIT:

The match() helper might just do what you need though:

Groovy: Select all

az.match('[a-f]': '/volume1', '[g-x]': '/volume2') ?: '/volume3'

Re: Having a brainfart moment. (Get key from array match.)

Posted: 16 Aug 2025, 05:39
by Wolfie
Here's some code and data that I hope will help others.

Groovy: Select all

	def root="P:"
	config="P:/FileBot/"
	
	def maps = include config+"config.groovy"
	def map = maps['DEFAULTS'] + maps['TV'], folders=map['folders'], dd=map['dd'], talkshows=map['talkshows'], anime=(anime ? (map['anime'] ? "ANIME" : null) :null)
	def groups = allOf{"TV"}{map['groups'].join('|')}{anime}.join('|'), drives=folders.keySet().join('|')
	def franchises = map['franchises'], franchise = any{franchises.find{k,v-> fn=~v }.key}{franchises.find{k,v-> imdbid=~"^${v}\$" }.key}{franchises.find{k,v-> tvdbid=~"^${v}\$" }.key}{}
	def col = /(tt|tmdb|tvdb)[0-9]+/

Groovy: Select all

[
	"DEFAULTS":[
		"dd":"06",
		"collections":"collections.txt",
		"overrides":"overrides.txt",
		"folders":[
			"01":"_01",
			"02":"_02",
			"03":"_03",
			"04":"_04",
			"05":"_05",
			"06":"_06",
			"E1":"_E1",
			"E2":"_E2",
			"E3":"_E3",
		],
	],

	"TV":[
		"talkshows":true,
		"anime":false,
		"franchises":[
			"StarTrek": "^Star ?Trek|tt0112178|74550",
			"StarWars": "^(Star ?Wars|(The ?)?Mandelorian|Obi-?Wan ?Kenobi)",
		],
		"groups":[
			"DC(shows)?",
			"Marvel(TV)?",
			"Star ?Trek",
		],
	],

	"MOVIES":[
		"collectionsFolder":"_",
	]
]
The "franchises" here is the most recent thing I worked on. Idea is to let it override the default folder name of "TV" later on using the any{} function.

As an example...

Groovy: Select all

TVfolder=any{franchise}{anime}{"TV"}
So if someone wants to group a bunch of related shows into the same main folder, they just name to set the name of the folder as the key (left side), then enter either names or IMDB ID's or TVDB ID's (or a mix) separated by |'s. If using names, regex format. The key can have spaces, of course, even though I don't include them above. The 'talkshows' value is since I also separate talk shows from regular shows. I prefer to not separate shows based on anime, but that's made into an easy to toggle option. Helpful when wanting to toggle something both via GUI and command line uses without making changes in multiple places.

Re: Having a brainfart moment. (Get key from array match.)

Posted: 16 Aug 2025, 08:23
by Wolfie
Now here's an interesting situation that is baffling me.

Using the 'folders' array from above ("01" = "_01", etc), I'm able to get results from one method but not another.

Working:

Groovy: Select all

folders[file.path.match("(?<=\\_)(${folders.keySet().join('|')})")]
Not working:

Groovy: Select all

folders[file.path.match("(?<=\\)(${folders.values().join('|')})")]
The ONLY difference between the two is that the first turns into "(?<=\\_?)(01|02|03|04|05|06|E1|E2|E3)\\" and the second turns into "(?<=\\)(_01|_02|_03|_04|_05|_06|_E1|_E2|_E3)" but yet only the first works even though both searches should return the same result.

Example path: "A:/_02/TV/BCDEFG"

Both should be returning "_02" but the second doesn't return anything. Does having "_" in front of them somehow mess up the regex engine?

Re: Having a brainfart moment. (Get key from array match.)

Posted: 16 Aug 2025, 09:03
by rednoah
:?: What are the values that are being worked with? What is file.path? What is the pattern you pass to the match() function?

:idea: Plugging in the values you shared we get a regular expression error:

Format: Select all

{ 'A:/_02/TV/BCDEFG'.match("(?<=\\)(_01|_02|_03|_04|_05|_06|_E1|_E2|_E3)") }

Code: Select all

Expression yields empty value: Unclosed group near index 43
(?<=\)(_01|_02|_03|_04|_05|_06|_E1|_E2|_E3)
:?: What does (?<=\\) try to do? In this case it's actually escaping the ) parenthesis. The first \ is for escaping the \ in the String literal.


:idea: Since _ doesn't need to be escaped, the \\ in (?<=\\_) does nothing. It could just be (?<=_). If wanted to not have a lookbehind you would remove that construct altogethere instead of just removing the _ character.


:arrow: tl;dr you probably meant to do just this:

Groovy: Select all

folders[ file.path.match( folders.values().join('|') ) ]

Re: Having a brainfart moment. (Get key from array match.)

Posted: 16 Aug 2025, 18:43
by Wolfie
I'm trying to get it to match the '/' in "A:/" to limit it to a single folder name. Trying to make sure it matches the "_02" in "/_02/" and not in a situation like "part_023" for example.

Re: Having a brainfart moment. (Get key from array match.)

Posted: 17 Aug 2025, 03:59
by rednoah
{ file.path } will be using \ and not / on Windows. In the context of a file path /\ doesn't matter, but in the context of a regular expression one does no match the other.


:!: The preview in the format editor will display the normalised file path. Meaning it'll display / even if the file path actually uses \ in the variable value.


:arrow: I'd write a pattern that matches either / or \ to ensure it works on all platforms and more importantly avoid issues where the \ is displayed as / leading to confusion:

Format: Select all

{ 'A:\\_02\\test.txt'.match(/(?<=\\|\/)(_02)(?=\\|\/)/) }

Re: Having a brainfart moment. (Get key from array match.)

Posted: 19 Aug 2025, 01:17
by Wolfie
Here's one for you. How do I do something like this:

Groovy: Select all

array.find{ k,v -> v.find{ p,regex -> value=~regex} }
Imagine an array like:

Groovy: Select all

"arrayT":[
	"a1":[ "a11":"regex11", "a12":"regex12", ],
	"a2":[ "a21":"regex21", "a22":"regex22", ],
	"a3":[ "a31":"regex31", "a32":"regex32", ],
],
When I try to do it with one .find{}, it returns only the first array (a1) even if the match is in (a2). :?:

Re: Having a brainfart moment. (Get key from array match.)

Posted: 19 Aug 2025, 07:31
by rednoah
e.g.

Groovy: Select all

{
	def data = [
		"arrayT":[
			"a1":[ "a11":"regex11", "a12":"regex12", ],
			"a2":[ "a21":"regex21", "a22":"regex22", ],
			"a3":[ "a31":"regex31", "a32":"regex32", ],
		],
	]
	
	def value = /regex32/

	data.arrayT.findResult{ k1, v1 ->
		v1.findResult{ k2, v2 ->
			if (value =~ v2) return k1
		}
	}
}

Code: Select all

a3

Re: Having a brainfart moment. (Get key from array match.)

Posted: 19 Aug 2025, 12:19
by Wolfie
Any way to get it to return an array? So that the following is the result...

Code: Select all

result.key = "a3"
result.value = {"a32":"regex32"}
result.value.key = "a32"
result.value.value = "regex32"

Re: Having a brainfart moment. (Get key from array match.)

Posted: 19 Aug 2025, 12:31
by rednoah
:arrow: Maybe like this?

Format: Select all

{
	def data = [
		"arrayT":[
			"a1":[ "a11":"regex11", "a12":"regex12", ],
			"a2":[ "a21":"regex21", "a22":"regex22", ],
			"a3":[ "a31":"regex31", "a32":"regex32", ],
		],
	]
	
	def value = /regex32/

	data.arrayT.findResult{ k1, v1 ->
		v1.findResult{ k2, v2 ->
			if (value =~ v2) return [(k1):[(k2):v2]]
		}
	}
}

Code: Select all

{a3={a32=regex32}}


:arrow: I don't see the point of using a map inside a map when you know it'll only have 1 mapping. Maybe you rather mean to do something like this?

Format: Select all

{
	def data = [
		"arrayT":[
			"a1":[ "a11":"regex11", "a12":"regex12", ],
			"a2":[ "a21":"regex21", "a22":"regex22", ],
			"a3":[ "a31":"regex31", "a32":"regex32", ],
		],
	]
	
	def value = /regex32/

	def (k1, k2, v2) = data.arrayT.findResult{ k1, v1 ->
		v1.findResult{ k2, v2 ->
			if (value =~ v2) return [k1, k2, v2]
		}
	}
	
	return "$k1 $k2 $v2"
}

Code: Select all

a3 a32 regex32

Re: Having a brainfart moment. (Get key from array match.)

Posted: 19 Aug 2025, 13:06
by Wolfie
When I try to get it into a variable (not return the result as final), it doesn't want to work for me. ☹

The idea is to get it so that a single variable can be used to either get the "group" it match (a1, a2, a3), the key (a11, a12, etc), or the value (regex32) as desired. It's similar to the above but a step beyond.

Imagine:

Groovy: Select all

"paths":[
	"Star Trek":[
		"/first/path/":"^(first set of matches)",
		"/second/path/:"^(second|set|of|matches)",
	],
	"Star Wars":[
		"/first/path/again":"^(new set of match)",
	],
],
Let's assume that ST TNG matches the second one.
data.key = "Star Trek"
data.value.key = "/second/path/"
data.value.value = "^(second|set|of|matches)"

If I want to have it show me the "data.value.value" as filenames (for debugging/testing purposes, of course), then I can do so easily.

Re: Having a brainfart moment. (Get key from array match.)

Posted: 19 Aug 2025, 16:35
by rednoah
Wolfie wrote: Yesterday, 13:06 The idea is to get it so that a single variable can be used to either get the "group" it match (a1, a2, a3), the key (a11, a12, etc), or the value (regex32) as desired.
The second example above will give you what you want as 3 separate variables. If you want it as a single variable that has 2 properties, the second of which itself has 2 properties, then I would ask why make things more difficult? But here you go:

Format: Select all

{
	def data = [
		"paths":[
			"Star Trek":[
				"/first/path/":"^(first set of matches)",
				"/second/path/":"^(second|set|of|matches)",
			],
			"Star Wars":[
				"/first/path/again":"^(new set of match)",
			],
		],
	]
	
	def input = "second.set.of.matches"

	def result = data.paths.findResult{ group, paths ->
		paths.findResult{ path, pattern ->
			if (input =~ pattern) return [key: group, value: [key: path, value: pattern]]
		}
	}
	
	return [result.key, result.value.key, result.value.value].join('/')
}

Code: Select all

Star Trek/second/path/^(second|set|of|matches)

I would find this a bit hard to read though:

Code: Select all

result.key
result.value.key
result.value.value
while well-named variables seem a bit more easy to read:

Code: Select all

group
path
pattern

Re: Having a brainfart moment. (Get key from array match.)

Posted: 20 Aug 2025, 04:32
by Wolfie
Tweaked it to just be variable.(property) instead of branching it. Rethinking the idea though, as I noticed a potential problem, but not giving up on what you taught me. It's quite useful.

Re: Having a brainfart moment. (Get key from array match.)

Posted: 20 Aug 2025, 06:27
by Wolfie
And another tweak to account for the potential problem. So idea is still on. 😁