Twilio: how to get the subaccount of a phone number? - python

Is it possible that using the phone number I can get the sub account number that this phone number belongs to in Twilio?
I am using the following in python:
import os
from twilio.rest import Client
os.environ['account_sid'] = 'Master_account_SID'
os.environ['auth_token'] = 'Master_account_token'
account_sid = os.environ['account_sid']
auth_token = os.environ['auth_token']
client = Client(account_sid, auth_token)
incoming_phone_num = client.incoming_phone_numbers.list(phone_number='+1XXXXXXXXXX', limit=10)
print(incoming_phone_num.account_sid)
The above returns error "object has no attribute 'account_sid'"
Thanks.

Here is JavaScript but you will get the general idea from the explanation below.
const accountSid = process.env.TWILIO_ACCOUNT_SID;
const authToken = process.env.TWILIO_AUTH_TOKEN;
const client = require('twilio')(accountSid, authToken);
const phoneNumberToSearch = '+1484xxxxxx';
let subAccount;
client.api.accounts.list({status: 'active', limit: 1000})
.then(accounts => {
accounts.forEach(a => {
subAccount = require('twilio')(accountSid, authToken, { accountSid: a.sid });
subAccount.incomingPhoneNumbers
.list({phoneNumber: phoneNumberToSearch, limit: 1})
.then(incomingPhoneNumbers => {
incomingPhoneNumbers.forEach(i => console.log(i.accountSid))
});
})
});
API being used:
REST API: Accounts
To list all the subaccounts
Code Example: List All Active Accounts
IncomingPhoneNumber resource
To iterate through each subaccount looking for the number
Code Example: Filter IncomingPhoneNumbers with exact match
Making a phone call with a Subaccount
The structure to use the main project credentials for the sub-account
Code Example: Make a call from a subaccount (to see how to call the client)

Following the same idea as Alan's answer but since you were writing python:
from twilio.rest import Client
client = Client()
phoneNumber = '+1xxxxxxxxxx'
subaccounts = client.api.accounts.list(status='active', limit=1000)
for subaccount in subaccounts:
subclient = Client(account_sid=subaccount.sid)
numbers = subclient.incoming_phone_numbers.list(phone_number=phoneNumber, limit=1)
if len(numbers) > 0:
print(subaccount.sid, subaccount.friendly_name)
The key takeaway is that the phone numbers are only available in each subaccount so you need to loop through them to find the number you want.
Note that Twilio's python API will take credentials from environment variables itself so you didn't need to do that.

Related

Cloud Functions: How to send a daily email at 10am with an extract of a table?

New to GCP Cloud Functions, and I am wanting to send a daily email at 10am, which would contain an extract of a specific table in BigQuery.
So far, I have written my code to send an email; though, I am not sure what to do in order to send the email at 10 am daily alongside the table extract:
def email(request):
import os
from sendgrid import SendGridAPIClient
from sendgrid.helpers.mail import Mail, Email
from python_http_client.exceptions import HTTPError
sg = SendGridAPIClient(os.environ['EMAIL_API_KEY'])
html_content = "<p>Table XYZ is attached here</p>"
message = Mail(
to_emails="[Destination]#email.com",
from_email=Email('[YOUR]#gmail.com', "Your name"),
subject="Hello world",
html_content=html_content
)
message.add_bcc("[YOUR]#gmail.com")
try:
response = sg.send(message)
return f"email.status_code={response.status_code}"
#expected 202 Accepted
except HTTPError as e:
return e.message
Use Google Cloud Scheduler to activate your Cloud Function and the BigQuery API to extract the data from the particular table to be included in a daily email that is sent out at 10 a.m.
Write the code to extract the data from the particular table in BigQuery and send an email by creating a new Cloud Function in the GCP console. The google-cloud-big query and google-auth packages can be used to communicate with BigQuery.
A sample of the code is shown below:
from google.cloud import bigquery
from google.oauth2 import service_account
from sendgrid import SendGridAPIClient
from sendgrid.helpers.mail import Mail, Email
from python_http_client.exceptions import HTTPError
from datetime import datetime
def email(request):
project_id = '<your-project-id>'
credentials = service_account.Credentials.from_service_account_file('<path-to-your-service-account-key>')
client = bigquery.Client(project=project_id, credentials=credentials)
query = '''
SELECT *
FROM `<your-project-id>.<your-dataset>.<your-table>`
'''
results = client.query(query).result()
html_content = '<table>'
for row in results:
html_content += '<tr>'
for field in row:
html_content += f'<td>{field}</td>'
html_content += '</tr>'
html_content += '</table>'
message = Mail(
to_emails="<destination-email>#example.com",
from_email=Email('<SausageMan123>#gmail.com', "SausageMan123"),
subject="Data extract from BigQuery",
html_content=html_content
)
message.add_bcc("<SausageMan123>#gmail.com")
try:
sg = SendGridAPIClient('<your-sendgrid-api-key>')
response = sg.send(message)
return f"Email sent at {datetime.now()} with status code {response.status_code}"
except HTTPError as e:
return e.message
Create a Cloud Function that takes the information from your BigQuery
table and sends an HTML email. To extract the data, use the BigQuery
API, and to send the email, use a library like Nodemailer.
Build a Pub/Sub topic in Cloud Pub/Sub that will be used to activate
Cloud Function.
Create a new job in Cloud Scheduler that publishes a message to the
Pub/Sub topic every day at 10am. Whatever parameters your Cloud
Function requires to function, such as the table name or email
recipients, can be included in the message payload that you supply.
Sample code for HTML
const {BigQuery} = require('#google-cloud/bigquery');
const nodemailer = require('nodemailer');
exports.dailyEmail = async (message, context) =>
{
const {tableId, recipients} = message.attributes;
const bigquery = new BigQuery();
const [rows] = await bigquery.query(`SELECT * FROM ${tableId}`);
const htmlTable = '<table><thead><tr><th>Column 1</th><th>Column 2</th></tr></thead><tbody>' +
rows.map(row => `<tr><td>${row.column1}</td><td>${row.column2}</td></tr>`).join('') +
'</tbody></table>';
const transporter = nodemailer.createTransport({ });
await transporter.sendMail({
from: 'myemail#example.com',
to: recipients,
subject: 'Daily BigQuery Report',
html: htmlTable,
});
};
updated code
const {BigQuery} = require('#google-cloud/bigquery');
const {Storage} = require('#google-cloud/storage');
const sgMail = require('#sendgrid/mail');
exports.extractDataAndSendEmail = async (event, context) => {
const projectId = 'your-project-id';
const datasetId = 'your-dataset-id';
const tableId = 'your-table-id';
const bucketName = 'your-bucket-name';
const fileName = 'your-file-name.csv';
const recipients = ['recipient1#example.com', 'recipient2#example.com'];
const bigquery = new BigQuery({projectId});
const storage = new Storage({projectId});
const bucket = storage.bucket(bucketName);
const query = `SELECT * FROM ${projectId}.${datasetId}.${tableId}`;
const [rows] = await bigquery.query(query);
const csvData = rows.map(row => Object.values(row).join(',')).join('\n');
const file = bucket.file(fileName);
await file.save(csvData);
sgMail.setApiKey(process.env.SENDGRID_API_KEY);
const msg = {
to: recipients,
from: 'your-sender-email#example.com',
subject: 'Your Daily Extract',
text: 'Attached is your daily extract',
attachments: [
{
content: file.createReadStream(),
filename: fileName,
type: 'text/csv'
}
]
};
await sgMail.send(msg);
};
In Python, you would use the from... import statement to import the BigQuery class from the google.cloud.bigquery package.
Here's an example of how to import BigQuery into Python:
from google.cloud import bigquery
client = bigquery.Client()
bigquery_object = client.bigquery()
As an Example of how you could use the relevant client libraries and implement this functionality in Python, consider the following:
from google.cloud import bigquery
from google.cloud import storage
import sendgrid
from sendgrid.helpers.mail import Mail, Attachment, FileContent, FileName, FileType, Disposition
def extract_data_and_send_email(event, context):
project_id = 'your-project-id'
dataset_id = 'your-dataset-id'
table_id = 'your-table-id'
bucket_name = 'your-bucket-name'
file_name = 'your-file-name.csv'
recipients = ['recipient1#example.com', 'recipient2#example.com']
bigquery_client = bigquery.Client(project=project_id)
query = f'SELECT * FROM `{project_id}.{dataset_id}.{table_id}`'
job = bigquery_client.query(query)
rows = job.result()
csv_data = ''.join([','.join(map(str, row.values()))+'\n' for row in rows])
storage_client = storage.Client(project=project_id)
bucket = storage_client.bucket(bucket_name)
blob = bucket.blob(file_name)
blob.upload_from_string(csv_data)
sendgrid_client = sendgrid.SendGridAPIClient(api_key=process.env.SENDGRID_API_KEY)
message = Mail(from_email='your-sender-email#example.com',
to_emails=recipients,
subject='Your Daily Extract',
plain_text_content='Attached is your daily extract')
file_content = blob.download_as_bytes()
attachment = Attachment(FileContent(file_content),
FileName(file_name),
FileType('text/csv'),
Disposition('attachment'))
message.attachment = attachment
sendgrid_client.send(message)

python flask api to asp.net core api

and greetings.
I am currently trying to integrate a USSD service. I however am stuck with a platform-specific tutorial. the service is written in python flask, while I a developing using asp.net core API. In the tutorial there are certain requirements, I do not understand.
The overview of the connectivity is: here
Below are the explanations of the tutorial.
We have initialized a brand new Flask app. We have made sure that it’s
the main app running. Just below that, we have defined a route that
allows us to actually access our application. We have defined the
methods that we need which is the GET and POST HTTP methods. We have
defined a method/function that will be executed when we are accessing
the route. In this case, we’ve called it ussd_callback. Within the
method we receive some special parameters that we are getting from the
Africa’s Talking API:
session_id gets a unique session ID service_code gets your USSD code
phone_number gets the phone number thats currently accessing the USSD
text carries the user response as they use the USSD application
with the code
from flask import Flask, request
app = Flask(__name__)
response = ""
#app.route('/', methods=['POST', 'GET'])
def ussd_callback():
global response
session_id = request.values.get("sessionId", None)
service_code = request.values.get("serviceCode", None)
phone_number = request.values.get("phoneNumber", None)
text = request.values.get("text", "default")
under the ussd_callback function, one can return a raw string, like bellow:
if text == '':
response = "CON What would you want to check \n"
response += "1. My Account \n"
response += "2. My phone number"
and continue with
elif text == '1':
response = "CON Choose account information you want to view \n"
response += "1. Account number \n"
response += "2. Account balance"
After which, one can return response.
I have created my own solution in ASP.net core 5 API, with the following.
[HttpPost]
[Route("api/[controller]/AddNew")]
public ActionResult<string> AddNew(string venueId)
{
var answer = "";
int number = 0;
if (venueId is null)
{
answer = answer + "CON Please select venue:\n 1.Abor \n 2.Owo \n 3.Ugwueme \n 4.Oweli \n 0.Page 2 ";
return answer;
}
bool isReal = Int32.TryParse(venueId, out number);
if (isReal)
{
if (number == 0)
{
answer = answer = "CON \n 5.Umuogbo Agu \n 6.Awha Imezi \n 7.Ovoko \n 8.Opatu \n 9.Akiyi Umulokpa";
return answer;
}
else if (number > 9)
{
answer = answer + "CON Invalid input, Please select venue:\n 1.Abor \n 2.Owo \n 3.Ugwueme \n 4.Oweli \n 0.Page 2 ";
return answer;
}
}
else
{
answer = answer + "CON Invalid input, Please select venue:\n 1.Abor \n 2.Owo \n 3.Ugwueme \n 4.Oweli \n 0.Page 2 ";
return answer;
}
var data_venue = _db.Venues.Where(m => m.Id == number).FirstOrDefault();
if (data_venue is null)
{
return NotFound();
}
ApiReport data = new ApiReport()
{
DateReported = DateTime.Now,
VenueId = number,
};
var data_report = ReportMapping.ApiReport_To_DataReport(data);
data_report.DateReported = DateTime.Now;
data_report.PhoneNumber = "000";
_db.Reports.Add(data_report);
_db.SaveChanges();
return $"END \n Thank you for informing us about the new case in {data_venue.Name}. \n ";
}
The USSD initially runs fine and shows the base menu, but it will not work if it tries to respond. it is like I am still sending null values into the code. I would love to debug and see the input data myself but this service works with hosted applications.
I feel that I might have the input parameters wrong, or that I am not using proper headers.
Please fam, where have I gone wrong?

How to query the balance of a TRC20 token for a given TRX address?

I'd like to get the balance of a TRC20 token (in this case the WIN token) for a Tron wallet address that owns WIN tokens.
I'm using the Python module tron-api-python and based on what i've read on GitHub and the docs the code for that should look something like this:
from tronapi import Tron
# Source for ABI: https://tronscan.org/#/token20/TLa2f6VPqDgRE67v1736s7bJ8Ray5wYjU7/code
contract_abi = '[{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"spender","type":"address"},{"name":"value","type":"uint256"}],"name":"approve","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"from","type":"address"},{"name":"to","type":"address"},{"name":"value","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"spender","type":"address"},{"name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"to","type":"address"},{"name":"value","type":"uint256"}],"name":"mint","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"value","type":"uint256"}],"name":"burn","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"from","type":"address"},{"name":"value","type":"uint256"}],"name":"burnFrom","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"account","type":"address"}],"name":"addMinter","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"renounceMinter","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"spender","type":"address"},{"name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"to","type":"address"},{"name":"value","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"account","type":"address"}],"name":"isMinter","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"owner","type":"address"},{"name":"spender","type":"address"}],"name":"allowance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"name","type":"string"},{"name":"symbol","type":"string"},{"name":"decimals","type":"uint8"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"account","type":"address"}],"name":"MinterAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"account","type":"address"}],"name":"MinterRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"owner","type":"address"},{"indexed":true,"name":"spender","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Approval","type":"event"}]'
tron = Tron()
contract = tron.trx.contract("TLa2f6VPqDgRE67v1736s7bJ8Ray5wYjU7", abi=contract_abi)
balance = contract.functions.balanceOf("TXRZqGMEXsGTX6AQtcSgYknos93hqw18P7")
print(balance)
But the result i get is:
eth_abi.exceptions.NoEntriesFound: No matching entries for 'address' in encoder registry
You can use this API:
import requests
import json
def get_balance(address, token_symbol):
url = "https://apilist.tronscan.org/api/account"
payload = {
"address": address,
}
res = requests.get(url, params=payload)
trc20token_balances = json.loads(res.text)["trc20token_balances"]
token_balance = next((item for item in trc20token_balances if item["symbol"] == token_symbol), None)
if token_balance == None:
return 0
else:
return int(token_balance["balance"])
The previous response broadcasts a transaction to read a constant function; you don't need to do that if you're only going to read the balance.
Found it myself. This is not the code to get the balance but to send the WIN token so for this to return the balance the function_selector and the parameters would need to change but the rest should be fine since both is based on triggering a smart contract.
tron_kwargs = dict()
tron_kwargs["private_key"] = your_privkey
tron_kwargs["default_address"] = your_base58_address
tron = Tron(**tron_kwargs)
kwargs = dict()
kwargs["contract_address"] = tron.address.to_hex(wink_base58_contract_address)
kwargs["function_selector"] = "transfer(address,uint256)"
kwargs["fee_limit"] = 100000
kwargs["call_value"] = 0
kwargs["parameters"] = [
{
'type': 'address',
'value': tron.address.to_hex(recipients_base58_address)
},
{
'type': 'uint256',
'value': 8000000
}
]
raw_tx = tron.transaction_builder.trigger_smart_contract(**kwargs)
sign = tron.trx.sign(raw_tx["transaction"])
result = tron.trx.broadcast(sign)

BlinkTrade Rest API Returns Nothing (Account Balance Request)

Using python 3.6.1 attempting to connect to foxbit (blinktrade platform) to check account balance I run the code in my terminal and it returns nothing. No traceback or anything. Just blankness. Any ideas? Thanks in advance!
import hashlib
import hmac
import time
import requests
import datetime
def send_msg(msg, env='prod'):
if env == 'prod':
BLINKTRADE_API_URL = 'https://api.blinktrade.com'
else:
BLINKTRADE_API_URL = 'https://api.testnet.blinktrade.com'
BLINKTRADE_API_VERSION = 'v1'
TIMEOUT_IN_SECONDS = 10
key = 'keykeykeykeykey32952592753'
secret = 'secretsecretsecret23535345'
secret2 = bytearray(secret, 'utf8') #turn secret into bytearray
dt = datetime.datetime.now()
nonce = str(int((time.mktime( dt.timetuple() ) + dt.microsecond/1000000.0) * 1000000))
nonce = nonce.encode("utf8")
signature = hmac.new( secret2, nonce, digestmod=hashlib.sha256).hexdigest()
headers = {
'user-agent': 'blinktrade_tools/0.1',
'Content-Type': 'application/json', # You must POST a JSON message
'APIKey': key, # Your APIKey
'Nonce': nonce, # The nonce must be an integer, always greater than the previous one.
'Signature': signature # Use the API Secret to sign the nonce using HMAC_SHA256 algo
}
url = '%s/tapi/%s/message' % (BLINKTRADE_API_URL, BLINKTRADE_API_VERSION)
return requests.post(url, json=msg, verify=True, headers=headers).json()
# Request Balance
msg = {
"MsgType": "U2", # Balance Request
"BalanceReqID": 1 # An ID assigned by you. It can be any number. The response message associated with this request will contain the same ID.}
print(send_msg(msg))
Well, I changed my location and used different wifi. Apparently no problem with the code just a serious latency issue with my wifi.
Use:
# Request Balance
msg = {
"MsgType": "U2",
"BalanceReqID": 1
}
print(send_msg(msg))

Is There Any Way To Check if a Twitch Stream Is Live Using Python?

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)

Categories

Resources