Skip to content

Commit

Permalink
Fix implementation of unsubscribe()
Browse files Browse the repository at this point in the history
  • Loading branch information
SeoulSKY committed Sep 2, 2024
1 parent 70aa257 commit 5ed056f
Show file tree
Hide file tree
Showing 7 changed files with 34 additions and 12 deletions.
18 changes: 18 additions & 0 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,24 @@
Changelog
==========

v2.1.0
------

* From now on, YouTubeNotifier extends AsyncYouTubeNotifier and AsyncYouTubeNotifier extends object. BaseYouTubeNotifier was removed.
* Added (Async)YouTubeNotifier.run_in_background(). It works similar to the run method, but it immediately returns when the notifier is running.
* Added (Async) YouTubeNotifier.unsubscribe(). It unsubscribes the subscribed channel IDs
* From now on, (Async)YouTubeNotifier.subscribe() immediately raises ValueError when the given channel ids are not valid. In the past, it didn't raise error until the notifier started running.
* Improved the speed of verifying channel IDs

Following methods are deprecated and will be removed in version 3.0.0
* AsyncYouTubeNotifier.serve() -> use AsyncYouTubeNotifier.run()
* (Async)YouTubeNotifier.add_listener() -> use either add_any_listener(), add_upload_listener(), or add_edit_listener()

Following decorators are deprecated and will be removed in version 3.0.0
* @(Async)YouTubeNotifier.listener() -> use either @any, @upload or @edit

**Full Changelog**: https://github.com/SeoulSKY/ytnoti/compare/v2.0.1...v2.1.0

v2.0.1
------

Expand Down
2 changes: 1 addition & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
project = "ytnoti"
copyright = "2024 - Present, SeoulSKY" # noqa: A001
author = "SeoulSKY"
release = "2.0.1"
release = "2.1.0"

# -- General configuration ---------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
Expand Down
2 changes: 1 addition & 1 deletion examples/basic/async.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ async def listener(video: Video) -> None:
print(f"New video from {video.channel.name}: {video.title}")

await notifier.subscribe("UC9EEyg7QBL-stRX-7hTV3ng") # Channel ID of SpeedyStyle
await notifier.serve()
await notifier.run()


if __name__ == "__main__":
Expand Down
2 changes: 1 addition & 1 deletion examples/multithreading.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""THe Following is an example of how to use this library with multithreading."""
"""The following is an example of how to use this library with multithreading."""

import time
from threading import Thread
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

setup(
name="ytnoti",
version="2.0.1",
version="2.1.0",
packages=find_packages(),
author="SeoulSKY",
author_email="[email protected]",
Expand Down
4 changes: 4 additions & 0 deletions tests/test_youtube_notifier.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,11 +126,15 @@ def test_subscribe(notifier: YouTubeNotifier) -> None:

def test_unsubscribe(notifier: YouTubeNotifier) -> None:
"""Test the unsubscribe method of the YouTubeNotifier class."""
notifier.subscribe(channel_ids)
notifier.unsubscribe(channel_ids)

with pytest.raises(ValueError):
notifier.unsubscribe("Invalid")

with pytest.raises(ValueError):
notifier.unsubscribe(channel_ids)

assert len(notifier._subscribed_ids) == 0

def test_listener(notifier: YouTubeNotifier) -> None:
Expand Down
16 changes: 8 additions & 8 deletions ytnoti/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
import warnings
from asyncio import Task
from collections.abc import Callable, Coroutine, Iterable
from contextlib import asynccontextmanager, contextmanager
from contextlib import asynccontextmanager, contextmanager, suppress
from datetime import datetime
from http import HTTPStatus
from pyexpat import ExpatError
Expand All @@ -38,6 +38,7 @@
from fastapi.routing import APIRoute
from httpx import AsyncClient
from pyngrok import ngrok
from pyngrok.exception import PyngrokNgrokURLError
from starlette.routing import Route
from uvicorn import Config, Server

Expand Down Expand Up @@ -591,19 +592,17 @@ async def subscribe(self, channel_ids: str | Iterable[str]) -> Self:

async def unsubscribe(self, channel_ids: str | Iterable[str]) -> Self:
"""Unsubscribe from YouTube channels to stop receiving push notifications.
This is lazy and will unsubscribe when the notifier is ready.
If the notifier is already ready, it will unsubscribe immediately.
:param channel_ids: The channel ID(s) to unsubscribe from.
:return: The current instance for method chaining.
:raises ValueError: If the channel ID is invalid.
:raises HTTPError: If failed to verify the channel ID or failed to unsubscribe
due to an HTTP error.
:raises ValueError: If the channel_ids includes ids that are not subscribed
"""
if isinstance(channel_ids, str):
channel_ids = [channel_ids]

await self._verify_channel_ids(channel_ids)
if not self._subscribed_ids.issuperset(channel_ids):
raise ValueError(f"No such subscribed channel IDs: "
f"{self._subscribed_ids.difference(channel_ids)}")

unsubscribe_ids = self._subscribed_ids.intersection(channel_ids)

Expand Down Expand Up @@ -687,7 +686,8 @@ def stop(self) -> None:
self._server = None

if self._config.using_ngrok:
ngrok.disconnect(self._config.callback_url)
with suppress(PyngrokNgrokURLError):
ngrok.disconnect(self._config.callback_url)

async def _on_exit(self) -> None:
"""Perform a task after the notifier is stopped."""
Expand Down

0 comments on commit 5ed056f

Please sign in to comment.