From 52dfa42283541ff48cce3a6cbdf4e2e2e8567a30 Mon Sep 17 00:00:00 2001 From: dec05eba Date: Sat, 9 Dec 2023 14:21:21 +0100 Subject: Local anime: parse SXXEXX pattern --- src/plugins/utils/EpisodeNameParser.cpp | 65 +++++++++++++++++++++++++++------ tests/main.cpp | 12 ++++++ 2 files changed, 66 insertions(+), 11 deletions(-) diff --git a/src/plugins/utils/EpisodeNameParser.cpp b/src/plugins/utils/EpisodeNameParser.cpp index e314953..8610ab0 100644 --- a/src/plugins/utils/EpisodeNameParser.cpp +++ b/src/plugins/utils/EpisodeNameParser.cpp @@ -1,6 +1,39 @@ #include "../../../plugins/utils/EpisodeNameParser.hpp" namespace QuickMedia { + static bool is_num(char c) { + return c >= '0' && c <= '9'; + } + + static bool char_to_num(char c) { + return c - '0'; + } + + // Finds and parses SXXEXX where X is a number, returns the index to after the pattern or std::string_view::npos + static size_t parse_season_episode_pattern(std::string_view episode_name, int *season, int *episode) { + *season = 0; + *episode = 0; + + size_t index = 0; + while(true) { + index = episode_name.find('S', index); + if(index == std::string_view::npos) + return std::string_view::npos; + + if(index + 6 >= episode_name.size()) + return std::string_view::npos; + + if(is_num(episode_name[index + 1]) && is_num(episode_name[index + 2]) && episode_name[index + 3] == 'E' + && is_num(episode_name[index + 4]) && is_num(episode_name[index + 5])) + { + *season = char_to_num(episode_name[index + 1]) * 10 + char_to_num(episode_name[index + 2]); + *episode = char_to_num(episode_name[index + 4]) * 10 + char_to_num(episode_name[index + 5]); + return index + 6; + } + ++index; + } + } + static bool has_season_in_name(std::string_view episode_name) { size_t sep_count = 0; size_t index = 0; @@ -96,20 +129,30 @@ namespace QuickMedia { } std::optional episode_name_extract_parts(std::string_view episode_name) { + const std::string_view full_episode_name = episode_name; EpisodeNameParts name_parts; - const bool has_season = has_season_in_name(episode_name); + + int season = 0; + int episode = 0; + size_t after_season_episode_pattern = parse_season_episode_pattern(episode_name, &season, &episode); + const bool has_season = after_season_episode_pattern != std::string_view::npos || has_season_in_name(episode_name); name_parts.group = episode_name_extract_group(episode_name); name_parts.anime = episode_name_extract_anime(episode_name); if(name_parts.anime.empty()) return std::nullopt; - if(has_season) - name_parts.season = episode_name_extract_season(episode_name); - - name_parts.episode = episode_name_extract_episode(episode_name); - if(name_parts.episode.empty()) - return std::nullopt; + if(after_season_episode_pattern == std::string_view::npos) { + if(has_season) + name_parts.season = episode_name_extract_season(episode_name); + + name_parts.episode = episode_name_extract_episode(episode_name); + if(name_parts.episode.empty()) + return std::nullopt; + } else { + name_parts.season = full_episode_name.substr(after_season_episode_pattern - 5, 2); + name_parts.episode = full_episode_name.substr(after_season_episode_pattern - 2, 2); + } if(episode_name.find("480p") != std::string_view::npos) name_parts.resolution = "480p"; @@ -118,13 +161,13 @@ namespace QuickMedia { else if(episode_name.find("1080p") != std::string_view::npos) name_parts.resolution = "1080p"; else if(episode_name.find("2160p") != std::string_view::npos) - name_parts.resolution = "2160p"; + name_parts.resolution = "4k"; else if(episode_name.find("1280x720") != std::string_view::npos) - name_parts.resolution = "1280x720"; + name_parts.resolution = "720p"; else if(episode_name.find("1920x1080") != std::string_view::npos) - name_parts.resolution = "1920x1080"; + name_parts.resolution = "1080p"; else if(episode_name.find("3840x2160") != std::string_view::npos) - name_parts.resolution = "3840x2160"; + name_parts.resolution = "4k"; if(ends_with(episode_name, ".mkv")) name_parts.file_ext = ".mkv"; diff --git a/tests/main.cpp b/tests/main.cpp index 5063c2d..329ffb4 100644 --- a/tests/main.cpp +++ b/tests/main.cpp @@ -83,6 +83,7 @@ int main() { assert_equals(name_parts1->anime, "Shikkakumon no Saikyou Kenja"); assert_equals(name_parts1->season.size(), 0); assert_equals(name_parts1->episode, "07"); + assert_equals(name_parts1->resolution, "1080p"); std::optional name_parts2 = episode_name_extract_parts("[SubsPlease] Shingeki no Kyojin (The Final Season) - 81 (1080p) [601A33BD].mkv"); assert_equals(name_parts2.has_value(), true); @@ -90,6 +91,7 @@ int main() { assert_equals(name_parts2->anime, "Shingeki no Kyojin (The Final Season)"); assert_equals(name_parts2->season.size(), 0); assert_equals(name_parts2->episode, "81"); + assert_equals(name_parts2->resolution, "1080p"); std::optional name_parts3 = episode_name_extract_parts("[SubsPlease] Lupin III - Part 6 - 18 (1080p) [98204042].mkv"); assert_equals(name_parts3.has_value(), true); @@ -97,6 +99,7 @@ int main() { assert_equals(name_parts3->anime, "Lupin III"); assert_equals(name_parts3->season, "Part 6"); assert_equals(name_parts3->episode, "18"); + assert_equals(name_parts3->resolution, "1080p"); std::optional name_parts4 = episode_name_extract_parts("[SubsPlease] Kimetsu no Yaiba - Yuukaku-hen - 11 (1080p) [BE15F231].mkv"); assert_equals(name_parts4.has_value(), true); @@ -104,6 +107,15 @@ int main() { assert_equals(name_parts4->anime, "Kimetsu no Yaiba"); assert_equals(name_parts4->season, "Yuukaku-hen"); assert_equals(name_parts4->episode, "11"); + assert_equals(name_parts4->resolution, "1080p"); + + std::optional name_parts5 = episode_name_extract_parts("[Breeze] Undead Unluck - S01E10 [1080p EAC-3 AV1].mkv"); + assert_equals(name_parts5.has_value(), true); + assert_equals(name_parts5->group, "Breeze"); + assert_equals(name_parts5->anime, "Undead Unluck"); + assert_equals(name_parts5->season, "01"); + assert_equals(name_parts5->episode, "10"); + assert_equals(name_parts5->resolution, "1080p"); uint32_t emoji_sequence[32]; size_t emoji_sequence_length = 0; -- cgit v1.2.3