summaryrefslogtreecommitdiffstats
path: root/gallery_dl/extractor/twitter.py
diff options
context:
space:
mode:
Diffstat (limited to 'gallery_dl/extractor/twitter.py')
-rw-r--r--gallery_dl/extractor/twitter.py89
1 files changed, 63 insertions, 26 deletions
diff --git a/gallery_dl/extractor/twitter.py b/gallery_dl/extractor/twitter.py
index f924292..f459fba 100644
--- a/gallery_dl/extractor/twitter.py
+++ b/gallery_dl/extractor/twitter.py
@@ -168,6 +168,11 @@ class TwitterExtractor(Extractor):
if key in bvals:
value = bvals[key].get("image_value")
if value and "url" in value:
+ base, sep, size = value["url"].rpartition("&name=")
+ if sep:
+ base += sep
+ value["url"] = base + self._size_image
+ value["_fallback"] = self._image_fallback(base)
files.append(value)
return
elif name == "unified_card":
@@ -759,7 +764,10 @@ class TwitterAPI():
"__fs_interactive_text": False,
"__fs_dont_mention_me_view_api_enabled": False,
}
+
+ self._log_warnings = extractor.config("warnings")
self._json_dumps = json.JSONEncoder(separators=(",", ":")).encode
+ self._user = None
cookies = extractor.session.cookies
cookiedomain = extractor.cookiedomain
@@ -898,6 +906,15 @@ class TwitterAPI():
}
return self._pagination_users(endpoint, variables)
+ def user_by_rest_id(self, rest_id):
+ endpoint = "/graphql/I5nvpI91ljifos1Y3Lltyg/UserByRestId"
+ params = {"variables": self._json_dumps({
+ "userId": rest_id,
+ "withSafetyModeUserFields": True,
+ "withSuperFollowsUserFields": True,
+ })}
+ return self._call(endpoint, params)["data"]["user"]["result"]
+
def user_by_screen_name(self, screen_name):
endpoint = "/graphql/7mjxD3-C6BxitPMVQ6w0-Q/UserByScreenName"
params = {"variables": self._json_dumps({
@@ -909,11 +926,12 @@ class TwitterAPI():
def _user_id_by_screen_name(self, screen_name):
if screen_name.startswith("id:"):
+ self._user = util.SENTINEL
return screen_name[3:]
user = ()
try:
- user = self.user_by_screen_name(screen_name)
+ user = self._user = self.user_by_screen_name(screen_name)
return user["rest_id"]
except KeyError:
if "unavailable_message" in user:
@@ -929,7 +947,7 @@ class TwitterAPI():
endpoint = "/1.1/guest/activate.json"
return str(self._call(endpoint, None, root, "POST")["guest_token"])
- def _call(self, endpoint, params, root=None, method="GET", warning=True):
+ def _call(self, endpoint, params, root=None, method="GET"):
if root is None:
root = self.root
@@ -954,7 +972,7 @@ class TwitterAPI():
if response.status_code < 400:
# success
- if errors and warning:
+ if errors and self._log_warnings:
self.extractor.log.warning(errors)
return data
@@ -965,22 +983,6 @@ class TwitterAPI():
self.extractor.wait(until=until, seconds=seconds)
continue
- if response.status_code == 401 and \
- "have been blocked from viewing" in errors:
- # account blocked
- extr = self.extractor
- if self.headers["x-twitter-auth-type"] and \
- extr.config("logout"):
- guest_token = self._guest_token()
- extr.session.cookies.set(
- "gt", guest_token, domain=extr.cookiedomain)
- extr._cookiefile = None
- del extr.session.cookies["auth_token"]
- self.headers["x-guest-token"] = guest_token
- self.headers["x-twitter-auth-type"] = None
- extr.log.info("Retrying API request as guest")
- continue
-
# error
raise exception.StopExtraction(
"%s %s (%s)", response.status_code, response.reason, errors)
@@ -1070,9 +1072,10 @@ class TwitterAPI():
params["cursor"] = cursor
def _pagination_tweets(self, endpoint, variables, path=None):
+ extr = self.extractor
variables.update(self.variables)
- original_retweets = (self.extractor.retweets == "original")
- pinned_tweet = self.extractor.pinned
+ original_retweets = (extr.retweets == "original")
+ pinned_tweet = extr.pinned
while True:
params = {"variables": self._json_dumps(variables)}
@@ -1083,13 +1086,47 @@ class TwitterAPI():
instructions = (data["user"]["result"]["timeline"]
["timeline"]["instructions"])
else:
+ instructions = data
for key in path:
- data = data[key]
- instructions = data["instructions"]
+ instructions = instructions[key]
+ instructions = instructions["instructions"]
entries = instructions[0]["entries"]
except (KeyError, IndexError):
- return
+ extr.log.debug(data)
+
+ if self._user:
+ user = self._user
+ if user is util.SENTINEL:
+ try:
+ user = self.user_by_rest_id(variables["userId"])
+ except KeyError:
+ raise exception.NotFoundError("user")
+ user = user.get("legacy")
+ if not user:
+ pass
+ elif user.get("blocked_by"):
+ if self.headers["x-twitter-auth-type"] and \
+ extr.config("logout"):
+ guest_token = self._guest_token()
+ extr.session.cookies.set(
+ "gt", guest_token, domain=extr.cookiedomain)
+ extr._cookiefile = None
+ del extr.session.cookies["auth_token"]
+ self.headers["x-guest-token"] = guest_token
+ self.headers["x-twitter-auth-type"] = None
+ extr.log.info("Retrying API request as guest")
+ continue
+ raise exception.AuthorizationError(
+ "{} blocked your account".format(
+ user["screen_name"]))
+ elif user.get("protected"):
+ raise exception.AuthorizationError(
+ "{}'s Tweets are protected".format(
+ user["screen_name"]))
+
+ raise exception.StopExtraction(
+ "Unable to retrieve Tweets from this timeline")
tweets = []
tweet = cursor = None
@@ -1121,7 +1158,7 @@ class TwitterAPI():
["itemContent"]["tweet_results"]["result"])
legacy = tweet["legacy"]
except KeyError:
- self.extractor.log.debug(
+ extr.log.debug(
"Skipping %s (deleted)",
(entry.get("entryId") or "").rpartition("-")[2])
continue
@@ -1160,7 +1197,7 @@ class TwitterAPI():
quoted["legacy"]["quoted_by_id_str"] = tweet["rest_id"]
yield quoted
except KeyError:
- self.extractor.log.debug(
+ extr.log.debug(
"Skipping quote of %s (deleted)",
tweet.get("rest_id"))
continue