aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/plugins/utils/EpisodeNameParser.cpp65
-rw-r--r--tests/main.cpp12
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<EpisodeNameParts> 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<EpisodeNameParts> 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<EpisodeNameParts> 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<EpisodeNameParts> 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<EpisodeNameParts> 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;