| 1 | require 'google/apis/youtube_v3' |
| 2 | require 'google/api_client/client_secrets' |
| 3 | |
| 4 | # Fix this later |
| 5 | # rubocop:disable Metrics/ClassLength |
| 6 | class YoutubeClient |
| 7 | BASE_URI = 'https://youtube.googleapis.com/youtube/v3'.freeze |
| 8 | |
| 9 | def initialize(authorization) |
| 10 | raise 'Authorization is required' if authorization.nil? |
| 11 | |
| 12 | @authorization = authorization |
| 13 | @token = authorization.token |
| 14 | @youtube_export_playlist_count = 0 |
| 15 | @youtube_export_playlist_items_count = 0 |
| 16 | end |
| 17 | |
| 18 | def youtube_export_playlist_max_iteration |
| 19 | # If development, set to 2, else 10. |
| 20 | Rails.env.development? ? 2 : 10 |
| 21 | end |
| 22 | |
| 23 | # Personal content |
| 24 | def search_personal(_keywords) |
| 25 | results = service.list_searches('snippet', for_mine: false, q: 'dewa', type: 'video', |
| 26 | options: { authorization: auth_client }) |
| 27 | p results |
| 28 | end |
| 29 | |
| 30 | def search(keywords) |
| 31 | uri = 'https://www.googleapis.com/youtube/v3/search' |
| 32 | client = HTTPClient.new |
| 33 | query = { 'key' => 'AIzaSyDhs0-L3B6X_oq0cVn7GIPgvmb5--VlecE', 'q' => keywords, 'type' => 'video', |
| 34 | 'part' => 'snippet' } |
| 35 | header = [ |
| 36 | ['Accept', 'application/json'], |
| 37 | ['Content-Type', 'application/json'] |
| 38 | ] |
| 39 | client.get(uri, query, header) |
| 40 | end |
| 41 | |
| 42 | def user_likes_videos(next_page_token = nil) |
| 43 | query = { 'key' => ENV['GOOGLE_API_KEY'], 'myRating' => 'like', 'part' => 'snippet,contentDetails,statistics', |
| 44 | 'maxResults' => '50', 'pageToken' => next_page_token } |
| 45 | header = [ |
| 46 | ['Accept', 'application/json'], |
| 47 | ['Authorization', "Bearer #{@token}"] |
| 48 | ] |
| 49 | client.get("#{BASE_URI}/videos", query, header) |
| 50 | end |
| 51 | |
| 52 | # Get user's playlists list |
| 53 | def export_user_playlist(next_page_token = nil) |
| 54 | @youtube_export_playlist_count += 1 |
| 55 | response = get_user_playlist(next_page_token) |
| 56 | response_json = JSON.parse(response.body) |
| 57 | # Return if no playlist found |
| 58 | return if response_json['items'].nil? |
| 59 | |
| 60 | # Loop through all playlists items |
| 61 | response_json['items'].each do |playlists| |
| 62 | # Get playlist items |
| 63 | export_user_playlist_items(playlists['id']) |
| 64 | end |
| 65 | |
| 66 | # Check playlist pagination |
| 67 | if response_json['nextPageToken'].present? && @youtube_export_playlist_count < youtube_export_playlist_max_iteration |
| 68 | export_user_playlist(response_json['nextPageToken']) |
| 69 | end |
| 70 | end |
| 71 | |
| 72 | private |
| 73 | |
| 74 | def client |
| 75 | HTTPClient.new |
| 76 | end |
| 77 | |
| 78 | def service |
| 79 | @service ||= Google::Apis::YoutubeV3::YouTubeService.new |
| 80 | end |
| 81 | |
| 82 | def auth_client |
| 83 | @auth_client ||= Signet::OAuth2::Client.new(access_token: @token) |
| 84 | end |
| 85 | |
| 86 | def get_user_playlist(next_page_token = nil) |
| 87 | query = { 'key' => ENV['GOOGLE_API_KEY'], 'maxResults' => '50', 'mine' => true, |
| 88 | 'pageToken' => next_page_token } |
| 89 | header = [ |
| 90 | ['Accept', 'application/json'], |
| 91 | ['Authorization', "Bearer #{@token}"] |
| 92 | ] |
| 93 | client.get("#{BASE_URI}/playlists", query, header) |
| 94 | end |
| 95 | |
| 96 | def export_user_playlist_items(playlist_id, next_page_token = nil) |
| 97 | @youtube_export_playlist_items_count += 1 |
| 98 | response = get_user_playlist_items(playlist_id, next_page_token) |
| 99 | response_json = JSON.parse(response.body) |
| 100 | |
| 101 | # Get video ids from playlist items, separated by comma |
| 102 | video_ids = response_json['items'].map { |item| item['contentDetails']['videoId'] }.join(',') |
| 103 | p "Exporting playlist items: #{video_ids}" |
| 104 | get_videos_from_playlist_video_ids(video_ids) |
| 105 | |
| 106 | # Check playlist items pagination |
| 107 | if response_json['nextPageToken'].present? && @youtube_export_playlist_items_count < youtube_export_playlist_max_iteration |
| 108 | export_user_playlist_items(playlist_id, response_json['nextPageToken']) |
| 109 | end |
| 110 | end |
| 111 | |
| 112 | def get_user_playlist_items(id, next_page_token = nil) |
| 113 | query = { 'key' => ENV['GOOGLE_API_KEY'], 'part' => 'snippet,contentDetails', 'maxResults' => '50', |
| 114 | 'playlistId' => id, 'pageToken' => next_page_token } |
| 115 | header = [ |
| 116 | ['Accept', 'application/json'], |
| 117 | ['Authorization', "Bearer #{@token}"] |
| 118 | ] |
| 119 | client.get("#{BASE_URI}/playlistItems", query, header) |
| 120 | end |
| 121 | |
| 122 | def get_videos_from_playlist_video_ids(video_ids) |
| 123 | response = user_videos({ 'id' => video_ids }) |
| 124 | response_json = JSON.parse(response.body) |
| 125 | p "Exporting videos from playlist: #{response_json}" |
| 126 | export_youtube_videos(response_json['items'], @authorization.user_id) |
| 127 | end |
| 128 | |
| 129 | def export_youtube_videos(items, user_id) |
| 130 | music_videos = items.select { |item| item['snippet']['categoryId'] == '10' } |
| 131 | music_videos.each do |video| |
| 132 | SongProvider.upsert( |
| 133 | { user_id: user_id, provider_type: :youtube, provider_id: video['id'], name: video['snippet']['title'], |
| 134 | preview_url: "https://www.youtube.com/watch?v=#{video['id']}", description: video['snippet']['description'], |
| 135 | image_url: video['snippet']['thumbnails']['high']['url'] }, |
| 136 | unique_by: :index_song_providers_on_provider_id_and_provider_type |
| 137 | ) |
| 138 | end |
| 139 | end |
| 140 | |
| 141 | def user_videos(additional_query, next_page_token = nil) |
| 142 | p "Additional query: #{additional_query}" |
| 143 | query = { 'key' => ENV['GOOGLE_API_KEY'], 'part' => 'snippet,contentDetails,statistics', |
| 144 | 'maxResults' => '50', 'pageToken' => next_page_token } |
| 145 | query = query.merge(additional_query) |
| 146 | p "Query: #{query}" |
| 147 | header = [ |
| 148 | ['Accept', 'application/json'], |
| 149 | ['Authorization', "Bearer #{@token}"] |
| 150 | ] |
| 151 | client.get("#{BASE_URI}/videos", query, header) |
| 152 | end |
| 153 | end |