Implement a way to send watch events through GQL
This commit is contained in:
1 parent
cac9b29587
commit
40000cf295
5 files changed
+98
-38
No files matched your search
+50
-9
@@ -1,6 +1,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
import gzip
|
||||
import json
|
||||
import asyncio
|
||||
import logging
|
||||
@@ -11,14 +12,14 @@ from typing import Any, SupportsInt, cast, TYPE_CHECKING
|
||||
import aiohttp
|
||||
from yarl import URL
|
||||
|
||||
from utils import Game, json_minify
|
||||
from utils import Game, json_minify, isonow
|
||||
from exceptions import MinerException, RequestException
|
||||
from constants import CALL, GQL_OPERATIONS, ONLINE_DELAY, URLType
|
||||
from constants import CALL, GQL_QUERIES, ONLINE_DELAY, URLType, GQLQuery
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from twitch import Twitch
|
||||
from gui import ChannelList
|
||||
from constants import JsonType, GQLOperation
|
||||
from constants import JsonType, GQLPersistedQuery
|
||||
|
||||
|
||||
logger = logging.getLogger("TwitchDrops")
|
||||
@@ -63,6 +64,36 @@ class Stream:
|
||||
]
|
||||
return {"data": (b64encode(json_minify(payload).encode("utf8"))).decode("utf8")}
|
||||
|
||||
@cached_property
|
||||
def _gql_payload(self) -> GQLQuery:
|
||||
payload = [
|
||||
{
|
||||
"event": "minute-watched",
|
||||
"properties": {
|
||||
"broadcast_id": str(self.broadcast_id),
|
||||
"channel_id": str(self.channel.id),
|
||||
"channel": self.channel._login,
|
||||
"client_time": isonow(),
|
||||
"game": self.game.name if self.game is not None else "",
|
||||
"game_id": str(self.game.id) if self.game is not None else "",
|
||||
"hidden": False,
|
||||
"is_live": True,
|
||||
"live": True,
|
||||
"logged_in": True,
|
||||
"minutes_logged": 1,
|
||||
"muted": False,
|
||||
"user_id": self.channel._twitch._auth_state.user_id,
|
||||
}
|
||||
}
|
||||
]
|
||||
return GQLQuery(
|
||||
(
|
||||
"\n mutation SendEvents($input: SendSpadeEventsInput!) "
|
||||
"{\n sendSpadeEvents(input: $input) {\n statusCode\n}\n}\n"
|
||||
),
|
||||
b64encode(gzip.compress(json_minify(payload).encode("utf8"))).decode("utf8")
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def from_get_stream(cls, channel: Channel, channel_data: JsonType) -> Stream:
|
||||
stream = channel_data["stream"]
|
||||
@@ -99,7 +130,7 @@ class Stream:
|
||||
return self._stream_url
|
||||
# get the stream playback access token from GQL
|
||||
playback_token_response: JsonType = await self.channel._twitch.gql_request(
|
||||
GQL_OPERATIONS["PlaybackAccessToken"].with_variables({"login": self.channel._login})
|
||||
GQL_QUERIES["PlaybackAccessToken"].with_variables({"login": self.channel._login})
|
||||
)
|
||||
token_data: JsonType = playback_token_response["data"]["streamPlaybackAccessToken"]
|
||||
token_value = token_data["value"]
|
||||
@@ -203,8 +234,8 @@ class Channel:
|
||||
return self.id
|
||||
|
||||
@property
|
||||
def stream_gql(self) -> GQLOperation:
|
||||
return GQL_OPERATIONS["GetStreamInfo"].with_variables({"channel": self._login})
|
||||
def stream_gql(self) -> GQLPersistedQuery:
|
||||
return GQL_QUERIES["GetStreamInfo"].with_variables({"channel": self._login})
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
@@ -342,7 +373,7 @@ class Channel:
|
||||
if not stream.drops_enabled:
|
||||
try:
|
||||
available_drops_campaigns: JsonType = await self._twitch.gql_request(
|
||||
GQL_OPERATIONS["AvailableDrops"].with_variables({"channelID": str(self.id)})
|
||||
GQL_QUERIES["AvailableDrops"].with_variables({"channelID": str(self.id)})
|
||||
)
|
||||
except MinerException:
|
||||
logger.log(CALL, f"AvailableDrops GQL call failed for channel: {self._login}")
|
||||
@@ -408,7 +439,7 @@ class Channel:
|
||||
self.display()
|
||||
|
||||
# NOTE: This is currently unused.
|
||||
async def _send_watch(self) -> bool:
|
||||
async def _send_watch_playlist(self) -> bool:
|
||||
"""
|
||||
This performs a HEAD request on the stream's current playlist,
|
||||
to simulate watching the stream.
|
||||
@@ -460,7 +491,8 @@ class Channel:
|
||||
async with self._twitch.request("HEAD", stream_chunk_url) as head_response:
|
||||
return head_response.status == 200
|
||||
|
||||
async def send_watch(self) -> bool:
|
||||
# NOTE: This is currently unused.
|
||||
async def _send_watch_spade(self) -> bool:
|
||||
if self._stream is None:
|
||||
return False
|
||||
if self._spade_url is None:
|
||||
@@ -472,3 +504,12 @@ class Channel:
|
||||
return response.status == 204
|
||||
except RequestException:
|
||||
return False
|
||||
|
||||
async def send_watch(self) -> bool: # send_watch_gql
|
||||
if self._stream is None:
|
||||
return False
|
||||
try:
|
||||
watch_response = await self._twitch.gql_request(self._stream._gql_payload)
|
||||
return watch_response["data"]["sendSpadeEvents"]["statusCode"] == 204
|
||||
except RequestException:
|
||||
return False
|
||||
Reference in new issue
Block a user