diff --git a/HISTORY.rst b/HISTORY.rst index 04fa8f0..7afea59 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -101,6 +101,7 @@ History - Changed `size` output to return `guessit.Size` object. - Added `audio_video_rate` as new possible property. - Added `video_video_rate` as new possible property. +- Added `disc` as a new possible property. 2.1.4 (2017-06-01) ------------------ diff --git a/docs/properties.rst b/docs/properties.rst index d5c39a1..cfdfdf6 100644 --- a/docs/properties.rst +++ b/docs/properties.rst @@ -92,6 +92,11 @@ Episode properties Episode number. (Can be a list if several are found) +- **disc** + + Disc number. (Can be a list if several are found) + + - **episode_count** Total number of episodes. diff --git a/guessit/rules/properties/episodes.py b/guessit/rules/properties/episodes.py index ac17403..4924256 100644 --- a/guessit/rules/properties/episodes.py +++ b/guessit/rules/properties/episodes.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- """ -episode, season, episode_count, season_count and episode_details properties +episode, season, disc, episode_count, season_count and episode_details properties """ import copy from collections import defaultdict @@ -85,6 +85,7 @@ def episodes(): all_words = ['All'] season_markers = ["S"] season_ep_markers = ["x"] + disc_markers = ['d'] episode_markers = ["xE", "Ex", "EP", "E", "x"] range_separators = ['-', '~', 'to', 'a'] weak_discrete_separators = list(sep for sep in seps if sep not in range_separators) @@ -145,10 +146,10 @@ def episodes(): validator={'__parent__': ordering_validator}, conflict_solver=season_episode_conflict_solver) \ .regex(build_or_pattern(season_markers, name='seasonMarker') + r'(?P\d+)@?' + - build_or_pattern(episode_markers, name='episodeMarker') + r'@?(?P\d+)', + build_or_pattern(episode_markers + disc_markers, name='episodeMarker') + r'@?(?P\d+)', validate_all=True, validator={'__parent__': seps_before}).repeater('+') \ - .regex(build_or_pattern(episode_markers + discrete_separators + range_separators, + .regex(build_or_pattern(episode_markers + disc_markers + discrete_separators + range_separators, name='episodeSeparator', escape=True) + r'(?P\d+)').repeater('*') \ @@ -313,7 +314,7 @@ def episodes(): SeePatternRange(range_separators + ['_']), EpisodeNumberSeparatorRange(range_separators), SeasonSeparatorRange(range_separators), RemoveWeakIfMovie, RemoveWeakIfSxxExx, RemoveWeakDuplicate, EpisodeDetailValidator, RemoveDetachedEpisodeNumber, VersionValidator, - CountValidator, EpisodeSingleDigitValidator) + CountValidator, EpisodeSingleDigitValidator, RenameToDiscMatch) return rebulk @@ -398,12 +399,14 @@ class AbstractSeparatorRange(Rule): for separator in matches.named(self.property_name + 'Separator'): previous_match = matches.previous(separator, lambda match: match.name == self.property_name, 0) next_match = matches.next(separator, lambda match: match.name == self.property_name, 0) + initiator = separator.initiator if previous_match and next_match and separator.value in self.range_separators: to_remove.append(next_match) for episode_number in range(previous_match.value + 1, next_match.value): match = copy.copy(next_match) match.value = episode_number + initiator.children.append(match) to_append.append(match) to_append.append(next_match) to_remove.append(separator) @@ -415,9 +418,11 @@ class AbstractSeparatorRange(Rule): if separator not in self.range_separators: separator = strip(separator) if separator in self.range_separators: + initiator = previous_match.initiator for episode_number in range(previous_match.value + 1, next_match.value): match = copy.copy(next_match) match.value = episode_number + initiator.children.append(match) to_append.append(match) to_append.append(Match(previous_match.end, next_match.start - 1, name=self.property_name + 'Separator', @@ -664,3 +669,20 @@ class EpisodeSingleDigitValidator(Rule): if not matches.range(*group.span, predicate=lambda match: match.name == 'title'): ret.append(episode) return ret + + +class RenameToDiscMatch(Rule): + """ + Rename episodes detected with `d` episodeMarkers to `disc`. + """ + + consequence = [RenameMatch('disc'), RenameMatch('discMarker')] + + def when(self, matches, context): + discs = [] + markers = [] + for marker in matches.named('episodeMarker', predicate=lambda m: m.value.lower() == 'd'): + markers.append(marker) + discs.extend(sorted(marker.initiator.children.named('episode'), key=lambda m: m.value)) + + return discs, markers diff --git a/guessit/test/episodes.yml b/guessit/test/episodes.yml index 9f86287..34b5ca5 100644 --- a/guessit/test/episodes.yml +++ b/guessit/test/episodes.yml @@ -4349,3 +4349,41 @@ audio_bit_rate: 448Kbps release_group: ALANiS type: episode + +? Greys.Anatomy.S07D1.NTSC.DVDR-ToF +: title: Greys Anatomy + season: 7 + disc: 1 + other: NTSC + source: DVD + release_group: ToF + type: episode + +? Greys.Anatomy.S07D1.NTSC.DVDR-ToF +: title: Greys Anatomy + season: 7 + disc: 1 + other: NTSC + source: DVD + release_group: ToF + type: episode + +? Greys.Anatomy.S07D1-3&5.NTSC.DVDR-ToF +: title: Greys Anatomy + season: 7 + disc: [1, 2, 3, 5] + other: NTSC + source: DVD + release_group: ToF + type: episode + +? El.Principe.2014.S01D01.SPANiSH.COMPLETE.BLURAY-COJONUDO +: title: El Principe + year: 2014 + season: 1 + disc: 1 + language: spa + other: Complete + source: Blu-ray + release_group: COJONUDO + type: episode diff --git a/guessit/test/rules/episodes.yml b/guessit/test/rules/episodes.yml index fa175e3..98325fa 100644 --- a/guessit/test/rules/episodes.yml +++ b/guessit/test/rules/episodes.yml @@ -270,4 +270,10 @@ ? Episode71 ? Episode 71 -: episode: 71 \ No newline at end of file +: episode: 71 + +? S01D02.3-5-GROUP +: disc: [2, 3, 4, 5] + +? S01D02&4-6&8 +: disc: [2, 4, 5, 6, 8]