YouTube python API v3 HttpError 400 subscriptionDuplicate - python

I'm using YouTube python API v3 to subscribe oauth2 authenticated users to new channels.
def add_subscription(youtube, channel_id):
add_subscription_response = youtube.subscriptions().insert(
part='id,snippet',
body=dict(
snippet=dict(
resourceId=dict(
channelId=channel_id
)
)
)).execute()
return add_subscription_response["id"], add_subscription_response["snippet"]["title"]
youtube = get_authenticated_service(args)
try:
subscription_id,channel_title = add_subscription(youtube, args.channel_id)
except HttpError, e:
print "An HTTP error %d occurred:\n%s" % (e.resp.status, e.content)
else:
print "A subscription to '%s' was added." % channel_title
From https://developers.google.com/youtube/v3/docs/subscriptions/insert it seems that (or maybe, I understood that...) if the user is already subscribed to the channel described by channel_id, the function should raise an HttpError with e.resp.status=400 for a subscriptionDuplicate.
Nevertheless, if I try to subscribe to a channel the user is already subscribed to, the function normally returns a subscription_id and channel_title.
Shouldn't it raise HttpError 400?
And, if I'm not making mistakes and this is exactly the way the function should work, what could I do to check if the authenticated user is already subscribed to channel_id using only subscriptions().insert()?
I could call subscriptions().list() before, to check if user is subscribed:
def is_subscribed(youtube, channel_id):
is_subscription_response = youtube.subscriptions().list(
part='id',
mine='true',
forChannelId=channel_id
).execute()
if len(is_subscription_response["items"]) == 0:
return False
else:
return True
But this would increase quota usage...

I also tried the Subscriptions: insert request and use it in a channel that I already subscribed and I'm not getting the error subscriptionDuplicate. I don't know why the API did not return this error.
So to answer your question about how to check if the authenticated user is already subscribed to channel_id, use the Subscriptions: list to know all the channel that you subscribed.
Here is the sample request, just replace the channelId with your own channelId.
https://www.googleapis.com/youtube/v3/subscriptions?part=snippet&channelId=YOUR_CHANNEL_ID&key={YOUR_API_KEY}

Related

Spotipy ERROR 401 - Unauthorized although the used token is valid and already used before

Heyo Guys,
I am kinda frustraded because I can't find the error. I try to setup a script, which sets my playlists details back to how it was because of report abuses. I am using 'playlist_change_details' and 'playlist_upload_cover_image' which should use the same scope. Changing the name and the description is working, but the cover image tells me it got no token provided, although they use the same requested token. The image itself is valid and I didn't get an error about that.
Authentication Part (TaskSpotifyAuth.py):
import spotipy
import spotipy.oauth2 as oauth2
def auth(SCOPE = None, debug = False):
if SCOPE != None:
sp_oauth = oauth2.SpotifyOAuth(client_id=SPOTIPY_CLIENT_ID, client_secret=SPOTIPY_CLIENT_SECRET, scope=SCOPE,
redirect_uri=SPOTIPY_REDIRECT_URI, cache_path=CACHE)
access_token = ""
token_info = sp_oauth.get_cached_token()
if token_info != None:
if token_info['scope'] == SCOPE and sp_oauth.validate_token(token_info):
print("Found cached token for the scope: <" + SCOPE + ">") if debug == True else None
access_token = token_info['access_token']
else:
url = sp_oauth.get_authorization_code()
print(url)
code = sp_oauth.parse_response_code(url)
if code != "":
print("Found Spotify auth code in Request URL! Trying to get valid access token...") if debug == True else None
token_info = sp_oauth.get_access_token(code=code)
access_token = token_info['access_token']
if access_token:
print("Access token available! Trying to get user information...") if debug == True else None
sp = spotipy.Spotify(access_token)
return sp
else:
return None
Changing Details Part (TaskSpotify.py):
import TaskSpotifyAuth
def SpotifyLogin(scope=None, debug=False):
if scope == None:
return TaskSpotifyAuth.noPreToken()
else:
return TaskSpotifyAuth.auth(SCOPE=scope, debug=debug)
def change_playlist_details(pl_id, pl_name, pl_desc, pl_cover, debug=False):
sp = SpotifyLogin(scope='playlist-modify-public', debug=debug)
try:
sp.playlist_change_details(playlist_id=pl_id, name=pl_name, description=pl_desc)
try:
sp.playlist_upload_cover_image(playlist_id=pl_id, image_b64=pl_cover)
except:
print('Uploading a new cover image failed. The details of the playlist got changed.')
except:
print('Changing of the playlist details failed. No changes were made.')
Console Output:
#XXXXXXXXXXXXXX
Found Spotify auth code in Request URL! Trying to get valid access token...
Access token available! Trying to get user information...
HTTP Error for PUT to https://api.spotify.com/v1/playlists/XXXXXXXXXXXXXX/images with Params: {} returned 401 due to Unauthorized.
Uploading a new cover image failed. The details of the playlist got changed.
Message in the HTTP Error:
{
"error": {
"status": 401,
"message": "No token provided"
}
}
Thank you for your time!
Greets
MrSchiller
Looking at the documentation for authorization scopes, you may also need to include the scope for ugc-image-upload.

What can't I parse the API in my Telegram bot code?

I am trying to create a Telegram bot that allows users to search up recipes that require only ingredients that they have on-hand. It is built with Python and I have a rough code, but before I fine-tune the details, I want to get the basic form of it up and running. Unfortunately, I am facing difficulty in parsing the API for the recipes corresponding to ingredients that the user has listed in his/her message. Specifically, the logged error message is "Error parsing the API". Could someone take a look at my code and help me see what went wrong please?
This is the relevant portion of my code:
def handle_messages(messages):
for message in messages:
mappedIngreds = []
for i in range(len(message.text)):
ingred = message.text[i].lower()
if i == 0:
mappedIngreds.append(ingred)
else:
mappedIngreds.append(f"+ {ingred}")
# get responses from API
try:
response = requests.get(f"{apiURL}{mappedIngreds}{apiId}{apiKey}")
response.raise_for_status() # for debugging
except requests.RequestException:
logging.error("Error connecting to the API")
return None
# format responses into list of recipes
try:
recipes = []
for i in response.json():
recipeInfo = {}
recipeInfo["name"] = i["label"]
recipeInfo["url"] = i["url"]
recipes.append(recipeInfo)
except (KeyError, TypeError, ValueError):
logging.error("Error parsing the API")
return None
# send list of recipes to user
try:
bot.reply_to(message.chat.id, "Try these recipes:", *recipeInfo["name"], *recipeInfo["url"], sep="\n")
except:
logging.error("Error printing recipes")
My full code is here: https://pastebin.com/W0CceAt9

I would like to check the status of a list of twitter user ids

As stated in the question, I would like to check the status of a list of twitter user ids. I had about 20k twitter users. I was able to get the timelines of about half of them. The other have are probably either suspended, deactivated, or have 0 tweets. I found this script online that supposedly allow for checking the status of a twitter user. Here is the script (https://github.com/dbrgn/Twitter-User-Checker/blob/master/checkuser.py):
`
#!/usr/bin/env python2
# Twitter User Checker
# Author: Danilo Bargen
# License: GPLv3
import sys
import tweepy
import urllib2
try:
import json
except ImportError:
import simplejson as json
from datetime import datetime
auth = tweepy.AppAuthHandler("xxx", "xxxx")
api = tweepy.API(auth, wait_on_rate_limit=True, wait_on_rate_limit_notify=True)
if (not api):
print ("Can't Authenticate")
sys.exit(-1)
# Continue with rest of code
try:
user = sys.argv[1]
except IndexError:
print 'Usage: checkuser.py [username]'
sys.exit(-1)
url = 'https://api.twitter.com/1.1/users/show.json?id=%s' % user
try:
request = urllib2.urlopen(url)
status = request.code
data = request.read()
except urllib2.HTTPError, e:
status = e.code
data = e.read()
data = json.loads(data)
print data
if status == 403:
print "helloooooooo"
# if 'suspended' in data['error']:
# print 'User %s has been suspended' % user
# else:
# print 'Unknown response'
elif status == 404:
print 'User %s not found' % user
elif status == 200:
days_active = (datetime.now() - datetime.strptime(data['created_at'],
'%a %b %d %H:%M:%S +0000 %Y')).days
print 'User %s is active and has posted %s tweets in %s days' % \
(user, data['statuses_count'], days_active)
else:
print 'Unknown response'
`
I get the following error:
File "twitter_status_checker.py", line 16, in <module>
auth = tweepy.AppAuthHandler("xxx", "xxxx")
File "/Users/aloush/anaconda/lib/python2.7/site-packages/tweepy/auth.py", line 170, in __init__
'but got %s instead' % data.get('token_type'))
tweepy.error.TweepError: Expected token_type to equal "bearer", but got None instead
Could anyone help me fix the error as well as allow the script to check for a list of users rather than one user for each run.
Here is a list of the HTTP Status Codes I would like to check for: https://dev.twitter.com/overview/api/response-codes
Thank you.
It seems that you failed to authenticate twitter. For the latest version (3.5), tweepy uses OAuthHander to authenticate. Please check how to use Tweepy. And also the linked script you used is to check the account one by one, which could be very slow.
To check the status of a large set of Twitter accounts by Tweepy, particularly if you want to know the reason why it is inactive (e.g., not found, suspended), you need to be aware of the followings:
Which API should be used?
Twitter provides two related APIs, one is user/show and the other is user/lookup. The former one returns the profile of one specified user, while the later one returns profile of a block of up to 100 users. The corresponding tweepy APIs are API.get_user and API.lookup_users (I cannot find it in the documentation, but it does exist in code). Definitely, you should use the second one. However, when there exist some inactive users, the lookup_users API returns only these are active. This means that you have to call get_user API to get the very detail reason for inactive accounts.
How to determine the status of a user?
Of course, you should pay attention to the response code provided by Twitter. However, when using tweepy, instead of the HTTP ERROR CODES, you should pay more attention on the ERROR MESSAGE. Here are some common cases:
If the profile is successfully fetched, it is an active user;
Otherwise, we could check the error code:
50 User not found.
63 User has been suspended.
... maybe more code about the user account
For tweepy, when the profile is failed to fetch, a TweepyError is raised. And the TweepyError.message[0] is the error message from twitter API.
Okay, here are the logic to process
(1) Divide the large block of user into pieces of size of 100;
(2) for each of these pieces, do (3) and (4);
(3) call lookup_users, the returned users will be treated as the active users and the remaining users will be treated as inactive users;
(4) call get_user for each of the inactive users to get the detailed reason.
Here is a sample code for you:
import logging
import tweepy
logger = logging.getLogger(__name__)
def to_bulk(a, size=100):
"""Transform a list into list of list. Each element of the new list is a
list with size=100 (except the last one).
"""
r = []
qt, rm = divmod(len(a), size)
i = -1
for i in range(qt):
r.append(a[i * size:(i + 1) * size])
if rm != 0:
r.append(a[(i + 1) * size:])
return r
def fast_check(api, uids):
""" Fast check the status of specified accounts.
Parameters
---------------
api: tweepy API instance
uids: account ids
Returns
----------
Tuple (active_uids, inactive_uids).
`active_uids` is a list of active users and
`inactive_uids` is a list of inactive uids,
either supended or deactivated.
"""
try:
users = api.lookup_users(user_ids=uids,
include_entities=False)
active_uids = [u.id for u in users]
inactive_uids = list(set(uids) - set(active_uids))
return active_uids, inactive_uids
except tweepy.TweepError as e:
if e[0]['code'] == 50 or e[0]['code'] == 63:
logger.error('None of the users is valid: %s', e)
return [], inactive_uids
else:
# Unexpected error
raise
def check_inactive(api, uids):
""" Check inactive account, one by one.
Parameters
---------------
uids : list
A list of inactive account
Returns
----------
Yield tuple (uid, reason). Where `uid` is the account id,
and `reason` is a string.
"""
for uid in uids:
try:
u = api.get_user(user_id=uid)
logger.warning('This user %r should be inactive', uid)
yield (u, dict(code=-1, message='OK'))
except tweepy.TweepyError as e:
yield (uid, e[0][0])
def check_one_block(api, uids):
"""Check the status of user for one block (<100). """
active_uids, inactive_uids = fast_check(api, uids)
inactive_users_status = list(check_inactive(api, inactive_uids))
return active_uids, inactive_users_status
def check_status(api, large_uids):
"""Check the status of users for any size of users. """
active_uids = []
inactive_users_status = []
for uids in to_bulk(large_uids, size=100):
au, iu = check_one_block(api, uids)
active_uids += au
inactive_users_status += iu
return active_uids, inactive_users_status
def main(twitter_crendient, large_uids):
""" The main function to call check_status. """
# First prepare tweepy API
auth = tweepy.OAuthHandler(twitter_crendient['consumer_key'],
twitter_crendient['consumer_secret'])
auth.set_access_token(twitter_crendient['access_token'],
twitter_crendient['access_token_secret'])
api = tweepy.API(auth, wait_on_rate_limit=True)
# Then, call check_status
active_uids, inactive_user_status = check_status(api, large_uids)
Because of the lack of data, I never test the code. There may be bugs, you should take care of them.
Hope this is helpful.

Deleting Messages in Slack

Sooo, I'm relatively new to programming, and trying to learn how to consume API's. I figured I would start out by building a Slack bot for moderation purposes since I use Slack a lot. For the most part, everything works except for when I try to delete a message. The API returns saying it can't find the message even though it is there in the channel (the slack API uses timestamps to locate said message). The timestamps match, but proclaims the message doesn't exist. Here is my code:
def __init__(self, token):
self.token = token
self.users = {}
self.channels = {}
self.slack = SlackClient(self.token)
self.as_user = True
def connect(self):
if self.slack.rtm_connect():
self.post_message('#test', "*AUTOMOD* _v0.1_")
while True:
# print(self.slack.rtm_read())
self.parse_data(self.slack.rtm_read())
time.sleep(1)
def parse_data(self, payload):
if payload:
if payload[0]['type'] == 'message':
print(("user: {} message: {} channel: {}").format(payload[0]['user'], payload[0]['text'], payload[0]['channel']))
self.handle_message(payload[0])
def handle_message(self, data):
# these users can post whatever they want.
WHITELISTED = ["U4DU2TS2F", "U3VSRJJD8", "U3WLZUTQE", "U3W1Q2ULT"]
# get userid
sent_from = (data['user'])
# ignore whitelisted
if sent_from in WHITELISTED:
return
# if message was sent from someone not in WHITELISTED, delete it
else:
print(("\n\ntimestamp of message: {}").format(data['ts']))
self.delete_message(data['channel'], data['ts'])
self.post_message(data['channel'], "```" + random.choice(dongers) + "```")
def delete_message(self, channel, timestamp):
print(("deleting message in channel '{}'...").format(channel))
print("timestamp check (just to make sure): ", timestamp)
deleted = self.slack.api_call("chat.delete",
channel=channel,
timestamp=timestamp,
as_user=self.as_user
)
if deleted.get('ok'):
print("\nsuccessfully deleted.\n")
else:
print(("\ncouldn't delete message: {}\n").format(deleted['error']))
OUTPUT
timestamp of message: 1488822718.000040
deleting message in channel: 'G4DGYCW2X'
timestamp check (just to make sure...): 1488822718.000040
couldn't delete message: message_not_found
Any ideas on what could be happening? Here is the chat.delete method for context.
EDIT:
Due #pvg's recommendation of "Minimal, Complete, and Verifiable example", I have placed the ENTIRE code from the project in a gist.
One issue might be that you appear to be passing a timestamp parameter to chat.delete, when the API method takes a ts parameter instead. (See docs)

GmailUserSocialAuth email message returns empty message but has snippet

I'm working with the Gmail API in python, getting a request with:
gmail_auth = GmailUserSocialAuth.objects.filter(uid='...')[0]
response = gmail_auth.request('get', '...')
data = response.json()
response - gmail_auth.request('get', '/%s' % data['messages'][0]['id']
message = response.json()
When I print out the message, I get large large objects with all the fields and such. With one of the messages, I get this response:
{
... # a lot of fields
u'sizeEstimate': 10100,
'html_body': '',
'decoded_body': '',
u'snippet': u'Hi —, <content of email>. On Jun 30, 2016..., Ofek Gila <...> wrote: <content of previous email in thread>.',
}
Anyway, the issue is that I know the email was written because it appears in the snippet, but it doesn't show up anywhere else in the message object.
Any idea what could be happening?
Thanks in advance!
Try to use the get method as stated in the Python sample code.
Here's a snippet:
def GetMimeMessage(service, user_id, msg_id):
"""Get a Message and use it to create a MIME Message.
Args:
service: Authorized Gmail API service instance.
user_id: User's email address. The special value "me"
can be used to indicate the authenticated user.
msg_id: The ID of the Message required.
Returns:
A MIME Message, consisting of data from Message.
"""
try:
message = service.users().messages().get(userId=user_id, id=msg_id,
format='raw').execute()
print 'Message snippet: %s' % message['snippet']
msg_str = base64.urlsafe_b64decode(message['raw'].encode('ASCII'))
mime_msg = email.message_from_string(msg_str)
return mime_msg
except errors.HttpError, error:
print 'An error occurred: %s' % error
You may also check this SO thread and this one for additional insight.

Categories

Resources