tweepy-self 1.10.0b7__py3-none-any.whl → 1.10.0b8__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: tweepy-self
3
- Version: 1.10.0b7
3
+ Version: 1.10.0b8
4
4
  Summary: Twitter (selfbot) for Python!
5
5
  Home-page: https://github.com/alenkimov/tweepy-self
6
6
  Author: Alen
@@ -10,14 +10,14 @@ twitter/account.py,sha256=joAB5Zw-Le5E3kOZ-1nb4DPGlTqWYv2Vs6gJ3cwu7is,3175
10
10
  twitter/base/__init__.py,sha256=Q2ko0HeOS5tiBnDVKxxaZYetwRR3YXJ67ujL3oThGd4,141
11
11
  twitter/base/client.py,sha256=J_iL4ZGfwTbZ2gpjtFCbBxNgt7weJ55EeMGzYsLtjf4,500
12
12
  twitter/base/session.py,sha256=JFPS-9Qae1iY3NfNcywxvWWmRDijaU_Rjs3WaQ00iFA,2071
13
- twitter/client.py,sha256=69QQb-ZnbjqpIhhozxsboruuy3MeJDUGM7nPEH-cBdg,73559
13
+ twitter/client.py,sha256=3eCld11wiZPOKF561RlTcJ_Re-lupvGSPz7MPKrJl1k,75103
14
14
  twitter/enums.py,sha256=-OH6Ibxarq5qt4E2AhkProVawcEyIf5YG_h_G5xiV9Y,270
15
15
  twitter/errors.py,sha256=oNa0Neos80ZK4-0FBzqgxXonH564qFnoN-kavHalfR4,5274
16
- twitter/models.py,sha256=7yObMPUUEwJEbraHzFwmUKd91UhR2-zyfJTm4xIqrSQ,4834
16
+ twitter/models.py,sha256=CrGb3dvA0U4PfPTkUtuprPKXpqkLpM8AR_-De4D3efM,5677
17
17
  twitter/utils/__init__.py,sha256=usxpfcRQ7zxTTgZ-i425tT7hIz73Pwh9FDj4t6O3dYg,663
18
18
  twitter/utils/file.py,sha256=Sz2KEF9DnL04aOP1XabuMYMMF4VR8dJ_KWMEVvQ666Y,1120
19
19
  twitter/utils/html.py,sha256=nrOJw0vUKfBaHgFaQSQIdXfvfZ8mdu84MU_s46kJTJ4,2087
20
20
  twitter/utils/other.py,sha256=9RIYF2AMdmNKIwClG3jBP7zlvxZPEgYfuHaIiOhURzM,1061
21
- tweepy_self-1.10.0b7.dist-info/METADATA,sha256=NpC2w-frRkmdX851z52xcAnsXX33NJ49pNuo21TIFUY,13153
22
- tweepy_self-1.10.0b7.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
23
- tweepy_self-1.10.0b7.dist-info/RECORD,,
21
+ tweepy_self-1.10.0b8.dist-info/METADATA,sha256=gghI1xBSOt1w8QajiIFg6H93LAydql3haQ3tk0YghoU,13153
22
+ tweepy_self-1.10.0b8.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
23
+ tweepy_self-1.10.0b8.dist-info/RECORD,,
twitter/client.py CHANGED
@@ -30,7 +30,7 @@ from .errors import (
30
30
  from .utils import to_json
31
31
  from .base import BaseHTTPClient
32
32
  from .account import Account, AccountStatus
33
- from .models import User, Tweet, Media
33
+ from .models import User, Tweet, Media, Subtask
34
34
  from .utils import (
35
35
  parse_oauth_html,
36
36
  parse_unlock_html,
@@ -1377,7 +1377,8 @@ class Client(BaseHTTPClient):
1377
1377
  solution = await FunCaptcha(**funcaptcha).aio_captcha_handler()
1378
1378
  if solution.errorId:
1379
1379
  logger.warning(
1380
- f"{self.account} Failed to solve funcaptcha:"
1380
+ f"(auth_token={self.account.hidden_auth_token}, id={self.account.id}, username={self.account.username})"
1381
+ f"Failed to solve funcaptcha:"
1381
1382
  f"\n\tUnlock attempt: {attempt}/{self.max_unlock_attempts}"
1382
1383
  f"\n\tError ID: {solution.errorId}"
1383
1384
  f"\n\tError code: {solution.errorCode}"
@@ -1427,18 +1428,46 @@ class Client(BaseHTTPClient):
1427
1428
  response, response_json = await self.request("GET", url)
1428
1429
  self.account.backup_code = response_json["codes"][0]
1429
1430
 
1430
- async def _task(self, **kwargs):
1431
+ async def _send_raw_subtask(self, **request_kwargs) -> tuple[str, list[Subtask]]:
1431
1432
  """
1432
- :return: flow_token, subtasks
1433
+ :return: flow_token and subtasks
1433
1434
  """
1434
1435
  url = "https://api.twitter.com/1.1/onboarding/task.json"
1435
- response, response_json = await self.request("POST", url, **kwargs)
1436
- return response_json["flow_token"], response_json["subtasks"]
1436
+ response, data = await self.request("POST", url, **request_kwargs)
1437
+ subtasks = [
1438
+ Subtask.from_raw_data(subtask_data) for subtask_data in data["subtasks"]
1439
+ ]
1440
+ log_message = (
1441
+ f"(auth_token={self.account.hidden_auth_token}, id={self.account.id}, username={self.account.username})"
1442
+ f" Requested subtasks:"
1443
+ )
1444
+ for subtask in subtasks:
1445
+ log_message += f"\n\t{subtask.id}"
1446
+ if subtask.primary_text:
1447
+ log_message += f"\n\tPrimary text: {subtask.primary_text}"
1448
+ if subtask.secondary_text:
1449
+ log_message += f"\n\tSecondary text: {subtask.secondary_text}"
1450
+ if subtask.detail_text:
1451
+ log_message += f"\n\tDetail text: {subtask.detail_text}"
1452
+ logger.debug(log_message)
1453
+ return data["flow_token"], subtasks
1437
1454
 
1438
- async def _request_login_tasks(self):
1439
- """
1440
- :return: flow_token, subtask_ids
1441
- """
1455
+ async def _complete_subtask(
1456
+ self,
1457
+ flow_token: str,
1458
+ inputs: list[dict],
1459
+ **request_kwargs,
1460
+ ) -> tuple[str, list[Subtask]]:
1461
+ payload = request_kwargs["json"] = request_kwargs.get("json") or {}
1462
+ payload.update(
1463
+ {
1464
+ "flow_token": flow_token,
1465
+ "subtask_inputs": inputs,
1466
+ }
1467
+ )
1468
+ return await self._send_raw_subtask(**request_kwargs)
1469
+
1470
+ async def _request_login_tasks(self) -> tuple[str, list[Subtask]]:
1442
1471
  params = {
1443
1472
  "flow_name": "login",
1444
1473
  }
@@ -1493,30 +1522,14 @@ class Client(BaseHTTPClient):
1493
1522
  "web_modal": 1,
1494
1523
  },
1495
1524
  }
1496
- return await self._task(params=params, json=payload, auth=False)
1497
-
1498
- async def _send_task(self, flow_token: str, subtask_inputs: list[dict], **kwargs):
1499
- payload = kwargs["json"] = kwargs.get("json") or {}
1500
- payload.update(
1501
- {
1502
- "flow_token": flow_token,
1503
- "subtask_inputs": subtask_inputs,
1504
- }
1505
- )
1506
- return await self._task(**kwargs)
1507
-
1508
- async def _finish_task(self, flow_token):
1509
- payload = {
1510
- "flow_token": flow_token,
1511
- "subtask_inputs": [],
1512
- }
1513
- return await self._task(json=payload)
1525
+ return await self._send_raw_subtask(params=params, json=payload, auth=False)
1514
1526
 
1515
- async def _login_enter_user_identifier(self, flow_token):
1516
- subtask_inputs = [
1527
+ async def _login_enter_user_identifier(self, flow_token: str):
1528
+ inputs = [
1517
1529
  {
1518
1530
  "subtask_id": "LoginEnterUserIdentifierSSO",
1519
1531
  "settings_list": {
1532
+ "link": "next_link",
1520
1533
  "setting_responses": [
1521
1534
  {
1522
1535
  "key": "user_identifier",
@@ -1528,49 +1541,48 @@ class Client(BaseHTTPClient):
1528
1541
  },
1529
1542
  }
1530
1543
  ],
1531
- "link": "next_link",
1532
1544
  },
1533
1545
  }
1534
1546
  ]
1535
- return await self._send_task(flow_token, subtask_inputs, auth=False)
1547
+ return await self._complete_subtask(flow_token, inputs, auth=False)
1536
1548
 
1537
- async def _login_enter_password(self, flow_token):
1538
- subtask_inputs = [
1549
+ async def _login_enter_password(self, flow_token: str):
1550
+ inputs = [
1539
1551
  {
1540
1552
  "subtask_id": "LoginEnterPassword",
1541
1553
  "enter_password": {
1542
- "password": self.account.password,
1543
1554
  "link": "next_link",
1555
+ "password": self.account.password,
1544
1556
  },
1545
1557
  }
1546
1558
  ]
1547
- return await self._send_task(flow_token, subtask_inputs, auth=False)
1559
+ return await self._complete_subtask(flow_token, inputs, auth=False)
1548
1560
 
1549
1561
  async def _account_duplication_check(self, flow_token):
1550
- subtask_inputs = [
1562
+ inputs = [
1551
1563
  {
1552
1564
  "subtask_id": "AccountDuplicationCheck",
1553
1565
  "check_logged_in_account": {"link": "AccountDuplicationCheck_false"},
1554
1566
  }
1555
1567
  ]
1556
- return await self._send_task(flow_token, subtask_inputs, auth=False)
1568
+ return await self._complete_subtask(flow_token, inputs, auth=False)
1557
1569
 
1558
1570
  async def _login_two_factor_auth_challenge(self, flow_token, value: str):
1559
- subtask_inputs = [
1571
+ inputs = [
1560
1572
  {
1561
1573
  "subtask_id": "LoginTwoFactorAuthChallenge",
1562
1574
  "enter_text": {
1563
- "text": value,
1564
1575
  "link": "next_link",
1576
+ "text": value,
1565
1577
  },
1566
1578
  }
1567
1579
  ]
1568
- return await self._send_task(flow_token, subtask_inputs, auth=False)
1580
+ return await self._complete_subtask(flow_token, inputs, auth=False)
1569
1581
 
1570
1582
  async def _login_two_factor_auth_choose_method(
1571
1583
  self, flow_token: str, choices: Iterable[int] = (0,)
1572
1584
  ):
1573
- subtask_inputs = [
1585
+ inputs = [
1574
1586
  {
1575
1587
  "subtask_id": "LoginTwoFactorAuthChooseMethod",
1576
1588
  "choice_selection": {
@@ -1579,7 +1591,20 @@ class Client(BaseHTTPClient):
1579
1591
  },
1580
1592
  }
1581
1593
  ]
1582
- return await self._send_task(flow_token, subtask_inputs, auth=False)
1594
+ return await self._complete_subtask(flow_token, inputs, auth=False)
1595
+
1596
+ async def _login_acid(
1597
+ self,
1598
+ flow_token: str,
1599
+ value: str,
1600
+ ):
1601
+ inputs = [
1602
+ {
1603
+ "subtask_id": "LoginAcid",
1604
+ "enter_text": {"text": value, "link": "next_link"},
1605
+ }
1606
+ ]
1607
+ return await self._complete_subtask(flow_token, inputs, auth=False)
1583
1608
 
1584
1609
  async def _viewer(self):
1585
1610
  url, query_id = self._action_to_url("Viewer")
@@ -1596,9 +1621,9 @@ class Client(BaseHTTPClient):
1596
1621
  }
1597
1622
  variables = {"withCommunitiesMemberships": True}
1598
1623
  params = {
1599
- "features": to_json(features),
1600
- "fieldToggles": to_json(field_toggles),
1601
- "variables": to_json(variables),
1624
+ "features": features,
1625
+ "fieldToggles": field_toggles,
1626
+ "variables": variables,
1602
1627
  }
1603
1628
  return await self.request("GET", url, params=params)
1604
1629
 
@@ -1621,15 +1646,11 @@ class Client(BaseHTTPClient):
1621
1646
  guest_token = await self._request_guest_token()
1622
1647
  self._session.headers["X-Guest-Token"] = guest_token
1623
1648
 
1624
- # Можно не устанавливать, так как твиттер сам вернет этот токен
1625
- # self._session.cookies["gt"] = guest_token
1626
-
1627
1649
  flow_token, subtasks = await self._request_login_tasks()
1628
1650
  for _ in range(2):
1629
1651
  flow_token, subtasks = await self._login_enter_user_identifier(flow_token)
1630
1652
 
1631
- subtask_ids = [subtask["subtask_id"] for subtask in subtasks]
1632
-
1653
+ subtask_ids = {subtask.id for subtask in subtasks}
1633
1654
  if "LoginEnterAlternateIdentifierSubtask" in subtask_ids:
1634
1655
  if not self.account.username:
1635
1656
  raise TwitterException("Failed to login: no username to relogin")
@@ -1637,11 +1658,28 @@ class Client(BaseHTTPClient):
1637
1658
  flow_token, subtasks = await self._login_enter_password(flow_token)
1638
1659
  flow_token, subtasks = await self._account_duplication_check(flow_token)
1639
1660
 
1640
- subtask_ids = [subtask["subtask_id"] for subtask in subtasks]
1641
-
1642
- # TODO IMAP Обработчик
1661
+ subtask_ids = {subtask.id for subtask in subtasks}
1643
1662
  if "LoginAcid" in subtask_ids:
1644
- raise TwitterException(f"Failed to login: email verification!")
1663
+ if not self.account.email:
1664
+ raise TwitterException(
1665
+ f"Failed to login. Task id: LoginAcid. No email!"
1666
+ )
1667
+
1668
+ try:
1669
+ # fmt: off
1670
+ flow_token, subtasks = await self._login_acid(flow_token, self.account.email)
1671
+ # fmt: on
1672
+ except HTTPException as exc:
1673
+ if 399 in exc.api_codes:
1674
+ logger.warning(
1675
+ f"(auth_token={self.account.hidden_auth_token}, id={self.account.id}, username={self.account.username})"
1676
+ f" Bad email!"
1677
+ )
1678
+ raise TwitterException(
1679
+ f"Failed to login. Task id: LoginAcid. Bad email!"
1680
+ )
1681
+ else:
1682
+ raise
1645
1683
 
1646
1684
  if "LoginTwoFactorAuthChallenge" in subtask_ids:
1647
1685
  if not self.account.totp_secret:
@@ -1686,7 +1724,7 @@ class Client(BaseHTTPClient):
1686
1724
  else:
1687
1725
  raise
1688
1726
 
1689
- await self._finish_task(flow_token)
1727
+ await self._complete_subtask(flow_token, [])
1690
1728
  return update_backup_code
1691
1729
 
1692
1730
  async def relogin(self):
@@ -1729,13 +1767,13 @@ class Client(BaseHTTPClient):
1729
1767
 
1730
1768
  url = f"https://twitter.com/i/api/1.1/strato/column/User/{self.account.id}/account-security/twoFactorAuthSettings2"
1731
1769
  response, data = await self.request("GET", url)
1732
- return "Totp" in [
1733
- method_data["twoFactorType"] for method_data in data["methods"]
1734
- ]
1770
+ # fmt: off
1771
+ return "Totp" in [method_data["twoFactorType"] for method_data in data["methods"]]
1772
+ # fmt: on
1735
1773
 
1736
- async def _request_2fa_tasks(self):
1774
+ async def _request_2fa_tasks(self) -> tuple[str, list[Subtask]]:
1737
1775
  """
1738
- :return: flow_token, subtask_ids
1776
+ :return: flow_token, tasks
1739
1777
  """
1740
1778
  query = {
1741
1779
  "flow_name": "two-factor-auth-app-enrollment",
@@ -1791,34 +1829,37 @@ class Client(BaseHTTPClient):
1791
1829
  "web_modal": 1,
1792
1830
  },
1793
1831
  }
1794
- return await self._task(params=query, json=payload)
1832
+ return await self._send_raw_subtask(params=query, json=payload)
1795
1833
 
1796
- async def _two_factor_enrollment_verify_password_subtask(self, flow_token: str):
1797
- subtask_inputs = [
1834
+ async def _two_factor_enrollment_verify_password_subtask(
1835
+ self, flow_token: str
1836
+ ) -> tuple[str, list[Subtask]]:
1837
+ inputs = [
1798
1838
  {
1799
1839
  "subtask_id": "TwoFactorEnrollmentVerifyPasswordSubtask",
1800
1840
  "enter_password": {
1801
- "password": self.account.password,
1802
1841
  "link": "next_link",
1842
+ "password": self.account.password,
1803
1843
  },
1804
1844
  }
1805
1845
  ]
1806
- return await self._send_task(flow_token, subtask_inputs)
1846
+ return await self._complete_subtask(flow_token, inputs)
1807
1847
 
1808
1848
  async def _two_factor_enrollment_authentication_app_begin_subtask(
1809
1849
  self, flow_token: str
1810
- ):
1811
- subtask_inputs = [
1850
+ ) -> tuple[str, list[Subtask]]:
1851
+ inputs = [
1812
1852
  {
1813
1853
  "subtask_id": "TwoFactorEnrollmentAuthenticationAppBeginSubtask",
1814
1854
  "action_list": {"link": "next_link"},
1815
1855
  }
1816
1856
  ]
1817
- return await self._send_task(flow_token, subtask_inputs)
1857
+ return await self._complete_subtask(flow_token, inputs)
1818
1858
 
1819
1859
  async def _two_factor_enrollment_authentication_app_plain_code_subtask(
1820
- self, flow_token: str
1821
- ):
1860
+ self,
1861
+ flow_token: str,
1862
+ ) -> tuple[str, list[Subtask]]:
1822
1863
  subtask_inputs = [
1823
1864
  {
1824
1865
  "subtask_id": "TwoFactorEnrollmentAuthenticationAppPlainCodeSubtask",
@@ -1827,12 +1868,12 @@ class Client(BaseHTTPClient):
1827
1868
  {
1828
1869
  "subtask_id": "TwoFactorEnrollmentAuthenticationAppEnterCodeSubtask",
1829
1870
  "enter_text": {
1830
- "text": self.account.get_totp_code(),
1831
1871
  "link": "next_link",
1872
+ "text": self.account.get_totp_code(),
1832
1873
  },
1833
1874
  },
1834
1875
  ]
1835
- return await self._send_task(flow_token, subtask_inputs)
1876
+ return await self._complete_subtask(flow_token, subtask_inputs)
1836
1877
 
1837
1878
  async def _finish_2fa_task(self, flow_token: str):
1838
1879
  subtask_inputs = [
@@ -1841,52 +1882,38 @@ class Client(BaseHTTPClient):
1841
1882
  "cta": {"link": "finish_link"},
1842
1883
  }
1843
1884
  ]
1844
- return await self._send_task(flow_token, subtask_inputs)
1885
+ await self._complete_subtask(flow_token, subtask_inputs)
1845
1886
 
1846
1887
  async def _enable_totp(self):
1888
+ # fmt: off
1847
1889
  flow_token, subtasks = await self._request_2fa_tasks()
1848
- flow_token, subtasks = (
1849
- await self._two_factor_enrollment_verify_password_subtask(flow_token)
1850
- )
1851
- flow_token, subtasks = (
1852
- await self._two_factor_enrollment_authentication_app_begin_subtask(
1853
- flow_token
1854
- )
1890
+ flow_token, subtasks = await self._two_factor_enrollment_verify_password_subtask(
1891
+ flow_token
1855
1892
  )
1893
+ flow_token, subtasks = (await self._two_factor_enrollment_authentication_app_begin_subtask(flow_token))
1856
1894
 
1857
1895
  for subtask in subtasks:
1858
- if (
1859
- subtask["subtask_id"]
1860
- == "TwoFactorEnrollmentAuthenticationAppPlainCodeSubtask"
1861
- ):
1862
- self.account.totp_secret = subtask["show_code"]["code"]
1896
+ if subtask.id == "TwoFactorEnrollmentAuthenticationAppPlainCodeSubtask":
1897
+ self.account.totp_secret = subtask.raw_data["show_code"]["code"]
1863
1898
  break
1864
1899
 
1865
- flow_token, subtasks = (
1866
- await self._two_factor_enrollment_authentication_app_plain_code_subtask(
1867
- flow_token
1868
- )
1869
- )
1900
+ flow_token, subtasks = await self._two_factor_enrollment_authentication_app_plain_code_subtask(flow_token)
1870
1901
 
1871
1902
  for subtask in subtasks:
1872
- if (
1873
- subtask["subtask_id"]
1874
- == "TwoFactorEnrollmentAuthenticationAppCompleteSubtask"
1875
- ):
1876
- result = re.search(
1877
- r"\n[a-z0-9]{12}\n", subtask["cta"]["secondary_text"]["text"]
1878
- )
1903
+ if subtask.id == "TwoFactorEnrollmentAuthenticationAppCompleteSubtask":
1904
+ result = re.search(r"\n[a-z0-9]{12}\n", subtask.raw_data["cta"]["secondary_text"]["text"])
1879
1905
  backup_code = result[0].strip() if result else None
1880
1906
  self.account.backup_code = backup_code
1881
1907
  break
1882
1908
 
1909
+ # fmt: on
1883
1910
  await self._finish_2fa_task(flow_token)
1884
1911
 
1885
1912
  async def enable_totp(self):
1886
- if not self.account.password:
1887
- raise ValueError("Password is required for this action")
1888
-
1889
1913
  if await self.totp_is_enabled():
1890
1914
  return
1891
1915
 
1916
+ if not self.account.password:
1917
+ raise ValueError("Password required to enable TOTP")
1918
+
1892
1919
  await self._enable_totp()
twitter/models.py CHANGED
@@ -1,4 +1,4 @@
1
- from typing import Optional
1
+ from typing import Optional, Any
2
2
  from datetime import datetime, timedelta
3
3
 
4
4
  from pydantic import BaseModel, Field, field_validator
@@ -153,3 +153,24 @@ class Tweet(BaseModel):
153
153
  "raw_data": data,
154
154
  }
155
155
  return cls(**values)
156
+
157
+
158
+ class Subtask(BaseModel):
159
+ id: str
160
+ primary_text: Optional[str] = None
161
+ secondary_text: Optional[str] = None
162
+ detail_text: Optional[str] = None
163
+ raw_data: dict
164
+
165
+ @classmethod
166
+ def from_raw_data(cls, data: dict) -> "Subtask":
167
+ task = {"id": data["subtask_id"]}
168
+ if enter_text := data.get("enter_text"):
169
+ if header := enter_text.get("header"):
170
+ if primary_text := header.get("primary_text"):
171
+ task["primary_text"] = primary_text["text"]
172
+ if secondary_text := header.get("secondary_text"):
173
+ task["secondary_text"] = secondary_text["text"]
174
+ if detail_text := header.get("detail_text"):
175
+ task["detail_text"] = detail_text["text"]
176
+ return cls(**task, raw_data=data)