YPBT 0.2.4 → 0.2.5

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.
@@ -1,37 +1,37 @@
1
- # frozen_string_literal: true
2
-
3
- module YoutubeVideo
4
- # Executable code for file(s) in bin/ folder
5
- class Runner
6
- def self.run!(args)
7
- video_id = args[0] || ENV['YT_VIDEO_ID']
8
- unless video_id
9
- puts 'USAGE: YPBT [video_id]'
10
- exit(1)
11
- end
12
-
13
- video = YoutubeVideo::Video.find(video_id: video_id)
14
-
15
- output_info(video)
16
- end
17
-
18
- def self.output_info(video)
19
- title = video.title
20
- separator = Array.new(video.title.length) { '-' }.join
21
- video_info =
22
- video.comments.map.with_index do |comment, index|
23
- comment_info(comment, index)
24
- end.join
25
-
26
- [title, separator, video_info].join("\n")
27
- end
28
-
29
- def self.comment_info(comment, index)
30
- "#{index + 1}:\n"\
31
- " Author: #{comment.author.author_name}\n"\
32
- " Comment: #{comment.text_display}\n"\
33
- " LIKE: #{comment.author.like_count}\n"\
34
- " AuthorChannelUrl: #{comment.author.author_channel_url}\n"
35
- end
36
- end
37
- end
1
+ # frozen_string_literal: true
2
+
3
+ module YoutubeVideo
4
+ # Executable code for file(s) in bin/ folder
5
+ class Runner
6
+ def self.run!(args)
7
+ video_id = args[0] || ENV['YT_VIDEO_ID']
8
+ unless video_id
9
+ puts 'USAGE: YPBT [video_id]'
10
+ exit(1)
11
+ end
12
+
13
+ video = YoutubeVideo::Video.find(video_id: video_id)
14
+
15
+ output_info(video)
16
+ end
17
+
18
+ def self.output_info(video)
19
+ title = video.title
20
+ separator = Array.new(video.title.length) { '-' }.join
21
+ video_info =
22
+ video.comments.map.with_index do |comment, index|
23
+ comment_info(comment, index)
24
+ end.join
25
+
26
+ [title, separator, video_info].join("\n")
27
+ end
28
+
29
+ def self.comment_info(comment, index)
30
+ "#{index + 1}:\n"\
31
+ " Author: #{comment.author.author_name}\n"\
32
+ " Comment: #{comment.text_display}\n"\
33
+ " LIKE: #{comment.author.like_count}\n"\
34
+ " AuthorChannelUrl: #{comment.author.author_channel_url}\n"
35
+ end
36
+ end
37
+ end
@@ -1,55 +1,55 @@
1
- require 'ruby-duration'
2
-
3
- module YoutubeVideo
4
- TAG_TYPES = { MUSIC: 'music', VIDEO: 'video' }.freeze
5
- # comment's time tag infomation
6
- class Timetag
7
- attr_reader :start_time, :end_time, :tag_type, :duration, :comment,
8
- :like_count
9
- def initialize(start_time:, comment:, end_time: nil, like_count: nil,
10
- tag_type: nil)
11
- @start_time = string_to_time start_time
12
- @end_time = end_time
13
- @like_count = like_count ? like_count : comment.like_count
14
- @tag_type = tag_type
15
- end
16
-
17
- def start_time
18
- @start_time&.iso8601
19
- end
20
-
21
- def end_time=(end_time)
22
- @end_time = string_to_time end_time if end_time
23
- end
24
-
25
- def end_time
26
- @end_time&.iso8601 if @end_time
27
- end
28
-
29
- def duration
30
- @duration = @end_time - @start_time if @end_time && @start_time
31
- @duration&.iso8601 if @duration
32
- end
33
-
34
- def tag_type=(tag_type)
35
- @tag_type = TAG_TYPES[tag_type.to_sym] if tag_type
36
- end
37
-
38
- def self.find(comment:)
39
- time_tag_pattern = /http.+?youtube.+?\?.+?t=.+?\>([0-9:]+)<\/a>/
40
- start_times_string = comment.text_display.scan time_tag_pattern
41
- tags = start_times_string.map do |match_parts|
42
- Timetag.new(start_time: match_parts[0], comment: comment)
43
- end
44
- tags
45
- end
46
-
47
- private
48
-
49
- def string_to_time(time_string)
50
- time_unit = [:seconds, :minutes, :hours, :day, :weeks]
51
- time_array = time_string.scan(/[0-9]+/).map(&:to_i).reverse
52
- Duration.new(Hash[time_unit.zip(time_array)])
53
- end
54
- end
55
- end
1
+ require 'ruby-duration'
2
+
3
+ module YoutubeVideo
4
+ TAG_TYPES = { MUSIC: 'music', VIDEO: 'video' }.freeze
5
+ # comment's time tag infomation
6
+ class Timetag
7
+ attr_reader :start_time, :end_time, :tag_type, :duration, :comment,
8
+ :like_count
9
+ def initialize(start_time:, comment:, end_time: nil, like_count: nil,
10
+ tag_type: nil)
11
+ @start_time = string_to_time start_time
12
+ @end_time = end_time
13
+ @like_count = like_count ? like_count : comment.like_count
14
+ @tag_type = tag_type
15
+ end
16
+
17
+ def start_time
18
+ @start_time&.iso8601
19
+ end
20
+
21
+ def end_time=(end_time)
22
+ @end_time = string_to_time end_time if end_time
23
+ end
24
+
25
+ def end_time
26
+ @end_time&.iso8601 if @end_time
27
+ end
28
+
29
+ def duration
30
+ @duration = @end_time - @start_time if @end_time && @start_time
31
+ @duration&.iso8601 if @duration
32
+ end
33
+
34
+ def tag_type=(tag_type)
35
+ @tag_type = TAG_TYPES[tag_type.to_sym] if tag_type
36
+ end
37
+
38
+ def self.find(comment:)
39
+ time_tag_pattern = /http.+?youtube.+?\?.+?t=.+?\>([0-9:]+)<\/a>/
40
+ start_times_string = comment.text_display.scan time_tag_pattern
41
+ tags = start_times_string.map do |match_parts|
42
+ Timetag.new(start_time: match_parts[0], comment: comment)
43
+ end
44
+ tags
45
+ end
46
+
47
+ private
48
+
49
+ def string_to_time(time_string)
50
+ time_unit = [:seconds, :minutes, :hours, :day, :weeks]
51
+ time_array = time_string.scan(/[0-9]+/).map(&:to_i).reverse
52
+ Duration.new(Hash[time_unit.zip(time_array)])
53
+ end
54
+ end
55
+ end
@@ -1,5 +1,5 @@
1
- # frozen_string_literal: true
2
-
3
- module YoutubeVideo
4
- VERSION = '0.2.4'
5
- end
1
+ # frozen_string_literal: true
2
+
3
+ module YoutubeVideo
4
+ VERSION = '0.2.5'
5
+ end
@@ -1,38 +1,63 @@
1
- # frozen_string_literal: true
2
- require_relative 'comment'
3
- require_relative 'youtube_api'
4
-
5
- module YoutubeVideo
6
- # Main class to setup a Video
7
- class Video
8
- attr_reader :title, :description, :dislike_count, :like_count,
9
- :comment_count, :view_count, :duration, :id
10
-
11
- def initialize(data:)
12
- @id = data['id']
13
- @title = data['snippet']['title']
14
- @description = data['snippet']['description']
15
- @dislike_count = data['statistics']['dislikeCount'].to_i
16
- @like_count = data['statistics']['likeCount'].to_i
17
- @view_count = data['statistics']['viewCount'].to_i
18
- @duration = data['contentDetails']['duration']
19
- end
20
-
21
- def comments
22
- # contain only the comments which have time tag.
23
- return @comments if @comments
24
- raw_comments = YtApi.time_tags_info(@id)
25
- @comments = raw_comments.map { |comment| Comment.new(data: comment) }
26
- end
27
-
28
- def embed_url
29
- return @embed_url if @embed_url
30
- @embed_url = "https://www.youtube.com/embed/#{@id}"
31
- end
32
-
33
- def self.find(video_id:)
34
- video_data = YtApi.video_info(video_id)
35
- new(data: video_data) if video_data
36
- end
37
- end
38
- end
1
+ # frozen_string_literal: true
2
+ require_relative 'comment'
3
+ require_relative 'youtube_api'
4
+
5
+ module YoutubeVideo
6
+ # Main class to setup a Video
7
+ class Video
8
+ attr_reader :title, :description, :dislike_count, :like_count,
9
+ :comment_count, :view_count, :duration, :id, :channel_id
10
+
11
+ def initialize(data:)
12
+ @id = data['id']
13
+ @title = data['snippet']['title']
14
+ @channel_id = data['snippet']['channelId']
15
+ @description = data['snippet']['description']
16
+ @dislike_count = data['statistics']['dislikeCount'].to_i
17
+ @like_count = data['statistics']['likeCount'].to_i
18
+ @view_count = data['statistics']['viewCount'].to_i
19
+ @duration = data['contentDetails']['duration']
20
+ end
21
+
22
+ def comments
23
+ # contain only the comments which have time tag.
24
+ return @comments if @comments
25
+ raw_comments = YtApi.time_tags_info(@id)
26
+ @comments = raw_comments.map { |comment| Comment.new(data: comment) }
27
+ end
28
+
29
+ def channel_title
30
+ load_channel_info unless @channel_title
31
+ @channel_title
32
+ end
33
+
34
+ def channel_image_url
35
+ load_channel_info unless @channel_image_url
36
+ @channel_image_url
37
+ end
38
+
39
+ def channel_description
40
+ load_channel_info unless @channel_description
41
+ @channel_description
42
+ end
43
+
44
+ def embed_url
45
+ return @embed_url if @embed_url
46
+ @embed_url = "https://www.youtube.com/embed/#{@id}"
47
+ end
48
+
49
+ def self.find(video_id:)
50
+ video_data = YtApi.video_info(video_id)
51
+ new(data: video_data) if video_data
52
+ end
53
+
54
+ private
55
+
56
+ def load_channel_info
57
+ channel_data = YtApi.channel_info @channel_id
58
+ @channel_title = channel_data['title']
59
+ @channel_image_url = channel_data['image_url']
60
+ @channel_description = channel_data['description']
61
+ end
62
+ end
63
+ end
@@ -1,92 +1,108 @@
1
- # frozen_string_literal: true
2
- require 'http'
3
- require 'json'
4
-
5
- module YoutubeVideo
6
- # Service for all Youtube API calls
7
- class YtApi
8
- YT_URL = 'https://www.googleapis.com'
9
- YT_COMPANY = 'youtube'
10
- YT_COMPANY_URL = URI.join(YT_URL, "#{YT_COMPANY}/")
11
- API_VER = 'v3'
12
- YT_API_URL = URI.join(YT_COMPANY_URL, "#{API_VER}/")
13
- TIME_TAG_PATTERN = /http.+?youtube.+?\?.+?t=.+?\>([0-9:]+)<\/a>/
14
- def self.api_key
15
- return @api_key if @api_key
16
- @api_key = ENV['YOUTUBE_API_KEY']
17
- end
18
-
19
- def self.config=(credentials)
20
- @config ? @config.update(credentials) : @config = credentials
21
- end
22
-
23
- def self.video_info(video_id)
24
- field = 'items(id,snippet(channelId,description,publishedAt,title),'\
25
- 'statistics(likeCount,dislikeCount,viewCount),'\
26
- 'contentDetails(duration))'
27
- video_response = HTTP.get(yt_resource_url('videos'),
28
- params: { id: video_id,
29
- key: api_key,
30
- part: 'snippet,statistics,
31
- contentDetails',
32
- fields: field })
33
- JSON.parse(video_response.to_s)['items'].first
34
- end
35
-
36
- def self.comment_info(comment_id)
37
- comment_response = HTTP.get(yt_resource_url('comments'),
38
- params: { id: comment_id,
39
- key: api_key,
40
- part: 'snippet' })
41
- item = JSON.parse(comment_response.to_s)['items'].first
42
- comment = item['snippet']
43
- comment['id'] = comment_id
44
- comment
45
- end
46
-
47
- def self.video_comments_info(video_id, page_token = '', max_results = 100)
48
- comment_threads_response = HTTP.get(yt_resource_url('commentThreads'),
49
- params: { videoId: video_id,
50
- key: api_key,
51
- order: 'relevance',
52
- part: 'snippet',
53
- maxResults: max_results,
54
- pageToken: page_token })
55
- comment_threads = JSON.parse(comment_threads_response.to_s)
56
- comments = extract_comment(comment_threads)
57
- next_page_token = comment_threads['nextPageToken']
58
- [next_page_token, comments]
59
- end
60
-
61
- def self.extract_comment(comment_threads)
62
- comments = comment_threads['items'].map do |item|
63
- comment = item['snippet']['topLevelComment']['snippet']
64
- comment['id'] = item['id']
65
- comment
66
- end
67
- comments
68
- end
69
-
70
- def self.time_tags_info(video_id, max_search_time = 5)
71
- next_page = ''
72
- comments_with_tags = []
73
- max_search_time.times do
74
- next_page, tmp_comments = video_comments_info(video_id, next_page)
75
- tmp_comments.each do |comment|
76
- comments_with_tags.push(comment) if time_tag? comment
77
- end
78
- break unless next_page
79
- end
80
- comments_with_tags
81
- end
82
-
83
- def self.time_tag?(comment)
84
- !(comment['textDisplay'] =~ TIME_TAG_PATTERN).nil?
85
- end
86
-
87
- private_class_method
88
- def self.yt_resource_url(resouce_name)
89
- URI.join(YT_API_URL, resouce_name.to_s)
90
- end
91
- end
92
- end
1
+ # frozen_string_literal: true
2
+ require 'http'
3
+ require 'json'
4
+
5
+ module YoutubeVideo
6
+ # Service for all Youtube API calls
7
+ class YtApi
8
+ YT_URL = 'https://www.googleapis.com'
9
+ YT_COMPANY = 'youtube'
10
+ YT_COMPANY_URL = URI.join(YT_URL, "#{YT_COMPANY}/")
11
+ API_VER = 'v3'
12
+ YT_API_URL = URI.join(YT_COMPANY_URL, "#{API_VER}/")
13
+ TIME_TAG_PATTERN = /http.+?youtube.+?\?.+?t=.+?\>([0-9:]+)<\/a>/
14
+ def self.api_key
15
+ return @api_key if @api_key
16
+ @api_key = ENV['YOUTUBE_API_KEY']
17
+ end
18
+
19
+ def self.config=(credentials)
20
+ @config ? @config.update(credentials) : @config = credentials
21
+ end
22
+
23
+ def self.video_info(video_id)
24
+ field = 'items(id,snippet(channelId,description,publishedAt,title),'\
25
+ 'statistics(likeCount,dislikeCount,viewCount),'\
26
+ 'contentDetails(duration))'
27
+ video_response = HTTP.get(yt_resource_url('videos'),
28
+ params: { id: video_id,
29
+ key: api_key,
30
+ part: 'snippet,statistics,
31
+ contentDetails',
32
+ fields: field })
33
+ JSON.parse(video_response.to_s)['items'].first
34
+ end
35
+
36
+ def self.comment_info(comment_id)
37
+ comment_response = HTTP.get(yt_resource_url('comments'),
38
+ params: { id: comment_id,
39
+ key: api_key,
40
+ part: 'snippet' })
41
+ item = JSON.parse(comment_response.to_s)['items'].first
42
+ comment = item['snippet']
43
+ comment['id'] = comment_id
44
+ comment
45
+ end
46
+
47
+ def self.video_comments_info(video_id, page_token = '', max_results = 100)
48
+ comment_threads_response = HTTP.get(yt_resource_url('commentThreads'),
49
+ params: { videoId: video_id,
50
+ key: api_key,
51
+ order: 'relevance',
52
+ part: 'snippet',
53
+ maxResults: max_results,
54
+ pageToken: page_token })
55
+ comment_threads = JSON.parse(comment_threads_response.to_s)
56
+ comments = extract_comment(comment_threads)
57
+ next_page_token = comment_threads['nextPageToken']
58
+ [next_page_token, comments]
59
+ end
60
+
61
+ def self.channel_info(channel_id)
62
+ fields = 'items(id,snippet(title,description,thumbnails(default(url))))'
63
+ channel_response = HTTP.get(yt_resource_url('channels'),
64
+ params: { id: channel_id,
65
+ key: api_key,
66
+ part: 'snippet',
67
+ fields: fields })
68
+ channel_data = JSON.parse(channel_response.to_s)['items'].first['snippet']
69
+ {
70
+ 'title' => channel_data['title'],
71
+ 'description' => channel_data['description'],
72
+ 'image_url' => channel_data['thumbnails']['default']['url']
73
+ }
74
+ end
75
+
76
+ def self.extract_comment(comment_threads)
77
+ comments = comment_threads['items'].map do |item|
78
+ comment = item['snippet']['topLevelComment']['snippet']
79
+ comment['id'] = item['id']
80
+ comment
81
+ end
82
+ comments
83
+ end
84
+
85
+ def self.time_tags_info(video_id, max_search_time = 5)
86
+ next_page = ''
87
+ comments_with_tags = []
88
+ max_search_time.times do
89
+ next_page, tmp_comments = video_comments_info(video_id, next_page)
90
+ tmp_comments.each do |comment|
91
+ comments_with_tags.push(comment) if time_tag? comment
92
+ end
93
+ break unless next_page
94
+ end
95
+ comments_with_tags
96
+ end
97
+
98
+
99
+ def self.time_tag?(comment)
100
+ !(comment['textDisplay'] =~ TIME_TAG_PATTERN).nil?
101
+ end
102
+
103
+ private_class_method
104
+ def self.yt_resource_url(resouce_name)
105
+ URI.join(YT_API_URL, resouce_name.to_s)
106
+ end
107
+ end
108
+ end