diff --git a/showtime/__init__.py b/showtime/__init__.py index 68100f4..dae4b1d 100644 --- a/showtime/__init__.py +++ b/showtime/__init__.py @@ -1,2 +1,2 @@ -__version__ = '0.3.13' +__version__ = '0.3.14' __url__ = 'https://github.com/aquilax/showtime' diff --git a/showtime/command.py b/showtime/command.py index 191f66b..c9b9da0 100644 --- a/showtime/command.py +++ b/showtime/command.py @@ -262,6 +262,23 @@ def do_export(self, statement: Statement) -> None: episodes = self.app.episodes_watched_between(from_date, to_date) self.output.json(sorted(episodes, key=lambda k: k['watched'])) + @cmd2.with_category(EPISODE_CATEGORY) + def do_watched_between(self, statement: Statement) -> None: + """Export seen episodes between dates[export ]""" + try: + from_date_s, to_date_s = statement.split(' ') + from_date = dateutil.parser.parse(from_date_s).date() + to_date = dateutil.parser.parse(to_date_s).date() + + except (dateutil.parser.ParserError, OverflowError): + self.output.perror("Invalid date") + return + + episodes = self.app.episodes_watched_between(from_date, to_date) + sorted_episodes = sorted(episodes, key=lambda k: k['watched']) + episodes_table = self.output.format_unwatched(sorted_episodes) + self.output.ppaged(episodes_table) + @cmd2.with_category(EPISODE_CATEGORY) def do_new_unwatched(self, statement: Statement) -> None: """Show unwatched episodes aired in the last 7 days[new_unwatched ]""" diff --git a/showtime/database.py b/showtime/database.py index 2fb065c..b654c9d 100644 --- a/showtime/database.py +++ b/showtime/database.py @@ -128,35 +128,39 @@ def sync_episodes(self, show_id: ShowId, episodes: List[TVMazeEpisode], }, where('id') == matched_episode['id']) self.table(EPISODE).insert_multiple(queue) - def update_watched(self, episode_id: EpisodeId, watched: bool, when=datetime.utcnow().isoformat()) -> None: + def update_watched(self, episode_id: EpisodeId, watched: bool, when: Optional[datetime] = None) -> None: """Updates the watched date of an episode""" - watched_value = when if watched else '' + watched_date = when if when else datetime.utcnow().isoformat() + watched_value = watched_date if watched else '' self.table(EPISODE).update({ 'watched': watched_value }, where('id') == episode_id) def get_unwatched(self, current_datetime: datetime) -> List[Episode]: """Returns all aired episodes which are not watched yet""" - episodes = self.table(EPISODE).search(((where('watched') == '') & (where('airdate') <= current_datetime))) + episodes = self.table(EPISODE).search(((where('watched') == '') & (where('airdate') <= current_datetime.isoformat()))) return cast(List[Episode], episodes) - def update_watched_show(self, show_id: ShowId, watched: bool, when=datetime.utcnow().isoformat()) -> None: + def update_watched_show(self, show_id: ShowId, watched: bool, when:Optional[datetime] = None) -> None: """Updates all episodes of a show as watched now""" - watched_value = when if watched else '' + watched_date = when if when else datetime.utcnow().isoformat() + watched_value = watched_date if watched else '' self.table(EPISODE).update({ 'watched': watched_value }, where('show_id') == show_id) def update_watched_show_season(self, show_id: ShowId, season: int, watched: bool, - when=datetime.utcnow().isoformat()) -> None: + when:Optional[datetime] = None) -> None: """Updates all episodes of a show and season as watched now""" - watched_value = when if watched else '' + watched_date = when if when else datetime.utcnow().isoformat() + watched_value = watched_date if watched else '' self.table(EPISODE).update({ 'watched': watched_value }, ((where('show_id') == show_id) & (where('season') == season))) - def last_seen(self, show_id: ShowId, season: int, number: int, when=datetime.utcnow().isoformat()) -> int: + def last_seen(self, show_id: ShowId, season: int, number: int, when:Optional[datetime] = None) -> int: """Updates all show episodes as seen up to season and number""" + watched_date = when if when else datetime.utcnow().isoformat() episodes = self.get_episodes(show_id) episode_ids = [] for episode in episodes: @@ -166,7 +170,7 @@ def last_seen(self, show_id: ShowId, season: int, number: int, when=datetime.utc episode_ids.append(episode['id']) continue self.table(EPISODE).update({ - 'watched': when + 'watched': watched_date }, where('id').one_of(episode_ids)) return len(episode_ids) diff --git a/showtime/showtime.py b/showtime/showtime.py index 52cadd2..806f295 100644 --- a/showtime/showtime.py +++ b/showtime/showtime.py @@ -147,8 +147,9 @@ def episodes_update_season_not_watched(self, show_id: ShowId, season: int) -> No with transaction(self.database) as transacted_db: return transacted_db.update_watched_show_season(show_id, season, False) - def episodes_get_unwatched(self, current_datetime=datetime.utcnow().isoformat()) -> List[DecoratedEpisode]: + def episodes_get_unwatched(self, when:Optional[datetime] = None) -> List[DecoratedEpisode]: """Returns list of unwatched episodes""" + current_datetime = when if when else datetime.utcnow() episodes = self.database.get_unwatched(current_datetime) sorted_episodes = sorted(episodes, key=lambda episode: episode['airdate'] or '') return self._decorate_episodes(sorted_episodes) diff --git a/tests/command_test.py b/tests/command_test.py index 039fa9c..8760229 100644 --- a/tests/command_test.py +++ b/tests/command_test.py @@ -272,6 +272,22 @@ def test_export(test_app): """.strip() assert out.data == None +def test_watched_between(test_app): + test_app.app.episodes_watched_between = MagicMock(return_value=[decorated_episode]) + + out = test_app.app_cmd("watched_between 2020-01-01 2021-01-01") + + test_app.app.episodes_watched_between.assert_called_once_with(date(2020, 1, 1), date(2021, 1, 1)) + assert isinstance(out, CommandResult) + assert str(out.stdout).strip() == """ ++Episodes to watch-----+-----+-------------------+------------+---------+ +| ID | Show | S | E | Name | Aired | Watched | ++----+-----------+-----+-----+-------------------+------------+---------+ +| 1 | test-show | S01 | E01 | The first episode | 2020-01-01 | | ++----+-----------+-----+-----+-------------------+------------+---------+ +""".strip() + assert out.data == None + def test_new_unwatched(test_app): test_app.app.episodes_aired_unseen_between = MagicMock(return_value=[decorated_episode]) diff --git a/tests/database_test.py b/tests/database_test.py index 20a5faf..3542f71 100644 --- a/tests/database_test.py +++ b/tests/database_test.py @@ -3,12 +3,15 @@ from showtime.database import get_memory_db, transaction from showtime.types import ShowStatus, TVMazeShow, TVMazeEpisode + def get_tv_maze_show(id=1, name="show", premiered="2020", status="great", url="http://example.com") -> TVMazeShow: return TVMazeShow(id=id, name=name, premiered=premiered, status=status, url=url) + def get_tv_maze_episode(id=1, season=1, number=1, name="episode1", airdate="2020-10-10", runtime=30) -> TVMazeEpisode: return TVMazeEpisode(id=id, season=season, number=number, name=name, airdate=airdate, runtime=runtime) + def test_add(): show = get_tv_maze_show() with get_memory_db() as database: @@ -58,4 +61,22 @@ def test_last_seen(): assert len(episodes) == 3 assert episodes[0]['watched'] != '' assert episodes[1]['watched'] != '' - assert episodes[2]['watched'] == '' # last episode is not watched + assert episodes[2]['watched'] == '' # last episode is not watched + + +def test_watch(): + show1 = get_tv_maze_show(name="show 1") + episode1 = get_tv_maze_episode(id=1, name="episode1", number=1) + episode2 = get_tv_maze_episode(id=2, name="episode2", number=2) + with get_memory_db() as database: + with transaction(database) as transacted_db: + show_id = database.add_show(show1) + transacted_db.add_episode(show_id, episode1) + transacted_db.add_episode(show_id, episode2) + with transaction(database) as transacted_db: + transacted_db.update_watched(1, True) + episode1db = database.get_episode(1) + with transaction(database) as transacted_db: + transacted_db.update_watched(2, True) + episode2db = database.get_episode(2) + assert episode1db['watched'] != episode2db['watched']