I am working on a project here which grabs my YouTube account playlist and then adds each song to my Spotify likes. This is my first project with Python and API's so I may sound confused here.
I am using my google OAUTH Client 2.0 to authenticate once I run the program. I enter in the new key that they give me after authenticating and then select which playlist I want to grab songs from.
Then my issue occurs once I select the playlist I want to use. The execution then stops and gives me this error after a request.execute() call:
"googleapiclient.errors.HttpError: <HttpError 404 when requesting https://www.googleapis.com/youtube/v3/playlistItems?playlistId=%3Cyoutube_client.Playlist+object+at+0x0000028A3C883948%3E&part=id%2C+snippet&maxResults=50&alt=json returned "The playlist identified with the request's <code>playlistId</code> parameter cannot be found.">
When I click the link this message appears:
{
"error": {
"code": 403,
"message": "The request is missing a valid API key.",
"errors": [
{
"message": "The request is missing a valid API key.",
"domain": "global",
"reason": "forbidden"
}
],
"status": "PERMISSION_DENIED"
}
}
Here is the code that the execution stops:
def get_videos_from_playlist(self, playlist_id):
songs = []
request = self.youtube_client.playlistItems().list(
playlistId=playlist_id,
part="id, snippet",
maxResults=50
)
response = request.execute()
I'm confused where its asking me for my missing API but I am using the Google OAUTH 2.0 Client to authenticate. I thought I didn't need one if I have the other. Do I need both? Do I need to add something to the client secrets?
EDIT
Here is what the call looks like in my run.py:
def run():
#1. Get a list of our playlists from Youtube
youtube_client = YouTubeClient('./creds/secrets.json')
spotify_client = SpotifyClient(os.getenv('SPOTIFY_AUTH_TOKEN'))
playlists = youtube_client.get_playlists()
#2. Ask which playlist we want to get the music videos from
for index, playlist in enumerate(playlists):
print(f"{index}: {playlist.title}")
choice = int(input("Enter your choice: "))
chosen_playlist = playlists[choice]
print(f"You selected: {chosen_playlist.title}")
#3 For each video in the playlist, get the song information from Youtube
songs = youtube_client.get_videos_from_playlist(chosen_playlist)
print(f"Attempting to add {len(songs)}")
Here is the my youtube_client.py:
def __init__(self, credentials_location):
# youtube_dl default User-Agent can cause some json values to return as None, using Facebook's web crawler solves this.
youtube_dl.utils.std_headers['User-Agent'] = "facebookexternalhit/1.1 (+http://www.facebook.com/externalhit_uatext.php)"
scopes = ["https://www.googleapis.com/auth/youtube.readonly"]
# Disable OAuthlib's HTTPS verification when running locally.
# *DO NOT* leave this option enabled in production.
os.environ["OAUTHLIB_INSECURE_TRANSPORT"] = "1"
api_service_name = "youtube"
api_version = "v3"
# Get credentials and create an API client
flow = google_auth_oauthlib.flow.InstalledAppFlow.from_client_secrets_file(
credentials_location, scopes)
credentials = flow.run_console()
youtube_client = googleapiclient.discovery.build(
api_service_name, api_version, credentials=credentials)
self.youtube_client = youtube_client
def get_playlists(self):
request = self.youtube_client.playlists().list(
part="id, snippet",
maxResults=50,
mine=True
)
response = request.execute()
playlists = [Playlist(item['id'], item['snippet']['title']) for item in response['items']]
return playlists
The parameter
playlist_id
of functionget_videos_from_playlist
should be a playlist's ID (since it is passed on to the parameterplaylistId
of thePlaylistItems.list
API endpoint).But, by the code:
the actual type of
playlist_id
is the classPlaylist
(which your code above does not show).You must fix your call to
get_videos_from_playlist
above by passing to it the ID that is retained by thechosen_playlist
instance ofPlaylist
class.In case your
Playlist
class is something like:then your fixed code would look as: