123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126 |
- require 'dotenv/load'
- require 'google/apis/youtube_v3'
- require 'json'
- require 'open-uri'
- require 'twitter'
-
- Dotenv.load
-
- YOUTUBE_API_KEY = ENV["YOUTUBE_API_KEY"]
-
- TWITTER_CONSUMER_KEY = ENV["TWITTER_CONSUMER_KEY"]
- TWITTER_CONSUMER_SECRET = ENV["TWITTER_CONSUMER_SECRET"]
- TWITTER_ACCESS_TOKEN = ENV["TWITTER_ACCESS_TOKEN"]
- TWITTER_ACCESS_TOKEN_SECRET = ENV["TWITTER_ACCESS_TOKEN_SECRET"]
-
- YOUTUBE_DL_PATH = `which youtube-dl`.chomp
- FFMPEG_PATH = `which ffmpeg`.chomp
- FFPROBE_PATH = `which ffprobe`.chomp
-
- throw "YOUTUBE_API_KEY is required" unless YOUTUBE_API_KEY
- throw "TWITTER_CONSUMER_KEY is required" unless TWITTER_CONSUMER_KEY
- throw "TWITTER_CONSUMER_SECRET is required" unless TWITTER_CONSUMER_SECRET
- throw "TWITTER_ACCESS_TOKEN is required" unless TWITTER_ACCESS_TOKEN
- throw "TWITTER_ACCESS_TOKEN_SECRET is required" unless TWITTER_ACCESS_TOKEN_SECRET
-
- throw "Can't find youtube-dl" if YOUTUBE_DL_PATH.empty?
- throw "Can't find ffprobe" if FFPROBE_PATH.empty?
- throw "Can't find ffmpeg" if FFMPEG_PATH.empty?
-
- class YouTubeService
- @@RESULTS_PER_PAGE = 50.0
- @@PLAYLIST_OPTIONS = {
- fields: 'items/snippet/resourceId/videoId,nextPageToken,page_info',
- max_results: @@RESULTS_PER_PAGE,
- }
-
- def initialize
- @youtube = Google::Apis::YoutubeV3::YouTubeService.new
- @youtube.key = YOUTUBE_API_KEY
- end
-
- def fetch_random_frame_from_random_video
- video_id = fetch_random_video_from_channel('ComputerChroniclesYT')
- video_path = download_video(video_id)
- frame_path = extract_frame(video_path)
- delete_file(video_path)
- frame_path
- end
-
-
- def fetch_random_video_from_channel(channel_name)
- uploads_playlist_id = fetch_channel_uploads_playlist(channel_name)
- response = fetch_playlist_videos(uploads_playlist_id)
- extract_random_video(uploads_playlist_id, response)
- end
-
- def fetch_channel_uploads_playlist(channel_name)
- channel = @youtube.list_channels('contentDetails', for_username: channel_name)
- throw "No channel found" unless channel.items.first
- channel.items.first.content_details.related_playlists.uploads
- end
-
- def fetch_playlist_videos(playlist_id)
- @youtube.list_playlist_items('snippet', @@PLAYLIST_OPTIONS.merge(playlist_id: playlist_id))
- end
-
- def extract_random_video(playlist_id, response)
- number_of_videos = response.page_info.total_results
- number_of_pages = (number_of_videos / @@RESULTS_PER_PAGE).ceil
- random_page_number = rand(1..number_of_pages)
-
- (1..random_page_number).each do
- response = @youtube.list_playlist_items(
- 'snippet',
- @@PLAYLIST_OPTIONS.merge(
- page_token: response.next_page_token,
- playlist_id: playlist_id
- )
- )
- end
-
- response.items.sample.snippet.resource_id.video_id
- end
-
- def download_video(video_id)
- output_path = "/tmp/video.mp4"
- `#{YOUTUBE_DL_PATH} -f mp4 -o /tmp/video.mp4 #{video_id}`
- output_path
- end
-
- def extract_frame(video_path)
- output_path = "/tmp/frame.png"
- length = get_video_length(video_path)
- random_second = rand(0..length)
- `#{FFMPEG_PATH} -v error -ss #{random_second} -i #{video_path} -frames 1 -y #{output_path}`
- output_path
- end
-
- def get_video_length(video_path)
- `#{FFPROBE_PATH} -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 #{video_path}`.chomp.to_i
- end
-
- def delete_file(path)
- `rm #{path}`
- end
- end
-
- class TwitterService
- def initialize
- @twitter = Twitter::REST::Client.new do |config|
- config.consumer_key = TWITTER_CONSUMER_KEY
- config.consumer_secret = TWITTER_CONSUMER_SECRET
- config.access_token = TWITTER_ACCESS_TOKEN
- config.access_token_secret = TWITTER_ACCESS_TOKEN_SECRET
- end
- end
-
- def tweet_image(filepath)
- @twitter.update_with_media(String.new, File.new(filepath))
- end
- end
-
- youtube = YouTubeService.new
- filepath = youtube.fetch_random_frame_from_random_video
- TwitterService.new.tweet_image(filepath)
- youtube.delete_file(filepath)
|