I made a little script to get the UUID's of people who joined my minecraft server, then run them through the PlayerDB API through a post request to: https://playerdb.co/api/player/minecraft/* where the * is a player UUID, however it returns random 404 errors.
Error runs on the player_name_history line and highlights KeyError at 'player':
def getPlayerData(UUID_list):
baseurl = "https://playerdb.co/api/player/minecraft/"
player_names=[]
icon_list = []
for UUID in UUID_list:
response = requests.post(baseurl+UUID)
print("url posted:",baseurl+UUID)
print(response.status_code)
responseObject = response.json()
with open('responseObject.json','w') as f:
json.dump(responseObject, f)
player_name_history = responseObject['data']['player']['meta']['name_history']
for x in player_name_history:
player_name = x['name'] #iterates through all names, last name will not be overrwritten
player_names.append(player_name)
icon_link = responseObject['data']['player']['avatar']
icon_list.append(icon_link)
return player_names, icon_list
for x in player_name_history:
player_name = x['name'] #iterates through all names, last name will not be overrwritten
player_names.append(player_name)
icon_link = responseObject['data']['player']['avatar']
icon_list.append(icon_link)
return player_names, icon_list
You can pass my UUID into the function as a list to test:
['bf22088f-3d5b-45ef-b7dd-8d5bd3cdc310']
Example of it working:
url posted: https://playerdb.co/api/player/minecraft/bf22088f-3d5b-45ef-b7dd-8d5bd3cdc310
200
(['zonkedzolt'], ['https://crafthead.net/avatar/bf22088f-3d5b-45ef-b7dd-8d5bd3cdc310'])
Example of it not working:
url posted: https://playerdb.co/api/player/minecraft/bf22088f-3d5b-45ef-b7dd-8d5bd3cdc310
404
Traceback (most recent call last):
File "g:\*\getPlayerData.py", line 74, in <module>
print(getPlayerData(UUID_list))
File "g:\*\getPlayerData.py", line 58, in getPlayerData
player_name_history = responseObject['data']['player']['meta']['name_history']
KeyError: 'player'
json Dump: {"message": "", "code": "api.404", "data": {}, "success": false, "error": false}
The reason why i suspect it might be my code is because when i get the error, if i ctrl+left click the link on the "url posted:" line it brings up the correct result.
If you are getting error messages from the API like this:
{"message": "", "code": "api.404", "data": {}, "success": false, "error": false}
try requesting each UUID seperately and once you have gotten a good response, try running it with your program. It seems that the API caches UUIDs that have been asked for the first time, but if you ask again too quickly it will return the error above.
Occasionally I still run into the error above, but a re-request sorts it out. You can make a while loop to keep requesting until you recieve a good response. Here is the while loop I made:
goodResponse = False
while goodResponse == False:
response = requests.post(baseurl+UUID)
print("url posted:",baseurl+UUID)
print(response.status_code)
responseObject = response.json()
if "player" in responseObject['data']: #checks if UUID has recieved a good response, otherwise loops until it does.
goodResponse = True #continue code here
Related
ive got an api that takes in an id
http://127.0.0.1:5000/api/v1/resources/books?id=u3qR4Ps4TbATrg97
looks like that
what im trying to do after that is add something to the end of the url, for example
http://127.0.0.1:5000/api/v1/resources/books?id=u3qR4Ps4TbATrg97uid=something
im not 100% sure if this is possible
# Create some test data for our catalog in the form of a list of dictionaries.
books = [
{'id': 'u3qR4Ps4TbATrg97',
'uid': 'what',
'title': 'A Fire Upon the Deep',
'author': 'Vernor Vinge',
'first_sentence': 'The coldsleep itself was dreamless.',
'year_published': '1992'}
]
#app.route('/api/v1/resources/books', methods=['GET'])
def api_id():
# Check if an ID was provided as part of the URL.
# If ID is provided, assign it to a variable.
# If no ID is provided, display an error in the browser.
if 'id' and 'uid' in request.args:
id = str(request.args['id'])
uid = str(request.args['uid'])
else:
return "Error: No id field provided. Please specify an id."
results = []
for book in books:
if book['id'] == id:
results.append(book)
if book['uid'] == uid:
results.append(book)
this is what i have so far, mostly copy pasted from here
thats no the whole file just the important bits i can think of
You can add two inputs inside the GET query like this
http://127.0.0.1:5000/api/v1/resources/books?id=u3qR4Ps4TbATrg97&uid=something
Just put an & in between!
Use request.args.get method to get parameters from your url. Also add & to your URL as a parameter separator.
from flask import Flask, request
app = Flask(__name__)
#app.route('/api/v1/resources/books')
def books():
id_ = request.args.get('id')
uid = request.args.get('uid')
return f'id: {id_}, uid: {uid}'
app.run()
Open http://127.0.0.1:5000/api/v1/resources/books?id=u3qR4Ps4TbATrg97&uid=something
in browser and you'll get:
id: u3qR4Ps4TbATrg97, uid: something
Multiple parameters|arguments are passed with & character. ?params1=5¶ms2=3. For your example: http://127.0.0.1:5000/api/v1/resources/books?id=u3qR4Ps4TbATrg97&uid=what. For the code, I would do:
from flask import Flask, request, jsonify, make_response
app = Flask(__name__)
# Create some test data for our catalog in the form of a list of dictionaries.
books = [
{
"id": "u3qR4Ps4TbATrg97",
"uid": "what",
"title": "A Fire Upon the Deep",
"author": "Vernor Vinge",
"first_sentence": "The coldsleep itself was dreamless.",
"year_published": "1992",
}
]
#app.route("/api/v1/resources/books", methods=["GET"])
def api_id():
# Check if an ID was provided as part of the URL.
# If ID is provided, assign it to a variable.
# If no ID is provided, display an error in the browser.
if set(["id","uid"]).intersection(set(request.args)):
id_ = str(request.args["id"])
uid = str(request.args["uid"])
else:
return make_response(
jsonify({"message": "Error: No id field provided. Please specify an id."}),
400,
)
results = []
for book in books:
if book["id"] == id_:
results.append(book)
if book["uid"] == uid:
results.append(book)
response = make_response(
jsonify({"message": results}),
200,
)
response.headers["Content-Type"] = "application/json"
return response
This would return status code 400 if no match and 200 when match
I am trying to retrieve stripe user's stripeSubscriptionId & stripeCustomerId. Here's my code:
#blueprint.route("/webhook", methods=["POST"]) #confirms whether a user has subscribed or not
def stripe_webhook():
payload = request.get_data(as_text=True)
sig_header = request.headers.get("Stripe-Signature")
try:
event = stripe.Webhook.construct_event(
payload, sig_header, stripe_keys["endpoint_secret"]
)
except ValueError as e:
# Invalid payload
return "Invalid payload", 400
except stripe.error.SignatureVerificationError as e:
# Invalid signature
return "Invalid signature", 400
# Handle the checkout.session.completed event
if event["type"] == "checkout.session.completed":
session = event["data"]["object"]
# Fulfill the purchase...
handle_checkout_session(session)
return "Success", 200
def handle_checkout_session(session):
subID = stripe.Customer.retrieve(id, status)
logging.warn(str(subID))
#blueprint.route("/create-checkout-session")
def create_checkout_session():
domain_url = "http://localhost:5000/"
stripe.api_key = stripe_keys["secret_key"]
try:
checkout_session = stripe.checkout.Session.create(
success_url=domain_url + "success?session_id={CHECKOUT_SESSION_ID}",
cancel_url=domain_url + "cancel",
payment_method_types=["card"],
mode="subscription",
line_items=[
{
"price": stripe_keys["price_id"],
"quantity": 1,
}
]
)
return jsonify({"sessionId": checkout_session["id"]})
except Exception as e:
return jsonify(error=str(e)), 403
Yet I am getting: stripe.error.InvalidRequestError: Could not determine which URL to request: Customer instance has invalid ID: <built-in function id>, <class 'builtin_function_or_method'>. ID should be of type str(orunicode)
I took doc as a reference. However, I can't seem to figure out how to retrieve stripeSubscriptionId & stripeCustomerId from the webhook or in any other way for the past couple of hours despite reading all the docs. I have seen other SO pages but couldn't find one that had a similar concern as mine with a workable solution.
subID = stripe.Customer.retrieve(id, status)
logging.warn(str(subID))
You're not getting the id anywhere here. You likely want to use session["id"]. Also I'm not sure what status is supposed to be there?
First off I am total noob when it comes to writing python so a lot of what I've done thus far has been all learn as I go so with that said:
I have this bit of code here
if buycott_token != '':
print("Looking up in Buycott")
url = "https://www.buycott.com/api/v4/products/lookup"
headers = {
'Content-Type': 'application/json'
}
data={'barcode':upc,
'access_token':buycott_token
}
try:
r = requests.get(url=url, json=data, headers=headers)
j = r.json()
if r.status_code == 200:
print("Buycott found it so now we're going to gather some info here and then add it to the system")
name = j['products'][0]['product_name']
description = j['products'][0]['product_description']
#We now have what we need to add it to grocy so lets do that
#Sometimes buycott returns a success but it never actually does anything so lets just make sure that we have something
if name != '':
add_to_system(upc, name, description)
except requests.exceptions.Timeout:
print("The connection timed out")
except requests.exceptions.TooManyRedirects:
print ("Too many redirects")
except requests.exceptions.RequestException as e:
print e
98% of the time this works just fine with no issues. Then I'll scan something with my barcode scanner and I'll get
Traceback (most recent call last):
File "./barcode_reader.py", line 231, in <module>
increase_inventory(upc)
File "./barcode_reader.py", line 34, in increase_inventory
product_id_lookup(upc)
File "./barcode_reader.py", line 79, in product_id_lookup
upc_lookup(upc)
File "./barcode_reader.py", line 128, in upc_lookup
name = aj['products'][0]['product_name']
KeyError: 'products'
I am certain that it has something to do with how the json is being returned. Problem is when this is thrown it kills the script and that is that. Thank you for your assistance.
The problem is that there is no 'products' key in your response JSON. The workaround could be providing a default value if a 'products' key is not present:
default_value = [{'product_name': '', 'product_description': ''}]
j.get('products', default_value)[0]['product_name']
or you could simply check whether your response has the products key:
if 'products' not in j:
return 'Product not found'
I think this error is because of API doesn't give you proper json in response. So I think you can check from your side if key is in API response or not.
if 'products' in j:
name = j['products'][0]['product_name']
description = j['products'][0]['product_description']
else:
#Whatever you want when 'product' is not in API response
So I'm trying to confirm the location of a given view during testing. The docs say:
You can also use dictionary syntax on the response object to query the
value of any settings in the HTTP headers. For example, you could
determine the content type of a response using
response['Content-Type'].
However, when I put it to use I'm getting a key error. Help please.
Test:
def test_normal_rewardstore_usage(self):
logged_in = self.client.login(username=self.u1.username, password="psst")
response = self.client.get(reverse('rewards:rewardstore'))
location = "http://testserver%s" % (reverse('rewards:rewardpage', kwargs={'company':self.r1.company.slug, 'slug':self.r1.slug}))
self.assertEqual(response.status_code, 200)
self.assertEqual(response['Location'], location)
Error:
Traceback (most recent call last):
File "/app/rewards/tests/test_views.py", line 58, in test_normal_rewardstore_usage
self.assertEqual(response['Location'], location)
File "/app/.heroku/python/lib/python2.7/site-packages/django/http/response.py", line 189, in __getitem__
return self._headers[header.lower()][1]
KeyError: 'location'
View:
def RewardStore_Index(request, template='rewards/reward-store.html', page_template='rewards/rewards_page.html'):
user = User.objects.get(pk=request.user.pk)
contact = Contact.objects.get(user__pk=request.user.pk, is_active=True)
if request.user.is_authenticated():
a = Member.objects.get(pk=request.user.pk)
a = a.account_verified
rewards = Reward.objects.filter(country__iso=contact.get_country)
else:
a = False
g = GeoIP()
c = g.country(request.user)
c = c['country_code']
rewards = Reward.objects.filter(country__iso=c)
context = {
'targetuser': request.user,
'rewards': rewards,
'page_template': page_template,
'email_authenticated': True if a else False,
'notifications': NotificationMap.objects.filter(user__pk=request.user.pk, read=False).prefetch_related('notification', 'notification__users')
}
if request.is_ajax():
template = page_template
return render_to_response(
template, context, context_instance=RequestContext(request))
The headers made available in the response object will vary depending on the server used (source), so it wouldn't surprise me if the django test runner doesn't send back all the headers that you see in production. Also, Location is generally used with redirecting responses, and you're asserting that you receive a 200 first. Are you sure that you should be expecting a Location header in this circumstance?
I'm just wondering if there is any way to write a python script to check to see if a twitch.tv stream is live?
I'm not sure why my app engine tag was removed, but this would be using app engine.
Since all answers are actually outdated as of 2020-05-02, i'll give it a shot. You now are required to register a developer application (I believe), and now you must use an endpoint that requires a user-id instead of a username (as they can change).
See https://dev.twitch.tv/docs/v5/reference/users
and https://dev.twitch.tv/docs/v5/reference/streams
First you'll need to Register an application
From that you'll need to get your Client-ID.
The one in this example is not a real
TWITCH_STREAM_API_ENDPOINT_V5 = "https://api.twitch.tv/kraken/streams/{}"
API_HEADERS = {
'Client-ID' : 'tqanfnani3tygk9a9esl8conhnaz6wj',
'Accept' : 'application/vnd.twitchtv.v5+json',
}
reqSession = requests.Session()
def checkUser(userID): #returns true if online, false if not
url = TWITCH_STREAM_API_ENDPOINT_V5.format(userID)
try:
req = reqSession.get(url, headers=API_HEADERS)
jsondata = req.json()
if 'stream' in jsondata:
if jsondata['stream'] is not None: #stream is online
return True
else:
return False
except Exception as e:
print("Error checking user: ", e)
return False
I hated having to go through the process of making an api key and all those things just to check if a channel was live, so i tried to find a workaround:
As of june 2021 if you send a http get request to a url like https://www.twitch.tv/CHANNEL_NAME, in the response there will be a "isLiveBroadcast": true if the stream is live, and if the stream is not live, there will be nothing like that.
So i wrote this code as an example in nodejs:
const fetch = require('node-fetch');
const channelName = '39daph';
async function main(){
let a = await fetch(`https://www.twitch.tv/${channelName}`);
if( (await a.text()).includes('isLiveBroadcast') )
console.log(`${channelName} is live`);
else
console.log(`${channelName} is not live`);
}
main();
here is also an example in python:
import requests
channelName = '39daph'
contents = requests.get('https://www.twitch.tv/' +channelName).content.decode('utf-8')
if 'isLiveBroadcast' in contents:
print(channelName + ' is live')
else:
print(channelName + ' is not live')
It looks like Twitch provides an API (documentation here) that provides a way to get that info. A very simple example of getting the feed would be:
import urllib2
url = 'http://api.justin.tv/api/stream/list.json?channel=FollowGrubby'
contents = urllib2.urlopen(url)
print contents.read()
This will dump all of the info, which you can then parse with a JSON library (XML looks to be available too). Looks like the value returns empty if the stream isn't live (haven't tested this much at all, nor have I read anything :) ). Hope this helps!
RocketDonkey's fine answer seems to be outdated by now, so I'm posting an updated answer for people like me who stumble across this SO-question with google.
You can check the status of the user EXAMPLEUSER by parsing
https://api.twitch.tv/kraken/streams/EXAMPLEUSER
The entry "stream":null will tell you that the user if offline, if that user exists.
Here is a small Python script which you can use on the commandline that will print 0 for user online, 1 for user offline and 2 for user not found.
#!/usr/bin/env python3
# checks whether a twitch.tv userstream is live
import argparse
from urllib.request import urlopen
from urllib.error import URLError
import json
def parse_args():
""" parses commandline, returns args namespace object """
desc = ('Check online status of twitch.tv user.\n'
'Exit prints are 0: online, 1: offline, 2: not found, 3: error.')
parser = argparse.ArgumentParser(description = desc,
formatter_class = argparse.RawTextHelpFormatter)
parser.add_argument('USER', nargs = 1, help = 'twitch.tv username')
args = parser.parse_args()
return args
def check_user(user):
""" returns 0: online, 1: offline, 2: not found, 3: error """
url = 'https://api.twitch.tv/kraken/streams/' + user
try:
info = json.loads(urlopen(url, timeout = 15).read().decode('utf-8'))
if info['stream'] == None:
status = 1
else:
status = 0
except URLError as e:
if e.reason == 'Not Found' or e.reason == 'Unprocessable Entity':
status = 2
else:
status = 3
return status
# main
try:
user = parse_args().USER[0]
print(check_user(user))
except KeyboardInterrupt:
pass
Here is a more up to date answer using the latest version of the Twitch API (helix). (kraken is deprecated and you shouldn't use GQL since it's not documented for third party use).
It works but you should store the token and reuse the token rather than generate a new token every time you run the script.
import requests
client_id = ''
client_secret = ''
streamer_name = ''
body = {
'client_id': client_id,
'client_secret': client_secret,
"grant_type": 'client_credentials'
}
r = requests.post('https://id.twitch.tv/oauth2/token', body)
#data output
keys = r.json();
print(keys)
headers = {
'Client-ID': client_id,
'Authorization': 'Bearer ' + keys['access_token']
}
print(headers)
stream = requests.get('https://api.twitch.tv/helix/streams?user_login=' + streamer_name, headers=headers)
stream_data = stream.json();
print(stream_data);
if len(stream_data['data']) == 1:
print(streamer_name + ' is live: ' + stream_data['data'][0]['title'] + ' playing ' + stream_data['data'][0]['game_name']);
else:
print(streamer_name + ' is not live');
📚 Explanation
Now, the Twitch API v5 is deprecated. The helix API is in place, where an OAuth Authorization Bearer AND client-id is needed. This is pretty annoying, so I went on a search for a viable workaround, and found one.
🌎 GraphQL
When inspecting Twitch's network requests, while not being logged in, I found out the anonymous API relies on GraphQL. GraphQL is a query language for APIs.
query {
user(login: "USERNAME") {
stream {
id
}
}
}
In the graphql query above, we are querying a user by their login name. If they are streaming, the stream's id will be given. If not, None will be returned.
🐍 The Final Code
The finished python code, in a function, is below. The client-id is taken from Twitch's website. Twitch uses the client-id to fetch information for anonymous users. It will always work, without the need of getting your own client-id.
import requests
# ...
def checkIfUserIsStreaming(username):
url = "https://gql.twitch.tv/gql"
query = "query {\n user(login: \""+username+"\") {\n stream {\n id\n }\n }\n}"
return True if requests.request("POST", url, json={"query": query, "variables": {}}, headers={"client-id": "kimne78kx3ncx6brgo4mv6wki5h1ko"}).json()["data"]["user"]["stream"] else False
I've created a website where you can play with Twitch's GraphQL API. Refer to the GraphQL Docs for help on GraphQL syntax! There's also Twitch GraphQL API documentation on my playground.
Use the twitch api with your client_id as a parameter, then parse the json:
https://api.twitch.tv/kraken/streams/massansc?client_id=XXXXXXX
Twitch Client Id is explained here: https://dev.twitch.tv/docs#client-id,
you need to register a developer application: https://www.twitch.tv/kraken/oauth2/clients/new
Example:
import requests
import json
def is_live_stream(streamer_name, client_id):
twitch_api_stream_url = "https://api.twitch.tv/kraken/streams/" \
+ streamer_name + "?client_id=" + client_id
streamer_html = requests.get(twitch_api_stream_url)
streamer = json.loads(streamer_html.content)
return streamer["stream"] is not None
I'll try to shoot my shot, just in case someone still needs an answer to this, so here it goes
import requests
import time
from twitchAPI.twitch import Twitch
client_id = ""
client_secret = ""
twitch = Twitch(client_id, client_secret)
twitch.authenticate_app([])
TWITCH_STREAM_API_ENDPOINT_V5 = "https://api.twitch.tv/kraken/streams/{}"
API_HEADERS = {
'Client-ID' : client_id,
'Accept' : 'application/vnd.twitchtv.v5+json',
}
def checkUser(user): #returns true if online, false if not
userid = twitch.get_users(logins=[user])['data'][0]['id']
url = TWITCH_STREAM_API_ENDPOINT_V5.format(userid)
try:
req = requests.Session().get(url, headers=API_HEADERS)
jsondata = req.json()
if 'stream' in jsondata:
if jsondata['stream'] is not None:
return True
else:
return False
except Exception as e:
print("Error checking user: ", e)
return False
print(checkUser('michaelreeves'))
https://dev.twitch.tv/docs/api/reference#get-streams
import requests
# ================================================================
# your twitch client id
client_id = ''
# your twitch secret
client_secret = ''
# twitch username you want to check if it is streaming online
twitch_user = ''
# ================================================================
#getting auth token
url = 'https://id.twitch.tv/oauth2/token'
params = {
'client_id':client_id,
'client_secret':client_secret,
'grant_type':'client_credentials'}
req = requests.post(url=url,params=params)
token = req.json()['access_token']
print(f'{token=}')
# ================================================================
#getting user data (user id for example)
url = f'https://api.twitch.tv/helix/users?login={twitch_user}'
headers = {
'Authorization':f'Bearer {token}',
'Client-Id':f'{client_id}'}
req = requests.get(url=url,headers=headers)
userdata = req.json()
userid = userdata['data'][0]['id']
print(f'{userid=}')
# ================================================================
#getting stream info (by user id for example)
url = f'https://api.twitch.tv/helix/streams?user_id={userid}'
headers = {
'Authorization':f'Bearer {token}',
'Client-Id':f'{client_id}'}
req = requests.get(url=url,headers=headers)
streaminfo = req.json()
print(f'{streaminfo=}')
# ================================================================
This solution doesn't require registering an application
import requests
HEADERS = { 'client-id' : 'kimne78kx3ncx6brgo4mv6wki5h1ko' }
GQL_QUERY = """
query($login: String) {
user(login: $login) {
stream {
id
}
}
}
"""
def isLive(username):
QUERY = {
'query': GQL_QUERY,
'variables': {
'login': username
}
}
response = requests.post('https://gql.twitch.tv/gql',
json=QUERY, headers=HEADERS)
dict_response = response.json()
return True if dict_response['data']['user']['stream'] is not None else False
if __name__ == '__main__':
USERS = ['forsen', 'offineandy', 'dyrus']
for user in USERS:
IS_LIVE = isLive(user)
print(f'User {user} live: {IS_LIVE}')
Yes.
You can use Twitch API call https://api.twitch.tv/kraken/streams/YOUR_CHANNEL_NAME and parse result to check if it's live.
The below function returns a streamID if the channel is live, else returns -1.
import urllib2, json, sys
TwitchChannel = 'A_Channel_Name'
def IsTwitchLive(): # return the stream Id is streaming else returns -1
url = str('https://api.twitch.tv/kraken/streams/'+TwitchChannel)
streamID = -1
respose = urllib2.urlopen(url)
html = respose.read()
data = json.loads(html)
try:
streamID = data['stream']['_id']
except:
streamID = -1
return int(streamID)