pinterest-dl 1.0.3 → 2.0.0

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.
@@ -0,0 +1,142 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+ require 'net/http'
5
+ require 'uri'
6
+
7
+ module PinterestDL
8
+ class Search
9
+ RESOURCE_URL = 'https://www.pinterest.com/resource/BaseSearchResource/get/'
10
+
11
+ def initialize(client: PinterestDL::Client.new, config: PinterestDL.config)
12
+ @client = client
13
+ @config = config
14
+ end
15
+
16
+ def call(query, limit: 25, pages: 5)
17
+ results = []
18
+ bookmarks = nil
19
+ pages_fetched = 0
20
+
21
+ loop do
22
+ page = fetch_page(query, bookmarks: bookmarks)
23
+ pins = page[:pins]
24
+ results.concat(pins)
25
+ bookmarks = page[:bookmarks]
26
+ pages_fetched += 1
27
+
28
+ break if results.size >= limit
29
+ break if bookmarks.nil? || bookmarks.empty? || bookmarks == ['-end-']
30
+ break if pages_fetched >= pages
31
+ break if pins.empty?
32
+ end
33
+
34
+ results.first(limit)
35
+ end
36
+
37
+ private
38
+
39
+ def fetch_page(query, bookmarks: nil)
40
+ session = establish_session(query)
41
+ body = @client.get(
42
+ build_search_url(session[:source_path], query, bookmarks),
43
+ use_cache: false,
44
+ headers: search_headers(session)
45
+ )
46
+
47
+ json = safe_parse(body)
48
+ raise PinterestDL::NotFoundError, "No search results for \"#{query}\"" unless json
49
+
50
+ parse_search_response(json)
51
+ end
52
+
53
+ def establish_session(query)
54
+ source_path = "/search/pins/?q=#{URI.encode_www_form_component(query)}"
55
+ home_uri = URI("https://www.pinterest.com#{source_path}")
56
+ home_response = @client.raw_get(home_uri.to_s)
57
+ cookies = (home_response.get_fields('set-cookie') || []).map { |c| c.split(';').first }
58
+
59
+ { source_path: source_path, home_uri: home_uri, cookies: cookies, csrf: csrf_token(cookies) }
60
+ end
61
+
62
+ def csrf_token(cookies)
63
+ token_cookie = cookies.find { |c| c.start_with?('csrftoken=') }
64
+ token_cookie ? token_cookie.split('=', 2).last : 'undefined'
65
+ end
66
+
67
+ def build_search_url(source_path, query, bookmarks)
68
+ options = { query: query, scope: 'pins', page_size: 25 }
69
+ options[:bookmarks] = bookmarks if bookmarks && !bookmarks.empty?
70
+ data = { options: options, context: {} }.to_json
71
+
72
+ res_uri = URI(RESOURCE_URL)
73
+ res_uri.query = URI.encode_www_form('source_url' => source_path, 'data' => data)
74
+ res_uri.to_s
75
+ end
76
+
77
+ def search_headers(session)
78
+ cookie_header = [@config.cookies, session[:cookies].join('; ')].compact.reject(&:empty?).join('; ')
79
+
80
+ {
81
+ 'Accept' => 'application/json, text/javascript, */*, q=0.01',
82
+ 'X-Requested-With' => 'XMLHttpRequest',
83
+ 'X-Pinterest-PWS-Handler' => 'www/search/[scope].js',
84
+ 'X-CSRFToken' => session[:csrf],
85
+ 'Referer' => session[:home_uri].to_s,
86
+ 'Cookie' => cookie_header
87
+ }
88
+ end
89
+
90
+ def parse_search_response(json)
91
+ data_node = json.dig('resource_response', 'data') || {}
92
+ raw_results = data_node['results'] || []
93
+ next_bookmarks = json.dig('resource_response', 'bookmark') ||
94
+ json.dig('resource', 'options', 'bookmarks')
95
+
96
+ { pins: raw_results.filter_map { |r| build_pin(r) }, bookmarks: Array(next_bookmarks) }
97
+ end
98
+
99
+ def build_pin(raw)
100
+ id = raw['id']
101
+ return nil unless id
102
+
103
+ {
104
+ id: id,
105
+ pin_url: "https://www.pinterest.com/pin/#{id}/",
106
+ title: raw['title'] || raw['grid_title'],
107
+ description: raw['description'],
108
+ creator: pin_creator(raw),
109
+ image_url: pin_image_url(raw),
110
+ video_url: first_video_url(raw)
111
+ }
112
+ end
113
+
114
+ def pin_creator(raw)
115
+ raw.dig('pinner', 'username') || raw.dig('pinner', 'full_name')
116
+ end
117
+
118
+ def pin_image_url(raw)
119
+ raw.dig('images', 'orig', 'url') || fallback_image_url(raw)
120
+ end
121
+
122
+ def fallback_image_url(raw)
123
+ images = raw['images']
124
+ return nil unless images
125
+
126
+ images.values.filter_map { |v| v['url'] if v.is_a?(Hash) }.last
127
+ end
128
+
129
+ def first_video_url(raw)
130
+ video_list = raw.dig('videos', 'video_list')
131
+ return nil unless video_list
132
+
133
+ video_list.values.first&.dig('url')
134
+ end
135
+
136
+ def safe_parse(body)
137
+ JSON.parse(body)
138
+ rescue JSON::ParserError, TypeError
139
+ nil
140
+ end
141
+ end
142
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Monji024
4
+ module PinterestDL
5
+ VERSION = '2.0.0'
6
+ end
metadata CHANGED
@@ -1,28 +1,50 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pinterest-dl
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.3
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Monji
8
+ autorequire:
8
9
  bindir: bin
9
10
  cert_chain: []
10
- date: 2026-07-28 00:00:00.000000000 Z
11
+ date: 2026-08-28 00:00:00.000000000 Z
11
12
  dependencies: []
12
- description: Simple Pinterest Downloader Tool:)
13
+ description: A Ruby toolkit for getting direct image and video URLs from Pinterest
14
+ pins, searching pins, fetching board contents, and downloading media to disk — as
15
+ a library or a CLI.
13
16
  email: hoseinmonjiofficial@gmail.com
14
- executables: []
17
+ executables:
18
+ - pinterest-dl
15
19
  extensions: []
16
20
  extra_rdoc_files: []
17
21
  files:
22
+ - CHANGELOG.md
23
+ - LICENSE
18
24
  - README.md
25
+ - bin/pinterest-dl
19
26
  - lib/pinterest-dl.rb
27
+ - lib/pinterest_dl/api.rb
28
+ - lib/pinterest_dl/board.rb
29
+ - lib/pinterest_dl/client.rb
30
+ - lib/pinterest_dl/configuration.rb
31
+ - lib/pinterest_dl/downloader.rb
32
+ - lib/pinterest_dl/errors.rb
33
+ - lib/pinterest_dl/extractors/image.rb
34
+ - lib/pinterest_dl/extractors/video.rb
35
+ - lib/pinterest_dl/progress_bar.rb
36
+ - lib/pinterest_dl/search.rb
37
+ - lib/pinterest_dl/version.rb
20
38
  homepage: https://github.com/monji024/pinterest-dl
21
39
  licenses:
22
- - MIT
40
+ - WTFPL
23
41
  metadata:
24
42
  source_code_uri: https://github.com/monji024/pinterest-dl
25
43
  bug_tracker_uri: https://github.com/monji024/pinterest-dl/issues
44
+ changelog_uri: https://github.com/monji024/pinterest-dl/blob/main/CHANGELOG.md
45
+ rubygems_mfa_required: 'true'
46
+ documentation_uri: https://rubydoc.info/gems/pinterest-dl
47
+ post_install_message:
26
48
  rdoc_options: []
27
49
  require_paths:
28
50
  - lib
@@ -30,14 +52,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
30
52
  requirements:
31
53
  - - ">="
32
54
  - !ruby/object:Gem::Version
33
- version: 2.5.0
55
+ version: 2.7.0
34
56
  required_rubygems_version: !ruby/object:Gem::Requirement
35
57
  requirements:
36
58
  - - ">="
37
59
  - !ruby/object:Gem::Version
38
60
  version: '0'
39
61
  requirements: []
40
- rubygems_version: 3.6.3
62
+ rubygems_version: 3.3.15
63
+ signing_key:
41
64
  specification_version: 4
42
- summary: Extract direct image/video/search URLs from Pinterest!!!
65
+ summary: Extract direct image/video URLs, search, and download from Pinterest
43
66
  test_files: []