Skip to content

Commit

Permalink
Update topic url for pubsub
Browse files Browse the repository at this point in the history
  • Loading branch information
SeoulSKY committed Aug 7, 2024
1 parent bddb75a commit d077e0c
Show file tree
Hide file tree
Showing 8 changed files with 39 additions and 70 deletions.
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
NGROK_TOKEN=
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.0.0
------

Breaking Changes
~~~~~~~~~~~~~~~~

* Following fields in ``Video`` are removed as these are not sent by YouTube in the push notifications:

* description
* thumbnail
* stats

Bug Fixes
~~~~~~~~~

* Fixed YouTubeNotifier.run() and AsyncYouTubeNotifier.serve() raising TypeError when the optional parameter ``app`` wasn't given.
* Fixed (Async)YouTubeNotifier not invoking the event listeners for some YouTube channels.

v1.1.2
------

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

# -- General configuration ---------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
Expand Down
2 changes: 2 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@ pyngrok~=7.1.6
httpx~=0.27.0
setuptools~=70.1.1
aiofiles~=24.1.0
pytest~=8.3.2
python-dotenv~=1.0.1
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

setup(
name="ytnoti",
version="1.1.2",
version="2.0.0",
packages=find_packages(),
author="SeoulSKY",
author_email="contact@seoulsky.org",
Expand Down
2 changes: 1 addition & 1 deletion ytnoti/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from ytnoti.enums import NotificationKind, ServerMode
from ytnoti.models import YouTubeNotifierConfig
from ytnoti.models.history import VideoHistory
from ytnoti.models.video import Channel, Thumbnail, Video, Stats, Timestamp
from ytnoti.models.video import Channel, Video, Timestamp
from ytnoti.types import NotificationListener, T


Expand Down
39 changes: 15 additions & 24 deletions ytnoti/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
from ytnoti.errors import HTTPError
from ytnoti.models import YouTubeNotifierConfig
from ytnoti.models.history import InMemoryVideoHistory, VideoHistory
from ytnoti.models.video import Channel, Thumbnail, Video, Stats, Timestamp
from ytnoti.models.video import Channel, Video, Timestamp
from ytnoti.types import NotificationListener


Expand Down Expand Up @@ -312,7 +312,7 @@ def _get_server(self,

endpoint = urlparse(self._config.callback_url).path or "/"

if any(isinstance(route, (APIRoute, Route)) and route.path == endpoint for route in app.routes):
if any(isinstance(route, (APIRoute, Route)) and route.path == endpoint for route in self._config.app.routes):
raise ValueError(f"Endpoint {endpoint} is reserved for {__package__} so it cannot be used by the app")

self._config.app.include_router(self._get_router())
Expand Down Expand Up @@ -403,7 +403,7 @@ async def _register(self,
"https://pubsubhubbub.appspot.com",
data={
"hub.mode": mode,
"hub.topic": f"https://www.youtube.com/feeds/videos.xml?channel_id={channel_id}",
"hub.topic": f"https://www.youtube.com/xml/feeds/videos.xml?channel_id={channel_id}",
"hub.callback": self._config.callback_url,
"hub.verify": "sync",
"hub.secret": self._config.password,
Expand Down Expand Up @@ -473,7 +473,7 @@ async def _clean_up(self, *, running_server: Server | None) -> None:
@staticmethod
async def _get(request: Request):
"""
Handle challenge from the Google pubsubhubbub server.
Handle a challenge from the Google pubsubhubbub server.
"""

challenge = request.query_params.get("hub.challenge")
Expand Down Expand Up @@ -506,35 +506,17 @@ async def _post(self, request: Request):
id=entry["yt:channelId"],
name=entry["author"]["name"],
url=entry["author"]["uri"],
created_at=datetime.strptime(body["feed"]["published"], "%Y-%m-%dT%H:%M:%S%z")
)

thumbnail = Thumbnail(
url=entry["media:group"]["media:thumbnail"]["@url"],
width=int(entry["media:group"]["media:thumbnail"]["@width"]),
height=int(entry["media:group"]["media:thumbnail"]["@height"]),
)

# Uploader can hide video stats
stats = None
if "media:community" in entry["media:group"]:
stats = Stats(
likes=int(entry["media:group"]["media:community"]["media:starRating"]["@count"]),
views=int(entry["media:group"]["media:community"]["media:statistics"]["@views"]),
)

timestamp = Timestamp(
published=datetime.strptime(entry["published"], "%Y-%m-%dT%H:%M:%S%z"),
updated=datetime.strptime(entry["updated"], "%Y-%m-%dT%H:%M:%S%z")
published=self._parse_timestamp(entry["published"]),
updated=self._parse_timestamp(entry["updated"])
)

video = Video(
id=entry["yt:videoId"],
title=entry["title"],
description=entry["media:group"]["media:description"] or "",
url=entry["link"]["@href"],
thumbnail=thumbnail,
stats=stats,
timestamp=timestamp,
channel=channel
)
Expand All @@ -556,6 +538,15 @@ async def _post(self, request: Request):

return Response(status_code=HTTPStatus.NO_CONTENT.value)

@staticmethod
def _parse_timestamp(timestamp: str) -> datetime:
time, zone = timestamp.split("+", 1)

# Remove fractional seconds if exists
time = time.split(".", 1)[0]

return datetime.strptime(f"{time}+{zone}", "%Y-%m-%dT%H:%M:%S%z")

async def _is_authorized(self, request: Request) -> bool:
x_hub_signature = request.headers.get("X-Hub-Signature")
# Check if the header is missing or invalid
Expand Down
43 changes: 0 additions & 43 deletions ytnoti/models/video.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,38 +21,6 @@ class Channel:
url: str
"""The URL of the channel"""

created_at: datetime
"""The time when the channel was created"""


@dataclass
class Thumbnail:
"""
Represents a thumbnail of a video
"""

url: str
"""The URL of the thumbnail"""

width: int
"""The width of the thumbnail"""

height: int
"""The height of the thumbnail"""


@dataclass
class Stats:
"""
Represents the stats of a video
"""

likes: int
"""The number of likes of the video"""

views: int
"""The number of views of the video"""


@dataclass
class Timestamp:
Expand All @@ -73,26 +41,15 @@ class Video:
Represents a YouTube video
"""

# pylint: disable=too-many-instance-attributes

id: str
"""The unique ID of the video"""

title: str
"""The title of the video"""

description: str
"""The description of the video"""

url: str
"""The URL of the video"""

thumbnail: Thumbnail
"""The thumbnail of the video"""

stats: Stats | None
"""The stats of the video, if available"""

timestamp: Timestamp
"""The timestamps of the video"""

Expand Down

0 comments on commit d077e0c

Please sign in to comment.