diff --git a/CHANGELOG.md b/CHANGELOG.md index 6b7ae9326a..8b536822d4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,9 +4,12 @@ - Added Join notifier ([#5241](https://github.com/pymedusa/Medusa/pull/5241)) #### Improvements -- Vueified "config - notifications" page. Improved components: config-textbox, select-list, show-selector, config-textbox-number. Improved responsiveness of the notification page on smaller screens ([#4913](https://github.com/pymedusa/Medusa/pull/4913)) -- Allow the use of priorities in the Pushover notifier ([#5567](https://github.com/pymedusa/Medusa/pull/5567)) -- Allow Nyaa and Anidex to search for non-anime shows ([#5680](https://github.com/pymedusa/Medusa/pull/5680) & [#5680](https://github.com/pymedusa/Medusa/pull/5681)) +- Vueified "config - notifications" page: + - Improved components: config-textbox, select-list, show-selector, config-textbox-number + - Improved responsiveness of the notification page on smaller screens ([#4913](https://github.com/pymedusa/Medusa/pull/4913)) +- Allowed the use of priorities in the Pushover notifier ([#5567](https://github.com/pymedusa/Medusa/pull/5567)) +- Added delete method to EpisodeHandler (apiv2), for deleting a single episode ([#5685](https://github.com/pymedusa/Medusa/pull/5685)) +- Allowed Nyaa and Anidex to search for non-anime shows ([#5680](https://github.com/pymedusa/Medusa/pull/5680) & [#5681](https://github.com/pymedusa/Medusa/pull/5681)) #### Fixes - Fixed test not working for Download Station ([#5561](https://github.com/pymedusa/Medusa/pull/5561)) diff --git a/dredd/api-description.yml b/dredd/api-description.yml index ba6e45f316..2205777eef 100644 --- a/dredd/api-description.yml +++ b/dredd/api-description.yml @@ -324,6 +324,35 @@ paths: {"status": 2, "quality": 4} path-params: id: e999 + delete: + summary: Delete a specific episode from a given series + description: Delete a specific episode from a given series + parameters: + - $ref: '#/parameters/series-id' + name: seriesid + - $ref: '#/parameters/episode-id-delete' + name: id + responses: + 204: + description: Episode is deleted successfully + 400: + $ref: '#/responses/error' + description: Invalid id + x-request: + path-params: + seriesid: tvdb301824 + id: 123456 + 404: + $ref: '#/responses/error' + description: Episode not found + x-request: + path-params: + seriesid: tvdb301824 + id: s9999e9999 + 409: + $ref: '#/responses/error' + description: Unable to delete episode + x-disabled: true /series/{seriesid}/episodes/{id}/{field}: get: summary: Return a specific field from a given episode @@ -2342,6 +2371,13 @@ parameters: description: The episode id to retrieve. E.g. s02e03, e34 or 2016-12-31 x-example: s01e01 type: string + episode-id-delete: + name: episode-id-delete + in: path + required: true + description: The episode id to retrieve. E.g. s02e03, e34 or 2016-12-31 + x-example: s01e02 + type: string alias-id: name: alias-id in: path diff --git a/medusa/server/api/v2/episodes.py b/medusa/server/api/v2/episodes.py index b682decda1..f3a340460f 100644 --- a/medusa/server/api/v2/episodes.py +++ b/medusa/server/api/v2/episodes.py @@ -4,6 +4,7 @@ import logging +from medusa.helper.exceptions import EpisodeDeletedException from medusa.logger.adapters.style import BraceAdapter from medusa.server.api.v2.base import ( BaseRequestHandler, @@ -36,7 +37,7 @@ class EpisodeHandler(BaseRequestHandler): #: path param path_param = ('path_param', r'\w+') #: allowed HTTP methods - allowed_methods = ('GET', 'PATCH', ) + allowed_methods = ('GET', 'PATCH', 'DELETE',) def http_get(self, series_slug, episode_slug, path_param): """Query episode information. @@ -156,3 +157,31 @@ def _patch_episode(episode, data): ) return accepted + + def http_delete(self, series_slug, episode_slug, **kwargs): + """Delete the episode.""" + if not series_slug: + return self._method_not_allowed('Deleting multiple series are not allowed') + + identifier = SeriesIdentifier.from_slug(series_slug) + if not identifier: + return self._bad_request('Invalid series identifier') + + series = Series.find_by_identifier(identifier) + if not series: + return self._not_found('Series not found') + + episode_number = EpisodeNumber.from_slug(episode_slug) + if not episode_number: + return self._bad_request('Invalid episode number') + + episode = Episode.find_by_series_and_episode(series, episode_number) + if not episode: + return self._not_found('Episode not found') + + try: + episode.delete_episode() + except EpisodeDeletedException: + return self._no_content() + else: + return self._conflict('Unable to delete episode') diff --git a/medusa/tv/episode.py b/medusa/tv/episode.py index 579ae95d26..f08ed41b0b 100644 --- a/medusa/tv/episode.py +++ b/medusa/tv/episode.py @@ -95,8 +95,8 @@ class EpisodeNumber(Identifier): date_fmt = '%Y-%m-%d' regex = re.compile(r'\b(?:(?P\d{4}-\d{2}-\d{2})|' - r'(?:s(?P\d{1,4}))(?:e(?P\d{1,2}))|' - r'(?:e(?P\d{1,3})))\b', re.IGNORECASE) + r'(?:s(?P\d{1,4}))(?:e(?P\d{1,4}))|' + r'(?:e(?P\d{1,4})))\b', re.IGNORECASE) @classmethod def from_slug(cls, slug): diff --git a/tests/test_tv_identifiers.py b/tests/test_tv_identifiers.py index a5a4fa7a98..af1691f793 100644 --- a/tests/test_tv_identifiers.py +++ b/tests/test_tv_identifiers.py @@ -130,7 +130,7 @@ def test_series_identifier(p): }, { # p11: e1234 'slug': 'e1234', - 'expected': None, + 'expected': AbsoluteNumber(1234), }, { # p12: E15 'slug': 'E15', @@ -144,27 +144,31 @@ def test_series_identifier(p): 'slug': 's2017e02', 'expected': RelativeNumber(2017, 2), }, - { # p15: 2017-07-16 + { # p15: s01e9999 + 'slug': 's01e9999', + 'expected': RelativeNumber(1, 9999), + }, + { # p16: 2017-07-16 'slug': '2017-07-16', 'expected': AirByDateNumber(datetime(year=2017, month=7, day=16)), }, - { # p16: 2017-17-16 (invalid date) + { # p17: 2017-17-16 (invalid date) 'slug': '2017-17-16', 'expected': None, }, - { # p17: Invalid + { # p18: Invalid 'slug': 's01e022017-07-16', 'expected': None, }, - { # p18: Invalid + { # p19: Invalid 'slug': '22017-07-16', 'expected': None, }, - { # p19: Invalid + { # p20: Invalid 'slug': 'ss01', 'expected': None, }, - { # p20: Invalid + { # p21: Invalid 'slug': 'ee01', 'expected': None, },