summaryrefslogtreecommitdiffstats
path: root/gallery_dl/extractor/pinterest.py
diff options
context:
space:
mode:
Diffstat (limited to 'gallery_dl/extractor/pinterest.py')
-rw-r--r--gallery_dl/extractor/pinterest.py88
1 files changed, 73 insertions, 15 deletions
diff --git a/gallery_dl/extractor/pinterest.py b/gallery_dl/extractor/pinterest.py
index 24a0a55..3bbe06a 100644
--- a/gallery_dl/extractor/pinterest.py
+++ b/gallery_dl/extractor/pinterest.py
@@ -1,15 +1,16 @@
# -*- coding: utf-8 -*-
-# Copyright 2016-2019 Mike Fährmann
+# Copyright 2016-2020 Mike Fährmann
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 as
# published by the Free Software Foundation.
-"""Extract images from https://www.pinterest.com/"""
+"""Extractors for https://www.pinterest.com/"""
from .common import Extractor, Message
from .. import text, exception
+import itertools
import json
@@ -86,12 +87,17 @@ class PinterestBoardExtractor(PinterestExtractor):
subcategory = "board"
directory_fmt = ("{category}", "{board[owner][username]}", "{board[name]}")
archive_fmt = "{board[id]}_{id}"
- pattern = BASE_PATTERN + r"/(?!pin/)([^/?#&]+)/([^/?#&]+)(?!.*#related$)"
+ pattern = BASE_PATTERN + r"/(?!pin/)([^/?#&]+)/([^/?#&]+)/?$"
test = (
("https://www.pinterest.com/g1952849/test-/", {
"pattern": r"https://i\.pinimg\.com/originals/",
"count": 2,
}),
+ # board with sections (#835)
+ ("https://www.pinterest.com/g1952849/stuff/", {
+ "options": (("sections", True),),
+ "count": 5,
+ }),
("https://www.pinterest.com/g1952848/test/", {
"exception": exception.GalleryDLException,
}),
@@ -100,16 +106,51 @@ class PinterestBoardExtractor(PinterestExtractor):
def __init__(self, match):
PinterestExtractor.__init__(self, match)
self.user = text.unquote(match.group(1))
- self.board = text.unquote(match.group(2))
- self.board_id = 0
+ self.board_name = text.unquote(match.group(2))
+ self.board = None
def metadata(self):
- board = self.api.board(self.user, self.board)
- self.board_id = board["id"]
- return {"board": board}
+ self.board = self.api.board(self.user, self.board_name)
+ return {"board": self.board}
def pins(self):
- return self.api.board_pins(self.board_id)
+ board = self.board
+
+ if board["section_count"] and self.config("sections", True):
+ pins = [self.api.board_pins(board["id"])]
+ for section in self.api.board_sections(board["id"]):
+ pins.append(self.api.board_section_pins(section["id"]))
+ return itertools.chain.from_iterable(pins)
+ else:
+ return self.api.board_pins(board["id"])
+
+
+class PinterestSectionExtractor(PinterestExtractor):
+ """Extractor for board sections on pinterest.com"""
+ subcategory = "section"
+ directory_fmt = ("{category}", "{board[owner][username]}",
+ "{board[name]}", "{section[title]}")
+ archive_fmt = "{board[id]}_{id}"
+ pattern = BASE_PATTERN + r"/(?!pin/)([^/?#&]+)/([^/?#&]+)/([^/?#&]+)"
+ test = ("https://www.pinterest.com/g1952849/stuff/section", {
+ "count": 2,
+ })
+
+ def __init__(self, match):
+ PinterestExtractor.__init__(self, match)
+ self.user = text.unquote(match.group(1))
+ self.board_slug = text.unquote(match.group(2))
+ self.section_slug = text.unquote(match.group(3))
+ self.section = None
+
+ def metadata(self):
+ section = self.section = self.api.board_section(
+ self.user, self.board_slug, self.section_slug)
+ section.pop("preview_pins", None)
+ return {"board": section.pop("board"), "section": section}
+
+ def pins(self):
+ return self.api.board_section_pins(self.section["id"])
class PinterestRelatedPinExtractor(PinterestPinExtractor):
@@ -136,7 +177,7 @@ class PinterestRelatedBoardExtractor(PinterestBoardExtractor):
subcategory = "related-board"
directory_fmt = ("{category}", "{board[owner][username]}",
"{board[name]}", "related")
- pattern = BASE_PATTERN + r"/(?!pin/)([^/?#&]+)/([^/?#&]+).*#related$"
+ pattern = BASE_PATTERN + r"/(?!pin/)([^/?#&]+)/([^/?#&]+)/?#related$"
test = ("https://www.pinterest.com/g1952849/test-/#related", {
"range": "31-70",
"count": 40,
@@ -144,7 +185,7 @@ class PinterestRelatedBoardExtractor(PinterestBoardExtractor):
})
def pins(self):
- return self.api.board_related(self.board_id)
+ return self.api.board_related(self.board["id"])
class PinterestPinitExtractor(PinterestExtractor):
@@ -188,9 +229,10 @@ class PinterestAPI():
"*/*, q=0.01",
"Accept-Language" : "en-US,en;q=0.5",
"X-Pinterest-AppState": "active",
- "X-APP-VERSION" : "cb1c7f9",
+ "X-APP-VERSION" : "b00dd49",
"X-Requested-With" : "XMLHttpRequest",
- "Origin" : BASE_URL + "/",
+ "Origin" : BASE_URL,
+ "Referer" : BASE_URL + "/",
}
def __init__(self, extractor):
@@ -206,9 +248,9 @@ class PinterestAPI():
options = {"pin": pin_id, "add_vase": True, "pins_only": True}
return self._pagination("RelatedPinFeed", options)
- def board(self, user, board):
+ def board(self, user, board_name):
"""Query information about a board"""
- options = {"slug": board, "username": user,
+ options = {"slug": board_name, "username": user,
"field_set_key": "detailed"}
return self._call("Board", options)["resource_response"]["data"]
@@ -217,6 +259,22 @@ class PinterestAPI():
options = {"board_id": board_id}
return self._pagination("BoardFeed", options)
+ def board_section(self, user, board_slug, section_slug):
+ """Yield a specific board section"""
+ options = {"board_slug": board_slug, "section_slug": section_slug,
+ "username": user}
+ return self._call("BoardSection", options)["resource_response"]["data"]
+
+ def board_sections(self, board_id):
+ """Yield all sections of a specific board"""
+ options = {"board_id": board_id}
+ return self._pagination("BoardSections", options)
+
+ def board_section_pins(self, section_id):
+ """Yield all pins from a board section"""
+ options = {"section_id": section_id}
+ return self._pagination("BoardSectionPins", options)
+
def board_related(self, board_id):
"""Yield related pins of a specific board"""
options = {"board_id": board_id, "add_vase": True}