diff options
Diffstat (limited to 'gallery_dl/extractor/pinterest.py')
| -rw-r--r-- | gallery_dl/extractor/pinterest.py | 88 |
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} |
