Module: PinterestDL::Extractors::PinData

Defined in:
lib/pinterest_dl/extractors/pin_data.rb

Constant Summary collapse

SCRIPT_PATTERN =
%r{<script[^>]*id=["']__PWS_DATA__["'][^>]*>(.*?)</script>}m.freeze

Class Method Summary collapse

Class Method Details

.extract(html) ⇒ Object



10
11
12
13
14
15
16
17
18
19
20
21
22
# File 'lib/pinterest_dl/extractors/pin_data.rb', line 10

def extract(html)
  data = parse_embedded_json(html)
  return nil unless data

  pin = find_pin_node(data)
  return nil unless pin
  {
    image_url: pin.dig('images', 'orig', 'url'),
    video_url: first_video_url(pin),
    title: pin['title'] || pin['grid_title'],
    description: pin['description']
  }
end

.find_pin_node(data) ⇒ Object



32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/pinterest_dl/extractors/pin_data.rb', line 32

def find_pin_node(data)
  stack = [data]
  until stack.empty?
    node = stack.pop
    case node
    when Hash
      return node if pin_like?(node)

      stack.concat(node.values)
    when Array
      stack.concat(node)
    end
  end
  nil
end

.first_video_url(pin) ⇒ Object



53
54
55
56
57
58
# File 'lib/pinterest_dl/extractors/pin_data.rb', line 53

def first_video_url(pin)
  video_list = pin.dig('videos', 'video_list')
  return nil unless video_list.is_a?(Hash)

  video_list.values.first&.dig('url')
end

.parse_embedded_json(html) ⇒ Object



24
25
26
27
28
29
30
# File 'lib/pinterest_dl/extractors/pin_data.rb', line 24

def parse_embedded_json(html)
  html.to_s.scan(SCRIPT_PATTERN).each do |(raw)|
    parsed = safe_parse(raw)
    return parsed if parsed
  end
  nil
end

.pin_like?(node) ⇒ Boolean

Returns:

  • (Boolean)


48
49
50
51
# File 'lib/pinterest_dl/extractors/pin_data.rb', line 48

def pin_like?(node)
  images = node['images']
  images.is_a?(Hash) && images.dig('orig', 'url')
end

.safe_parse(raw) ⇒ Object



60
61
62
63
64
# File 'lib/pinterest_dl/extractors/pin_data.rb', line 60

def safe_parse(raw)
  JSON.parse(raw)
rescue JSON::ParserError
  nil
end