Skip to content

Commit

Permalink
Add files via upload
Browse files Browse the repository at this point in the history
  • Loading branch information
d60 authored Mar 24, 2024
1 parent ef59d24 commit f6742ea
Show file tree
Hide file tree
Showing 4 changed files with 170 additions and 3 deletions.
2 changes: 1 addition & 1 deletion twikit/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,4 @@
from .user import User
from .utils import build_query

__version__ = '1.3.12'
__version__ = '1.3.13'
2 changes: 2 additions & 0 deletions twikit/tweet.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ class Tweet:
Related tweets.
hashtags: list[str]
Hashtags included in the tweet text.
poll : Poll
Poll attached to the tweet.
"""

def __init__(self, client: Client, data: dict, user: User = None) -> None:
Expand Down
50 changes: 49 additions & 1 deletion twikit/twikit_async/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
from .message import Message
from .notification import Notification
from .trend import Trend
from .tweet import ScheduledTweet, Tweet
from .tweet import Poll, ScheduledTweet, Tweet
from .user import User
from .utils import Result

Expand Down Expand Up @@ -813,6 +813,54 @@ async def create_poll(

return response['card_uri']

async def vote(
self,
selected_choice: str,
card_uri: str,
tweet_id: str,
card_name: str
) -> Poll:
"""
Vote on a poll with the selected choice.
Parameters
----------
selected_choice : str
The label of the selected choice for the vote.
card_uri : str
The URI of the poll card.
tweet_id : str
The ID of the original tweet containing the poll.
card_name : str
The name of the poll card.
Returns
-------
Poll
The Poll object representing the updated poll after voting.
"""
data = urlencode({
'twitter:string:card_uri': card_uri,
'twitter:long:original_tweet_id': tweet_id,
'twitter:string:response_card_name': card_name,
'twitter:string:cards_platform': 'Web-12',
'twitter:string:selected_choice': selected_choice
})
print(card_uri, tweet_id, card_name, selected_choice)

headers = self._base_headers | {
'content-type': 'application/x-www-form-urlencoded'
}
response = (await self.http.post(
Endpoint.VOTE,
data=data,
headers=headers
)).json()

card_data = {
'rest_id': response['card']['url'],
'legacy': response['card']
}
return Poll(self, card_data, None)

async def create_tweet(
self,
text: str = '',
Expand Down
119 changes: 118 additions & 1 deletion twikit/twikit_async/tweet.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from __future__ import annotations

import re
from datetime import datetime
from typing import TYPE_CHECKING

Expand Down Expand Up @@ -159,10 +160,22 @@ def __init__(self, client: Client, data: dict, user: User = None) -> None:
i['text'] for i in hashtags
]

if (
'card' in data and
data['card']['legacy']['name'].startswith('poll')
):
self._poll_data = data['card']
else:
self._poll_data = None

@property
def created_at_datetime(self) -> datetime:
return timestamp_to_datetime(self.created_at)

@property
def poll(self) -> Poll:
return self._poll_data and Poll(self._client, self._poll_data, self)

async def delete(self) -> Response:
"""Deletes the tweet.
Expand Down Expand Up @@ -405,4 +418,108 @@ async def delete(self) -> Response:
return await self._client.delete_scheduled_tweet(self.id)

def __repr__(self) -> str:
return f'<ScheduledTweet id="{self.id}">'
return f'<ScheduledTweet id="{self.id}">'


class Poll:
"""Represents a poll associated with a tweet.
Attributes
----------
tweet : Tweet
The tweet associated with the poll.
id : str
The unique identifier of the poll.
name : str
The name of the poll.
choices : list of dict
A list containing dictionaries representing poll choices.
Each dictionary contains 'label' and 'count' keys
for choice label and count.
duration_minutes : int
The duration of the poll in minutes.
end_datetime_utc : str
The end date and time of the poll in UTC format.
last_updated_datetime_utc : str
The last updated date and time of the poll in UTC format.
selected_choice : str | None
Number of the selected choice.
"""

def __init__(
self, client: Client, data: dict, tweet: Tweet | None = None
) -> None:
self._client = client
self.tweet = tweet

legacy = data['legacy']
binding_values = legacy['binding_values']

if isinstance(legacy['binding_values'], list):
binding_values = {
i.get('key'): i.get('value')
for i in legacy['binding_values']
}

self.id: str = data['rest_id']
self.name: str = legacy['name']

choices_number = int(re.findall(
r'poll(\d)choice_text_only', self.name
)[0])
choices = []

for i in range(1, choices_number + 1):
choice_label = binding_values[f'choice{i}_label']
choice_count = binding_values[f'choice{i}_count']
choices.append({
'number': str(i),
'label': choice_label['string_value'],
'count': choice_count.get('string_value', '0')
})

self.choices = choices

duration_minutes = binding_values['duration_minutes']['string_value']
self.duration_minutes = int(duration_minutes)

end = binding_values['end_datetime_utc']['string_value']
updated = binding_values['last_updated_datetime_utc']['string_value']
self.end_datetime_utc: str = end
self.last_updated_datetime_utc: str = updated

counts_are_final = binding_values['counts_are_final']['boolean_value']
self.counts_are_final: bool = counts_are_final

if 'selected_choice' in binding_values:
selected_choice = binding_values['selected_choice']['string_value']
self.selected_choice: str = selected_choice
else:
self.selected_choice = None

async def vote(self, selected_choice: str) -> Poll:
"""
Vote on the poll with the specified selected choice.
Parameters
----------
selected_choice : str
The label of the selected choice for the vote.
Returns
-------
Poll
The Poll object representing the updated poll after voting.
"""
return await self._client.vote(
selected_choice,
self.id,
self.tweet.id,
self.name
)

def __repr__(self) -> str:
return f'<Poll id="{self.id}">'

def __eq__(self, __value: object) -> bool:
return isinstance(__value, Poll) and self.id == __value.id

def __ne__(self, __value: object) -> bool:
return not self == __value

0 comments on commit f6742ea

Please sign in to comment.