pinterest-dl 2.0.3 → 2.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -1
- data/lib/pinterest_dl/api.rb +0 -1
- data/lib/pinterest_dl/board.rb +29 -3
- data/lib/pinterest_dl/client.rb +1 -8
- data/lib/pinterest_dl/extractors/pin_data.rb +3 -0
- data/lib/pinterest_dl/extractors/video.rb +0 -1
- data/lib/pinterest_dl/search.rb +2 -1
- data/lib/pinterest_dl/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ab49a0f8fc2500835b07ec8abf935c4a643d7a9fa8f6e2de9bdb5250f10ef24c
|
|
4
|
+
data.tar.gz: 9fb506ca599f3a1625989ab178c7ed4f0c0e5ddad236f416f514666c90741bf0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e3962e2ea256111c1c9178947a0aa026daec6fed0c1cfefb2f81d92dd77299eebc9c2634f2ecf9e74ede3edfacb327ce28381c9aeffa951f9960c81f8883dddd
|
|
7
|
+
data.tar.gz: '09407f8541a4042be42584393524b8aee0147654d46c0abdc1d0c17ad9467bbaa17406fd260099fe214db43aa946553f20a696524616e66e2817477d6cd897b8'
|
data/CHANGELOG.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
All notable changes to this project are documented here.
|
|
4
4
|
This project follows [Semantic Versioning](https://semver.org/).
|
|
5
5
|
|
|
6
|
-
## [2.0.
|
|
6
|
+
## [2.0.3]
|
|
7
7
|
|
|
8
8
|
### Fixed
|
|
9
9
|
- **`PinterestDL::Board` was broken.** `lib/pinterest_dl/board.rb` accidentally
|
|
@@ -11,6 +11,11 @@ This project follows [Semantic Versioning](https://semver.org/).
|
|
|
11
11
|
search logic), so it silently collided with `PinterestDL::Search` at load
|
|
12
12
|
time and `PinterestDL.board(...)` never worked correctly. Restored the
|
|
13
13
|
correct `Board` class backed by Pinterest's `BoardFeedResource`.
|
|
14
|
+
- `PinterestDL.board` requests were missing a session cookie and CSRF token,
|
|
15
|
+
which Pinterest's internal resource API requires — every board request
|
|
16
|
+
came back as HTTP 403. `Board` now loads the board page first to obtain
|
|
17
|
+
a session cookie + CSRF token before calling the resource API, the same
|
|
18
|
+
way `Search` already did.
|
|
14
19
|
- `pin.it/...` short links were rejected by `get_image_url` / `get_video_url` /
|
|
15
20
|
`get_media` even though Pinterest itself redirects them to a normal pin
|
|
16
21
|
page. `PIN_URL_PATTERN` now accepts `pin.it/...` links too.
|
data/lib/pinterest_dl/api.rb
CHANGED
data/lib/pinterest_dl/board.rb
CHANGED
|
@@ -40,7 +40,13 @@ module PinterestDL
|
|
|
40
40
|
private
|
|
41
41
|
|
|
42
42
|
def fetch_page(match, bookmarks:)
|
|
43
|
-
|
|
43
|
+
session = establish_session(match)
|
|
44
|
+
body = @client.get(
|
|
45
|
+
build_request_url(match, bookmarks),
|
|
46
|
+
use_cache: false,
|
|
47
|
+
headers: board_headers(session)
|
|
48
|
+
)
|
|
49
|
+
|
|
44
50
|
json = safe_parse(body)
|
|
45
51
|
raise PinterestDL::NotFoundError, "Board not found: #{match[0]}" unless json
|
|
46
52
|
|
|
@@ -50,6 +56,20 @@ module PinterestDL
|
|
|
50
56
|
{ pins: Array(data_node).filter_map { |r| build_pin(r) }, bookmarks: Array(next_bookmarks) }
|
|
51
57
|
end
|
|
52
58
|
|
|
59
|
+
def establish_session(match)
|
|
60
|
+
board_path = "/#{match[:username]}/#{match[:slug]}/"
|
|
61
|
+
board_uri = URI("https://www.pinterest.com#{board_path}")
|
|
62
|
+
home_response = @client.raw_get(board_uri.to_s)
|
|
63
|
+
cookies = (home_response.get_fields('set-cookie') || []).map { |c| c.split(';').first }
|
|
64
|
+
|
|
65
|
+
{ board_path: board_path, board_uri: board_uri, cookies: cookies, csrf: csrf_token(cookies) }
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def csrf_token(cookies)
|
|
69
|
+
token_cookie = cookies.find { |c| c.start_with?('csrftoken=') }
|
|
70
|
+
token_cookie ? token_cookie.split('=', 2).last : 'undefined'
|
|
71
|
+
end
|
|
72
|
+
|
|
53
73
|
def build_request_url(match, bookmarks)
|
|
54
74
|
options = {
|
|
55
75
|
board_url: "/#{match[:username]}/#{match[:slug]}/",
|
|
@@ -64,10 +84,16 @@ module PinterestDL
|
|
|
64
84
|
res_uri.to_s
|
|
65
85
|
end
|
|
66
86
|
|
|
67
|
-
def
|
|
87
|
+
def board_headers(session)
|
|
88
|
+
cookie_header = [@config.cookies, session[:cookies].join('; ')].compact.reject(&:empty?).join('; ')
|
|
89
|
+
|
|
68
90
|
{
|
|
69
91
|
'Accept' => 'application/json, text/javascript, */*, q=0.01',
|
|
70
|
-
'X-Requested-With' => 'XMLHttpRequest'
|
|
92
|
+
'X-Requested-With' => 'XMLHttpRequest',
|
|
93
|
+
'X-Pinterest-PWS-Handler' => 'www/[username]/[slug].js',
|
|
94
|
+
'X-CSRFToken' => session[:csrf],
|
|
95
|
+
'Referer' => session[:board_uri].to_s,
|
|
96
|
+
'Cookie' => cookie_header
|
|
71
97
|
}
|
|
72
98
|
end
|
|
73
99
|
|
data/lib/pinterest_dl/client.rb
CHANGED
|
@@ -71,14 +71,7 @@ module PinterestDL
|
|
|
71
71
|
raise PinterestDL::NotFoundError, "Redirected without a location header (#{url})" unless location
|
|
72
72
|
|
|
73
73
|
location = URI.join(url, location).to_s if location.start_with?('/')
|
|
74
|
-
|
|
75
|
-
uri = URI(location)
|
|
76
|
-
if uri.host&.match?(/^(?:www\.)?pinterest\.(?!com$)[a-z.]+$/i) || uri.host == 'pin.it'
|
|
77
|
-
uri.host = 'www.pinterest.com'
|
|
78
|
-
location = uri.to_s
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
get_or_raw(location, raw: raw)
|
|
74
|
+
get_or_raw(location, raw: raw)
|
|
82
75
|
when Net::HTTPForbidden
|
|
83
76
|
raise PinterestDL::RateLimitError, "Request to #{url} was blocked (HTTP 403)"
|
|
84
77
|
else
|
|
@@ -6,13 +6,16 @@ module PinterestDL
|
|
|
6
6
|
module Extractors
|
|
7
7
|
module PinData
|
|
8
8
|
SCRIPT_PATTERN = %r{<script[^>]*id=["']__PWS_DATA__["'][^>]*>(.*?)</script>}m.freeze
|
|
9
|
+
|
|
9
10
|
module_function
|
|
11
|
+
|
|
10
12
|
def extract(html)
|
|
11
13
|
data = parse_embedded_json(html)
|
|
12
14
|
return nil unless data
|
|
13
15
|
|
|
14
16
|
pin = find_pin_node(data)
|
|
15
17
|
return nil unless pin
|
|
18
|
+
|
|
16
19
|
{
|
|
17
20
|
image_url: pin.dig('images', 'orig', 'url'),
|
|
18
21
|
video_url: first_video_url(pin),
|
data/lib/pinterest_dl/search.rb
CHANGED
|
@@ -50,7 +50,8 @@ module PinterestDL
|
|
|
50
50
|
parse_search_response(json)
|
|
51
51
|
end
|
|
52
52
|
|
|
53
|
-
|
|
53
|
+
# Pinterest's search resource requires a session cookie + CSRF token
|
|
54
|
+
# obtained by first loading the human-facing search page.
|
|
54
55
|
def establish_session(query)
|
|
55
56
|
source_path = "/search/pins/?q=#{URI.encode_www_form_component(query)}"
|
|
56
57
|
home_uri = URI("https://www.pinterest.com#{source_path}")
|
data/lib/pinterest_dl/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: pinterest-dl
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.0.
|
|
4
|
+
version: 2.0.4
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Monji
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-08-
|
|
11
|
+
date: 2026-08-30 00:00:00.000000000 Z
|
|
12
12
|
dependencies: []
|
|
13
13
|
description: A Ruby toolkit for getting direct image and video URLs from Pinterest
|
|
14
14
|
pins, searching pins, fetching board contents, and downloading media to disk — as
|