Solved: I used the time.sleep() method to space out method calls and it worked.
Code summary: Script that uses YouTube API and implements OAuth 2.0 to get access to one account, retrieve its liked videos, and get access to another account and use that list of liked videos to like them on the new account. It may seem like a weird project but I just started using Python this week and this is my first project and it seemed easy enough (I was wrong)
This is the relevant part of my code:
def likeVideos(videos,youtubeObject): youtube = youtubeObject videos = videos numofVideosLiked = 0 numLikedVideos = 0 for video in videos: numLikedVideos += 1 for video in videos: newRequest = youtube.videos().getRating( id=[video['id']] ) newResponse = newRequest.execute() if 'rating' in newResponse and (newResponse['rating'] == 'like' or newResponse['rating'] == 'unspecified'): print(f"Already liked '{video['snippet']['title']}' or something went wrong...") else: likeRequest = youtube.videos().rate( id=video['id'], rating='like' ).execute() numofVideosLiked += 1 print(f"Liking {video['snippet']['title']}...{numofVideosLiked}/{numLikedVideos}")
The output in the terminal indicated that I successfully liked my first 194 videos from the parent account before it broke down:
Liking coding in c until my program is unsafe...191/354Liking OVERDOSING ON TF2!!!...192/354Liking JavaScript Fighting Game Tutorial with HTML Canvas...193/354Liking DIY PCBs At Home (Single Sided Presensitized)...194/354
However, the child account only had 30 videos actually liked, and they were done in random intervals of 5. (To be specific, videos 1-5, 31-35, 68-72, 106-110, etc were actually liked on the second account) My understanding is that reading from lists is in groups of 5 so you need to increase the maxResults parameter like I did here when retrieving the list initially:
while True: # Make API request request = youtube.videos().list( part='snippet', myRating='like', maxResults=50, pageToken = next_page_token ) response = request.execute() # Add videos to list videos += response['items'] next_page_token = response.get('nextPageToken') if not next_page_token: break
But I am not sure what to do when actually calling the rate() function to like the videos because its only parameters are id and rating.
I believe this code block is the main problem:
if 'rating' in newResponse and (newResponse['rating'] == 'like' or newResponse['rating'] == 'unspecified'): print(f"Already liked '{video['snippet']['title']}' or something went wrong...") else: likeRequest = youtube.videos().rate( id=video['id'], rating='like' ).execute()
The if statement never catches already-liked videos when I run the script multiple times after some videos were already liked and the method of liking the videos doesn't seem to be accurate.
- Is it possible Youtube limits how fast you can like videos? Is there a workaround?
- What is a better way to check if the videos are already liked other than this code snippet?:
if 'rating' in newResponse and (newResponse['rating'] == 'like' or newResponse['rating'] == 'unspecified'):
Here is the full source code only if it's necessary to help with my question:
from googleapiclient.discovery import buildfrom google_auth_oauthlib.flow import InstalledAppFlowfrom google.auth.transport.requests import Requestimport pickleimport os# Make API request and build Youtube objectdef getYoutubeObject(client_secret, path_to_pickled_file): credentials = None scopes = ["https://www.googleapis.com/auth/youtube.force-ssl",'https://www.googleapis.com/auth/youtube','https://www.googleapis.com/auth/youtube.readonly','https://www.googleapis.com/auth/youtube.upload','https://www.googleapis.com/auth/youtubepartner','https://www.googleapis.com/auth/youtubepartner-channel-audit'] # path_to_pickled_file file stores user credentials if os.path.exists(path_to_pickled_file): print("Loading credentials of account from file...") with open(path_to_pickled_file, 'rb') as token: credentials = pickle.load(token) # If there are no valid credentials, refresh token or log in if not credentials or not credentials.valid: if credentials and credentials.expired and credentials.refresh_token: print("Refreshing access token for account...") credentials.refresh(Request()) else: print("Fetching new tokens for account...") flow = InstalledAppFlow.from_client_secrets_file( client_secret, scopes=scopes ) flow.run_local_server( port=8080, prompt="consent", authorization_prompt_message='' ) credentials = flow.credentials # Save credentials for next use with open(path_to_pickled_file, 'wb') as f: print("Saving credentials of account for future use...") pickle.dump(credentials, f) api_name = 'youtube' api_version = 'v3' youtube = build(api_name, api_version, credentials=credentials) return youtube# Return list of liked videosdef getLikedVideos(youtubeObject): youtube = youtubeObject next_page_token = None videos = [] # fields = "id, snippet(title)" while True: # Make API request request = youtube.videos().list( part='snippet', myRating='like', maxResults=50, pageToken = next_page_token ) response = request.execute() # Add videos to list videos += response['items'] next_page_token = response.get('nextPageToken') if not next_page_token: break numLikedVideos = 0 for video in videos: numLikedVideos += 1 print(f"You have {numLikedVideos} likes videos!") input("Press Enter to continue...") return videosdef likeVideos(videos,youtubeObject): youtube = youtubeObject videos = videos numofVideosLiked = 0 numLikedVideos = 0 for video in videos: numLikedVideos += 1 for video in videos: newRequest = youtube.videos().getRating( id=[video['id']] ) newResponse = newRequest.execute() if 'rating' in newResponse and (newResponse['rating'] == 'like' or newResponse['rating'] == 'unspecified'): print(f"Already liked '{video['snippet']['title']}' or something went wrong...") else: likeRequest = youtube.videos().rate( id=video['id'], rating='like' ).execute() numofVideosLiked += 1 print(f"Liking {video['snippet']['title']}...{numofVideosLiked}/{numLikedVideos}")def main(): client_secret = 'client_secret.json' path_to_pickled_file = 'token.pickle' path_to_second_pickled_file = 'secondToken.pickle' input("Press Enter to retrieve first Youtube object...") youtube = getYoutubeObject(client_secret, path_to_pickled_file) input("Press Enter to get liked videos...") videos = getLikedVideos(youtube) input("Press Enter to retrieve second Youtube object...") newYtObj = getYoutubeObject(client_secret, path_to_second_pickled_file) input("Press Enter to like videos...") likeVideos(videos, newYtObj)main()
I tried liking all videos within a list (350+ items) using the videos.rate method. But, only 30 ended up actually being rated (In intervals of 5 chronologically from my liked video history. The first 5 were liked, then 25 videos later it worked again and liked 5 more, etc)