Class: RubyTube::Client

Inherits:
Object
  • Object
show all
Defined in:
lib/rubytube/client.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(url) ⇒ Client

Returns a new instance of Client.



5
6
7
8
9
10
11
12
# File 'lib/rubytube/client.rb', line 5

def initialize(url)
  self.video_id = Extractor.video_id(url)

  self.watch_url = "https://youtube.com/watch?v=#{video_id}"
  self.embed_url = "https://www.youtube.com/embed/#{video_id}"

  self.stream_monostate = Monostate.new
end

Instance Attribute Details

#embed_urlObject

Returns the value of attribute embed_url.



3
4
5
# File 'lib/rubytube/client.rb', line 3

def embed_url
  @embed_url
end

#stream_monostateObject

Returns the value of attribute stream_monostate.



3
4
5
# File 'lib/rubytube/client.rb', line 3

def stream_monostate
  @stream_monostate
end

#video_idObject

Returns the value of attribute video_id.



3
4
5
# File 'lib/rubytube/client.rb', line 3

def video_id
  @video_id
end

#watch_urlObject

Returns the value of attribute watch_url.



3
4
5
# File 'lib/rubytube/client.rb', line 3

def watch_url
  @watch_url
end

Instance Method Details

#authorObject



152
153
154
155
156
157
# File 'lib/rubytube/client.rb', line 152

def author
  return @author if @author

  @author = vid_info["videoDetails"]["author"]
  @author
end

#bypass_age_gateObject



119
120
121
122
123
124
125
126
127
128
129
# File 'lib/rubytube/client.rb', line 119

def bypass_age_gate
  it = InnerTube.new(client: "ANDROID_EMBED")
  resp = it.player(video_id)

  status = resp["playabilityStatus"]["status"]
  if status == "UNPLAYABLE"
    raise VideoUnavailable.new(video_id)
  end

  @vid_info = resp
end

#channel_idObject



166
167
168
169
170
171
# File 'lib/rubytube/client.rb', line 166

def channel_id
  return @channel_id if @channel_id

  @channel_id = vid_info["videoDetails"]["channelId"]
  @channel_id
end

#check_availabilityObject



67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/rubytube/client.rb', line 67

def check_availability
  status, messages = Extractor.playability_status(watch_html)

  messages.each do |reason|
    case status
    when "UNPLAYABLE"
      case reason
      when "Join this channel to get access to members-only content like this video, and other exclusive perks."
        raise MembersOnly.new(video_id)
      when "This live stream recording is not available."
        raise RecordingUnavailable.new(video_id)
      else
        raise VideoUnavailable.new(video_id)
      end
    when "LOGIN_REQUIRED"
      if reason == "This is a private video. Please sign in to verify that you may see it."
        raise VideoPrivate.new(video_id)
      end
    when "ERROR"
      if reason == "Video unavailable"
        raise VideoUnavailable.new(video_id)
      end
    when "LIVE_STREAM"
      raise LiveStreamError.new(video_id)
    end
  end
end

#fmt_streamsObject



42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/rubytube/client.rb', line 42

def fmt_streams
  check_availability
  return @fmt_streams if @fmt_streams

  @fmt_streams = []
  stream_manifest = Extractor.apply_descrambler(streaming_data)

  begin
    Extractor.apply_signature(stream_manifest, vid_info, js)
  rescue ExtractError
    js = nil
    js_url = nil
    Extractor.apply_signature(stream_manifest, vid_info, js)
  end

  for stream in stream_manifest
    @fmt_streams << Stream.new(stream, stream_monostate)
  end

  stream_monostate.title = title
  stream_monostate.duration = length

  @fmt_streams
end

#jsObject



21
22
23
24
25
26
# File 'lib/rubytube/client.rb', line 21

def js
  return @js if @js

  @js = Request.get(js_url)
  @js
end

#js_urlObject



28
29
30
31
32
33
# File 'lib/rubytube/client.rb', line 28

def js_url
  return @js_url if @js_url

  @js_url = Extractor.js_url(watch_html)
  @js_url
end

#keywordsObject



159
160
161
162
163
164
# File 'lib/rubytube/client.rb', line 159

def keywords
  return @keywords if @keywords

  @keywords = vid_info["videoDetails"]["keywords"]
  @keywords
end

#lengthObject



138
139
140
141
142
143
# File 'lib/rubytube/client.rb', line 138

def length
  return @length if @length

  @length = vid_info["videoDetails"]["lengthSeconds"].to_i
  @length
end

#streaming_dataObject



35
36
37
38
39
40
# File 'lib/rubytube/client.rb', line 35

def streaming_data
  return vid_info["streamingData"] if vid_info && vid_info.key?("streamingData")

  bypass_age_gate
  vid_info["streamingData"]
end

#streamsObject



95
96
97
98
99
100
# File 'lib/rubytube/client.rb', line 95

def streams
  return @streams if @streams

  check_availability
  @streams = StreamQuery.new(fmt_streams)
end

#thumbnail_urlObject



102
103
104
105
106
107
108
# File 'lib/rubytube/client.rb', line 102

def thumbnail_url
  thumbs = vid_info.fetch("videoDetails", {}).fetch("thumbnail", {}).fetch("thumbnails", [])

  return thumbs[-1]["url"] if thumbs.size > 0

  "https://img.youtube.com/vi/#{ideo_id}/maxresdefault.jpg"
end

#titleObject



131
132
133
134
135
136
# File 'lib/rubytube/client.rb', line 131

def title
  return @title if @title

  @title = vid_info["videoDetails"]["title"]
  @title
end

#vid_infoObject



110
111
112
113
114
115
116
117
# File 'lib/rubytube/client.rb', line 110

def vid_info
  return @vid_info if @vid_info

  it = InnerTube.new
  @vid_info = it.player(video_id)

  @vid_info
end

#viewsObject



145
146
147
148
149
150
# File 'lib/rubytube/client.rb', line 145

def views
  return @views if @views

  @views = vid_info["videoDetails"]["viewCount"].to_i
  @views
end

#watch_htmlObject



14
15
16
17
18
19
# File 'lib/rubytube/client.rb', line 14

def watch_html
  return @watch_html if @watch_html

  @watch_html = Request.get(watch_url)
  @watch_html
end