Skip to content

Instantly share code, notes, and snippets.

@prinsss
Created July 4, 2019 05:26
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save prinsss/fbe7fe6a9aa42575122a9144b998ce13 to your computer and use it in GitHub Desktop.
Save prinsss/fbe7fe6a9aa42575122a9144b998ce13 to your computer and use it in GitHub Desktop.
Check whether YouTube channel is live streaming.
#!/usr/bin/env python3
# coding: utf-8
import re
import sys
import json
import requests
from retrying import retry
headers = {
'Accept-Language': 'en-US,en;q=0.8',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:67.0) Gecko/20100101 Firefox/67.0',
}
# Apply for a YouTube Data API v3 key here
# https://console.developers.google.com/apis/library/youtube.googleapis.com
api_key = ''
@retry(stop_max_attempt_number=3)
def get(url: str) -> str:
try:
r = requests.get(url, headers=headers)
return r.text
except requests.RequestException:
pass
def get_json(url: str) -> dict:
try:
return json.loads(get(url))
except json.decoder.JSONDecodeError:
pass
def get_video_info(video_id) -> dict:
"""
Returns dict of video info.
YouTube API doc: https://developers.google.com/youtube/v3/docs/videos/list
"""
try:
response = get_json(
f'https://www.googleapis.com/youtube/v3/videos?id={video_id}&'
f'key={api_key}&part=liveStreamingDetails,snippet'
)
item = response['items'][0]
return item
except Exception:
pass
def get_live_video_info_by_channel_id(channel_id: str) -> dict:
"""
Get current live video of given channel.
Returns dict of video info with keys:
{ id, title, description, publishedAt, thumbnails, channelId, channelTitle, liveBroadcastContent, }
YouTube API doc: https://developers.google.com/youtube/v3/docs/search/list
"""
try:
response = get_json(
f'https://www.googleapis.com/youtube/v3/search?part=snippet&'
f'channelId={channel_id}&eventType=live&maxResults=1&type=video&key={api_key}'
)
video_id = response['items'][0]['id']['videoId']
# The video info in the API response is not complete,
# so we request the video info with another API here.
video_info = get_video_info(video_id)
except Exception:
raise
return {
'id': video_id,
**video_info['snippet']
}
def get_live_video_info_from_html(html: str) -> dict:
"""
Extract video info from HTML of channel page.
"""
# regex = r'{"itemSectionRenderer":{"contents":\[{"shelfRenderer":{"title":{"runs":\[{"text":"Live now".+?"content":{"expandedShelfContentsRenderer":{"items":(.+?),"showMoreText":{"runs":\[{"text":"Show more"}]}}}'
regex = r'"contents":\[{"channelFeaturedContentRenderer":{"items":(.+?)}}],"trackingParams"'
json_items = json.loads(re.search(regex, html).group(1))
extract = json_items[0]['videoRenderer']
# print(json.dumps(json_items, indent=2, separators=(',', ': ')))
# exit(0)
if (extract['badges'][0]['metadataBadgeRenderer']['label'] != 'LIVE NOW'):
raise RuntimeError('Not live')
return {
'id': extract['videoId'],
'title': extract['title']['simpleText'],
'description': extract['descriptionSnippet']['simpleText']
}
def check_channel_live_streaming(channel_id: str) -> bool:
try:
html = get(f'https://www.youtube.com/channel/{channel_id}/featured')
if '"label":"LIVE NOW"' in html:
# video_info = get_live_video_info_by_channel_id(channel_id)
video_info = get_live_video_info_from_html(html)
return video_info
else:
return False
except Exception:
raise
# usage: ./check_youtube.py youtube_channel_id
if __name__ == '__main__':
if (len(sys.argv) < 2):
print('usage: ' + sys.argv[0] + ' youtube_channel_id', file=sys.stderr)
exit(1)
channel_id = sys.argv[1]
info = check_channel_live_streaming(channel_id)
if info:
# Same output format as
# youtube-dl --get-id --get-title --get-description
print(info['title'])
print(info['id'])
print(info['description'])
else:
print(f'No live streams for channel {channel_id} available now', file=sys.stderr)
exit(1)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment