Skip to content

Commit f5b01c2

Browse files
authored
Add schedule endpoint and models (#211)
* Replace if statement with if expression * Simplify conditional into return statement * Inline variable that is immediately returned * Comparison moved to the right Use set when checking membership of a collection of literals * Inline variable that is immediately returned * remove none from dict.get returns none by default * Replace if statement with if expression Replace multiple comparisons of same variable with `in` operator Remove redundant conditional * Merge nested if conditions Remove none from dict.get returns none by default * Lift code into else after jump in control flow, Merge else clause's nested if statement into elif Remove redundant pass statements Simplify logical expression * Inline variable that is immediately returned * Merge nested if conditions Inline variable that is immediately returned * Merge nested if conditions * Swap if/else branches, Remove unnecessary else after guard condition * Replace unneeded comprehension with generator * added fetch_channel to client * formatting * remove typehint of User * Added fetch_follow method Removed for loop for fetch_channel * Update README.rst Added myself....just because * fix remove_cog * Fixed remove_cog * changed from list to set * Moved fetch_follow to user from client Fixed black formatting to 120 * Added ChannelInfo class in models Changed fetch_channel to return the ChannelInfo object * Removed except from remove_cog Issue was in unload_module Missing .items() for callsbacks Missing .__name__ for comparison * fixed reload_module * added created_at to User class * Routine fix where after task run completion iterations would set to 0 and run infinitely. * Add typehint for PartialUser in fetch_follow * Removed duplicate fetch_channel Updated docstring fetch_channel * Changed badges to a property returns a dict * change to more obvious wording * fetch duplicate fetch_channel update docstring * added founder to is_subscriber * Update websocket to fix chatters Correct some typos Update badges docstring Fix eventsub BanData key * reverted changes to ChannelBanData model * changed payload key to is_permanent for ChannelBanData * Added Schedule models Added user method fetch_schedule Added associated API calls Added explicit detail in fetch_channel docstring * forgot to merge * Revert "changed payload key to is_permanent for ChannelBanData" This reverts commit ba16c04. * Revert "forgot to merge" This reverts commit 7b16588. * Revert "Added Schedule models" This reverts commit ea6f7bf. * trying to fix my own repo * add * Added Schedule models Added user method fetch_schedule Added associated API calls Added explicit detail in fetch_channel docstring * added back in newlines from formatting * change to list comp * black formatting * change raise to ValueError and move above comp * changed segment_ids to list * update docstring * update docstring * Changed start_time to datetime object Internal conversion to RFC3339 Changed utc_offset to int and convert to str later * adding modify stream to match master * adding back in schedule
1 parent 1d475ca commit f5b01c2

File tree

4 files changed

+131
-4
lines changed

4 files changed

+131
-4
lines changed

twitchio/client.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -397,7 +397,7 @@ async def fetch_clips(self, ids: List[str]):
397397
return [models.Clip(self._http, d) for d in data]
398398

399399
async def fetch_channel(self, broadcaster: str):
400-
"""Retrieve a channel from the API.
400+
"""Retrieve channel information from the API.
401401
402402
Parameters
403403
-----------

twitchio/http.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -766,6 +766,45 @@ async def patch_channel(
766766
Route("PATCH", "channels", query=[("broadcaster_id", broadcaster_id)], body=body, token=token)
767767
)
768768

769+
async def get_channel_schedule(
770+
self,
771+
broadcaster_id: str,
772+
segment_ids: List[str] = None,
773+
start_time: datetime.datetime = None,
774+
utc_offset: int = None,
775+
first: int = 20,
776+
):
777+
778+
if first is not None and (first > 25 or first < 1):
779+
raise ValueError("The parameter 'first' was malformed: the value must be less than or equal to 25")
780+
if segment_ids is not None and len(segment_ids) > 100:
781+
raise ValueError("segment_id can only have 100 entries")
782+
783+
if start_time:
784+
start_time = start_time.strftime("%Y-%m-%dT%H:%M:%SZ")
785+
786+
if utc_offset:
787+
utc_offset = str(utc_offset)
788+
789+
q = [
790+
x
791+
for x in [
792+
("broadcaster_id", broadcaster_id),
793+
("first", first),
794+
("start_time", start_time),
795+
("utc_offset", utc_offset),
796+
]
797+
if x[1] is not None
798+
]
799+
800+
if segment_ids:
801+
for id in segment_ids:
802+
q.append(
803+
("id", id),
804+
)
805+
806+
return await self.request(Route("GET", "schedule", query=q), paginate=False, full_body=True)
807+
769808
async def get_channel_subscriptions(self, token: str, broadcaster_id: str, user_ids: List[str] = None):
770809
q = [("broadcaster_id", broadcaster_id)]
771810
if user_ids:

twitchio/models.py

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -612,7 +612,7 @@ def __init__(self, http: "TwitchHTTP", data: dict):
612612
self.locked_at = self._parse_time(data, "locked_at")
613613

614614
def _parse_time(self, data, field) -> Optional["Datetime"]:
615-
if field not in data or data[field] == None:
615+
if field not in data or data[field] is None:
616616
return None
617617

618618
time = data[field].split(".")[0]
@@ -654,3 +654,58 @@ def colour(self) -> str:
654654

655655
def __repr__(self):
656656
return f"<PredictionOutcome outcome_id={self.outcome_id} title={self.title} channel_points={self.channel_points} color={self.color}>"
657+
658+
class Schedule:
659+
660+
__slots__ = ("segments", "user", "vacation")
661+
662+
def __init__(self, http: "TwitchHTTP", data: dict):
663+
self.segments = [ScheduleSegment(d) for d in data["data"]["segments"]]
664+
self.user = PartialUser(http, data["data"]["broadcaster_id"], data["data"]["broadcaster_login"])
665+
self.vacation = ScheduleVacation(data["data"]["vacation"]) if data["data"]["vacation"] else None
666+
667+
def __repr__(self):
668+
return f"<Schedule segments={self.segments} user={self.user} vacation={self.vacation}>"
669+
670+
671+
class ScheduleSegment:
672+
673+
__slots__ = ("id", "start_time", "end_time", "title", "canceled_until", "category", "is_recurring")
674+
675+
def __init__(self, data: dict):
676+
self.id: str = data["id"]
677+
self.start_time = datetime.datetime.strptime(data["start_time"], "%Y-%m-%dT%H:%M:%SZ")
678+
self.end_time = datetime.datetime.strptime(data["end_time"], "%Y-%m-%dT%H:%M:%SZ")
679+
self.title: str = data["title"]
680+
self.canceled_until = (
681+
datetime.datetime.strptime(data["canceled_until"], "%Y-%m-%dT%H:%M:%SZ") if data["canceled_until"] else None
682+
)
683+
self.category = ScheduleCategory(data["category"]) if data["category"] else None
684+
self.is_recurring: bool = data["is_recurring"]
685+
686+
def __repr__(self):
687+
return f"<Segment id={self.id} start_time={self.start_time} end_time={self.end_time} title={self.title} canceled_until={self.canceled_until} category={self.category} is_recurring={self.is_recurring}>"
688+
689+
690+
class ScheduleCategory:
691+
692+
__slots__ = ("id", "name")
693+
694+
def __init__(self, data: dict):
695+
self.id: str = data["id"]
696+
self.name: str = data["name"]
697+
698+
def __repr__(self):
699+
return f"<ScheduleCategory id={self.id} name={self.name}>"
700+
701+
702+
class ScheduleVacation:
703+
704+
__slots__ = ("start_time", "end_time")
705+
706+
def __init__(self, data: dict):
707+
self.start_time = datetime.datetime.strptime(data["start_time"], "%Y-%m-%dT%H:%M:%SZ")
708+
self.end_time = datetime.datetime.strptime(data["end_time"], "%Y-%m-%dT%H:%M:%SZ")
709+
710+
def __repr__(self):
711+
return f"<ScheduleVacation start_time={self.start_time} end_time={self.end_time}>"

twitchio/user.py

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -604,7 +604,7 @@ async def fetch_videos(self, period="all", sort="time", type="all", language=Non
604604
--------
605605
List[:class:`twitchio.Video`]
606606
"""
607-
from models import Video
607+
from .models import Video
608608

609609
data = await self._http.get_videos(user_id=str(self.id), period=period, sort=sort, type=type, language=language)
610610
return [Video(self._http, x, self) for x in data]
@@ -696,7 +696,6 @@ async def create_prediction(
696696
async def modify_stream(self, token: str, game_id: int = None, language: str = None, title: str = None):
697697
"""|coro|
698698
Modify stream information
699-
700699
Parameters
701700
-----------
702701
token: :class:`str`
@@ -716,6 +715,40 @@ async def modify_stream(self, token: str, game_id: int = None, language: str = N
716715
title=title,
717716
)
718717

718+
async def fetch_schedule(
719+
self,
720+
segment_ids: List[str] = None,
721+
start_time: datetime.datetime = None,
722+
utc_offset: int = None,
723+
first: int = 20,
724+
):
725+
"""|coro|
726+
Fetches the schedule of a streamer
727+
Parameters
728+
-----------
729+
segment_ids: Optional[List[:class:`str`]]
730+
List of segment IDs of the stream schedule to return. Maximum: 100
731+
start_time: Optional[:class:`datetime.datetime`]
732+
A datetime object to start returning stream segments from. If not specified, the current date and time is used.
733+
utc_offset: Optional[:class:`int`]
734+
A timezone offset for the requester specified in minutes. +4 hours from GMT would be `240`
735+
first: Optional[:class:`int`]
736+
Maximum number of stream segments to return. Maximum: 25. Default: 20.
737+
Returns
738+
--------
739+
:class:`twitchio.Schedule`
740+
"""
741+
from .models import Schedule
742+
743+
data = await self._http.get_channel_schedule(
744+
broadcaster_id=str(self.id),
745+
segment_ids=segment_ids,
746+
start_time=start_time,
747+
utc_offset=utc_offset,
748+
first=first,
749+
)
750+
751+
return Schedule(self._http, data)
719752

720753
class BitLeaderboardUser(PartialUser):
721754

0 commit comments

Comments
 (0)