gameyfin
gameyfin copied to clipboard
Also check for minus (-) in title if game title could not be found
Currently, if the game title that gets parsed from the folder can not be found on IGDB,
it checks for brackets in it, removes them and searches again.
https://github.com/grimsi/gameyfin/blob/e53435092cea928d7b78cdfc101e8c032ffda437/backend/src/main/java/de/grimsi/gameyfin/igdb/IgdbWrapper.java#L125
This fixes some errors, but sometimes there is also a -
and some more text appended to the folder name.
Would it be possible for you to code that, if no brackets have been found (or if the title could not be found even after removing the brackets), it checks for a minus sign and if found, removes it and the text to its right and searches again?
This would be really great.
From looking at the code, it should not be too much of a change, but if you are too busy to do it yourself right now, I could later make a pull request with the change, if you are okay with this.
Thanks a lot :)
Good idea. I will most likely implement it, but I don't want Gameyfin to be a search engine on top of IGDBs search engine. So this will just cover super basic matching.
Sure, nothing extraordinary, just so more folders get recognized. I was bored earlier and came up with this
if(hasBrackets.find()) {
String searchTermWithoutBrackets = searchTerm.split(brackets.pattern())[0].trim();
log.warn("Trying again with search term '{}'", searchTermWithoutBrackets);
return searchForGameByTitle(searchTermWithoutBrackets);
} else if (searchTerm.contains("-")){
String searchTermWithoutDash = searchTerm.substring(0, searchTerm.lastIndexOf('-')).trim();
log.warn("Trying again with search term '{}'", searchTermWithoutDash);
return searchForGameByTitle(searchTermWithoutDash);
}
which worked relatively fine, but does not cover dots or underscores in filename, which still cause the search to not find a result.
Also, when testing, I saw that the mapping sometimes does not work for some weird reasons. For example the game "Apolune 2" (which is named exactly like this) returns Could not find game for title 'Apolune 2'
Also, when trying to use the manual mapping dialogue, it works fine, but the game search when using the text field only shows the first game of the series and nothing else.
So it looks like the search by the game name does not work for some games, only manual mapping by slug (The search on the website works fine for this and other games)
Im gonna make a new issue for this, just wanted to ask if you already know this or if theres a quick fix for it
Sadly the search API endpoints on IGDB are a bit hit or miss. Their search algorithm on the website is definitely better than the one you can use on their public API, but since I do not have access to it, there is nothing I can really do.
right, does not seem to work as well as their own search. I had the error from my last message some more time, but most times this could be fixed by replacing https://github.com/grimsi/gameyfin/blob/1fc2c22e05486160c3aeeb90c2075723665acd91/backend/src/main/java/de/grimsi/gameyfin/igdb/IgdbWrapper.java#L134 with
String possibleSlug = searchTerm.replace(" ", "-").toLowerCase();
log.warn("Using slug as last resort for " + searchTerm + ": " + possibleSlug);
return getGameBySlug(possibleSlug);
This tries to, if the bracket/dash trick earlier has not resulted in a found game, convert the name to its possible slug, which for me worked most of the times as the slug seems to be exact, unlike their search.
As getGameBySlug
also returns an empty optional, this should not have a negative side effect if the guessed slug is invalid.
More on-topic, I changed the game title parser a bit more, to remove more stuff from folder names that may hinder game recognition. The full code now looks like this
if (gameResult == null) {
log.warn("Could not find game for title '{}'", searchTerm);
// Try to remove brackets (and their content) at the end of the search term and search again
// Although this process is recursive, we will only end up with a maximum recursion depth of two
Pattern brackets = Pattern.compile ("[()<>{}\\[\\]]");
Matcher hasBrackets = brackets.matcher(searchTerm);
Pattern namings = Pattern.compile ("-|\\.|_|(?i)internal|(?i)repack|(?i)proper");
Matcher hasNaming = namings.matcher(searchTerm);
if(hasBrackets.find()) {
String searchTermWithoutBrackets = searchTerm.split(brackets.pattern())[0].trim();
log.warn("Removed brackets, trying again with search term '{}'", searchTermWithoutBrackets);
return searchForGameByTitle(searchTermWithoutBrackets);
} else if(hasNaming.find()) {
String searchTermWithoutDash = searchTerm;
if(searchTermWithoutDash.contains("-")){
searchTermWithoutDash = searchTermWithoutDash.substring(0, searchTermWithoutDash.lastIndexOf('-')).trim();
}
searchTermWithoutDash = searchTermWithoutDash.replace(".", " ");
searchTermWithoutDash = searchTermWithoutDash.replace("_", " ");
searchTermWithoutDash = searchTermWithoutDash.replaceAll("(?i)repack", " ");
searchTermWithoutDash = searchTermWithoutDash.replaceAll("(?i)internal", " ");
searchTermWithoutDash = searchTermWithoutDash.replaceAll("(?i)proper", " ");
log.warn("Removed disruptive release naming, trying again with search term '{}'", searchTermWithoutDash);
return searchForGameByTitle(searchTermWithoutDash);
}
log.warn("Using slug as last resort for " + searchTerm + ": " + searchTerm.replace(" ", "-").toLowerCase());
return getGameBySlug(searchTerm.replace(" ", "-").toLowerCase());
}
This works for the most cases in my library, with the exception of some rarely used terms, and, more often, folder names containing a version number like Game.v3.12.43
. Maybe here a check could be added to check for a lowercase v
and if all characters to the right of it are number, if both is true, remove the v
and everything to the right, but I did not do it so far as Im not a big fan of regex.
PS: As you may have seen on the terms that are being checked, this may dip a bit into the piracy scene, as GOG games dont have those terms in their name. From what I've seen, you only used GOG games in your screenshots, so I'm not sure if you're opposed to this. If you are, just let me know and I'll remove those terms.
Thanks for your work! It seems like you already cover a lot of edge cases which is something that I initially did not want. But maybe I have to think about how to implement the search algorithm to be more extendible. Or the easier solution would be to just rename the files/folders (that's what I do anyways, I like my directory tree to be clean, but I can see why not everyone would want the hassle with manually renaming the files and folders for each game). Also I used GoG games on the screenshots because I knew that there would be no copyright issues if those games would be redistributed with Gameyfin. I think that legally I have to say that I do not support piracy, but I can not and will not control what users put in their library :)
The search itself is fine, isn't it? Or are you referring to the IGDB API search and not to the Gameyfin search?
that I initially did not want
But are you fine with it now?
I like the edge cases being covered, as now I still have many games that are not recognized with edge cases.
If you are fine with it, I could gather most edge cases and write code for it to parse the game name and then make a pull request. This should not interfere with the bracket check you have now, so I don't think there are any downsides.
File renaming by the user would also be possible, but that would take longer to do than to write parsing code, even only using my own library, so I think this is a better option if you are fine with it.
Also, on the site where manual mappings can be done, it would be helpful to have an indicator if the game just could not be found or if it is already in the library, yesterday I stumbled upon this multiple times where I want to map a game, but it's already in the library (as I have two versions on my disk), so it just presents me with "Error"
Feel free to implement a more advanced matching algorithm (I already created a branch for it) and open a pull request. Regarding the indicator: Yes, I think that should be possible. Probably another column in the DB table, but I will have to think about how to approach this.