[pinterest] improve PinterestAPI code; remove OAuth mentions
on another note: access_tokens have been set to only allow for 10 requests per hour (from 200 yesterday)
This commit is contained in:
@@ -194,7 +194,7 @@ OAuth
|
|||||||
-----
|
-----
|
||||||
|
|
||||||
*gallery-dl* supports user authentication via OAuth_ for
|
*gallery-dl* supports user authentication via OAuth_ for
|
||||||
``deviantart``, ``flickr``, ``pinterest``, ``reddit`` and ``tumblr``.
|
``deviantart``, ``flickr``, ``reddit`` and ``tumblr``.
|
||||||
This is entirely optional, but grants *gallery-dl* the ability
|
This is entirely optional, but grants *gallery-dl* the ability
|
||||||
to issue requests on your account's behalf and enables it to access resources
|
to issue requests on your account's behalf and enables it to access resources
|
||||||
which would otherwise be unavailable to a public user.
|
which would otherwise be unavailable to a public user.
|
||||||
|
|||||||
@@ -820,13 +820,26 @@ How To
|
|||||||
=========== =====
|
=========== =====
|
||||||
|
|
||||||
|
|
||||||
|
extractor.pinterest.access-token
|
||||||
|
--------------------------------
|
||||||
|
=========== =====
|
||||||
|
Type ``string``
|
||||||
|
How To - register a Pinterest application and use its client-id and
|
||||||
|
client-secret (see `extractor.pinterest.client-id & .secret`_)
|
||||||
|
- run `gallery-dl oauth:pinterest` and authenticate access with
|
||||||
|
(preferably) the same account that registered the application
|
||||||
|
Notes Access tokens currently only allow for 10 requests per hour.
|
||||||
|
=========== =====
|
||||||
|
|
||||||
|
|
||||||
extractor.pinterest.client-id & .secret
|
extractor.pinterest.client-id & .secret
|
||||||
---------------------------------------
|
---------------------------------------
|
||||||
=========== =====
|
=========== =====
|
||||||
Type ``string``
|
Type ``string``
|
||||||
How To - login and visit Pinterest's
|
How To - login and visit Pinterest's
|
||||||
`Apps <https://developers.pinterest.com/apps/>`__ section
|
`Apps <https://developers.pinterest.com/apps/>`__ section
|
||||||
- click "Create app"
|
- agree to "Pinterest Developer Terms and the API Policy"
|
||||||
|
and click "Create app"
|
||||||
- choose a random name and description and click "Create"
|
- choose a random name and description and click "Create"
|
||||||
- scroll down and set a Site URL (e.g. https://example.org/)
|
- scroll down and set a Site URL (e.g. https://example.org/)
|
||||||
and allow https://mikf.github.io/gallery-dl/oauth-redirect.html
|
and allow https://mikf.github.io/gallery-dl/oauth-redirect.html
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ Niconico Seiga http://seiga.nicovideo.jp Images from Users, indi
|
|||||||
nijie https://nijie.info/ |Images from Use-3| Required
|
nijie https://nijie.info/ |Images from Use-3| Required
|
||||||
Nyafuu Archive https://archive.nyafuu.org/ Threads
|
Nyafuu Archive https://archive.nyafuu.org/ Threads
|
||||||
Pawoo https://pawoo.net Images from Users, Images from Statuses
|
Pawoo https://pawoo.net Images from Users, Images from Statuses
|
||||||
Pinterest https://www.pinterest.com Boards, Pins, pin.it Links Optional (OAuth)
|
Pinterest https://www.pinterest.com Boards, Pins, pin.it Links
|
||||||
Pixiv https://www.pixiv.net/ |Images from Use-4| Required
|
Pixiv https://www.pixiv.net/ |Images from Use-4| Required
|
||||||
PowerManga https://powermanga.org/ Chapters, Manga
|
PowerManga https://powermanga.org/ Chapters, Manga
|
||||||
Pure Mashiro http://reader.puremashiro.moe/ Chapters, Manga
|
Pure Mashiro http://reader.puremashiro.moe/ Chapters, Manga
|
||||||
|
|||||||
@@ -48,6 +48,9 @@ class PinterestPinExtractor(PinterestExtractor):
|
|||||||
("https://www.pinterest.com/pin/858146903966145188/", {
|
("https://www.pinterest.com/pin/858146903966145188/", {
|
||||||
"exception": exception.StopExtraction,
|
"exception": exception.StopExtraction,
|
||||||
}),
|
}),
|
||||||
|
("https://www.pinterest.com/pin/85814690396614518/", {
|
||||||
|
"exception": exception.NotFoundError,
|
||||||
|
}),
|
||||||
]
|
]
|
||||||
|
|
||||||
def __init__(self, match):
|
def __init__(self, match):
|
||||||
@@ -134,59 +137,58 @@ class PinterestPinitExtractor(PinterestExtractor):
|
|||||||
|
|
||||||
class PinterestAPI():
|
class PinterestAPI():
|
||||||
"""Minimal interface for the pinterest API"""
|
"""Minimal interface for the pinterest API"""
|
||||||
CLIENT_ID = "4959725425749142746"
|
|
||||||
CLIENT_SECRET = ("2ea77dc64ca02974a728e46c5a9d2adf"
|
|
||||||
"cdd42f4d4ffb40ad064072165ad4b10d")
|
|
||||||
|
|
||||||
def __init__(self, extractor, access_token="AfyIXxi1MJ6et0NlIl_vBchHbex-"
|
def __init__(self, extractor, access_token=None):
|
||||||
"FSWylPyr2GJE2uu3W8A97QAAAAA"):
|
|
||||||
access_token = extractor.config("access-token", access_token)
|
|
||||||
self.session = extractor.session
|
|
||||||
self.session.params["access_token"] = access_token
|
|
||||||
self.log = extractor.log
|
self.log = extractor.log
|
||||||
|
self.session = extractor.session
|
||||||
|
self.access_token = (
|
||||||
|
access_token or
|
||||||
|
extractor.config("access-token") or
|
||||||
|
"AfyIXxi1MJ6et0NlIl_vBchHbex-FSWylPyr2GJE2uu3W8A97QAAAAA"
|
||||||
|
)
|
||||||
|
|
||||||
def pin(self, pin_id, fields="id,image,note"):
|
def pin(self, pin_id, fields="id,image,note"):
|
||||||
"""Query information about a pin"""
|
"""Query information about a pin"""
|
||||||
|
endpoint = "pins/{}/".format(pin_id)
|
||||||
params = {"fields": fields}
|
params = {"fields": fields}
|
||||||
response = self.session.get(
|
return self._call(endpoint, params)["data"]
|
||||||
"https://api.pinterest.com/v1/pins/{pin}/".format(pin=pin_id),
|
|
||||||
params=params
|
|
||||||
)
|
|
||||||
return self._parse(response)["data"]
|
|
||||||
|
|
||||||
def board(self, user, board, fields="id,name,counts"):
|
def board(self, user, board, fields="id,name,counts"):
|
||||||
"""Query information about a board"""
|
"""Query information about a board"""
|
||||||
|
endpoint = "boards/{}/{}/".format(user, board)
|
||||||
params = {"fields": fields}
|
params = {"fields": fields}
|
||||||
response = self.session.get(
|
return self._call(endpoint, params)["data"]
|
||||||
"https://api.pinterest.com/v1/boards/{user}/{board}/"
|
|
||||||
.format(user=user, board=board), params=params
|
|
||||||
)
|
|
||||||
return self._parse(response)["data"]
|
|
||||||
|
|
||||||
def board_pins(self, user, board, fields="id,image,note"):
|
def board_pins(self, user, board, fields="id,image,note", limit=100):
|
||||||
"""Yield all pins of a specific board"""
|
"""Yield all pins of a specific board"""
|
||||||
params = {"fields": fields, "limit": 100}
|
endpoint = "boards/{}/{}/pins/".format(user, board)
|
||||||
url = ("https://api.pinterest.com/v1/boards/{user}/{board}/pins/"
|
params = {"fields": fields, "limit": limit}
|
||||||
.format(user=user, board=board))
|
return self._pagination(endpoint, params)
|
||||||
|
|
||||||
|
def _call(self, endpoint, params):
|
||||||
|
params["access_token"] = self.access_token
|
||||||
|
url = "https://api.pinterest.com/v1/" + endpoint
|
||||||
|
|
||||||
|
response = self.session.get(url, params=params)
|
||||||
|
status = response.status_code
|
||||||
|
data = response.json()
|
||||||
|
|
||||||
|
if 200 <= status < 400 and data.get("data"):
|
||||||
|
return data
|
||||||
|
|
||||||
|
msg = data.get("message", "")
|
||||||
|
if status == 404:
|
||||||
|
msg = msg.partition(" ")[0].lower()
|
||||||
|
raise exception.NotFoundError(msg)
|
||||||
|
self.log.error("API request failed: %s", msg or "")
|
||||||
|
raise exception.StopExtraction()
|
||||||
|
|
||||||
|
def _pagination(self, endpoint, params):
|
||||||
while True:
|
while True:
|
||||||
response = self._parse(self.session.get(url, params=params))
|
response = self._call(endpoint, params)
|
||||||
yield from response["data"]
|
yield from response["data"]
|
||||||
|
|
||||||
cursor = response["page"]["cursor"]
|
cursor = response["page"]["cursor"]
|
||||||
if not cursor:
|
if not cursor:
|
||||||
return
|
return
|
||||||
params["cursor"] = cursor
|
params["cursor"] = cursor
|
||||||
|
|
||||||
def _parse(self, response):
|
|
||||||
"""Parse an API response"""
|
|
||||||
data = response.json()
|
|
||||||
if 200 <= response.status_code < 400 and data.get("data"):
|
|
||||||
return data
|
|
||||||
|
|
||||||
msg = data.get("message")
|
|
||||||
if response.status_code == 404:
|
|
||||||
msg = msg.partition(" ")[0].lower()
|
|
||||||
raise exception.NotFoundError(msg)
|
|
||||||
else:
|
|
||||||
self.log.error("API request failed: %s", msg or "")
|
|
||||||
raise exception.StopExtraction()
|
|
||||||
|
|||||||
@@ -88,7 +88,6 @@ AUTH_MAP = {
|
|||||||
"flickr" : "Optional (OAuth)",
|
"flickr" : "Optional (OAuth)",
|
||||||
"idolcomplex": "Optional",
|
"idolcomplex": "Optional",
|
||||||
"nijie" : "Required",
|
"nijie" : "Required",
|
||||||
"pinterest" : "Optional (OAuth)",
|
|
||||||
"pixiv" : "Required",
|
"pixiv" : "Required",
|
||||||
"reddit" : "Optional (OAuth)",
|
"reddit" : "Optional (OAuth)",
|
||||||
"sankaku" : "Optional",
|
"sankaku" : "Optional",
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ TRAVIS_SKIP = {
|
|||||||
# temporary issues, etc.
|
# temporary issues, etc.
|
||||||
BROKEN = {
|
BROKEN = {
|
||||||
"luscious", # layout change
|
"luscious", # layout change
|
||||||
|
"pinterest", # access tokens have been set to 10 requests per hour
|
||||||
"puremashiro", # online reader down
|
"puremashiro", # online reader down
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,8 +41,6 @@ class TestExtractorResults(unittest.TestCase):
|
|||||||
config.set(("extractor", "deviantart", "client-id"), "7777")
|
config.set(("extractor", "deviantart", "client-id"), "7777")
|
||||||
config.set(("extractor", "deviantart", "client-secret"),
|
config.set(("extractor", "deviantart", "client-secret"),
|
||||||
"ff14994c744d9208e5caeec7aab4a026")
|
"ff14994c744d9208e5caeec7aab4a026")
|
||||||
config.set(("extractor", "pinterest", "access-token"),
|
|
||||||
"Ab1gUJFF5TFoWXRbX0p7_ue7jOHeFSX8iOrCIOZE24bOp0A6TQAAAAA")
|
|
||||||
config.set(("extractor", "tumblr", "api-key"),
|
config.set(("extractor", "tumblr", "api-key"),
|
||||||
"0cXoHfIqVzMQcc3HESZSNsVlulGxEXGDTTZCDrRrjaa0jmuTc6")
|
"0cXoHfIqVzMQcc3HESZSNsVlulGxEXGDTTZCDrRrjaa0jmuTc6")
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user