Skip to content

Instantly share code, notes, and snippets.

@codersquid
Last active August 29, 2015 14:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save codersquid/7b8b5c554d80228f88ad to your computer and use it in GitHub Desktop.
Save codersquid/7b8b5c554d80228f88ad to your computer and use it in GitHub Desktop.
code samples to get video metadata from PyCon Taiwan youtube channel
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import json
from steve.util import (
get_from_config,
get_project_config,
save_json_files
)
from apiclient.discovery import build
from apiclient.errors import HttpError
from oauth2client.tools import argparser
DRAFT = 2
def get_svc():
cfg = get_project_config()
API_KEY = get_from_config(cfg, 'api_key', 'youtube')
API_SERVICE_NAME = get_from_config(cfg, 'api_service_name', 'youtube')
API_VERSION = get_from_config(cfg, 'api_version', 'youtube')
return build(API_SERVICE_NAME, API_VERSION, developerKey=API_KEY)
def youtube_search_channel(svc, channel_id, max_results=50):
options = {
'channelId': channel_id,
'maxResults': max_results,
'part': 'id',
'type': 'video',
}
search_response = svc.search().list(**options).execute()
pages = [[item['id']['videoId'] for item in search_response.get('items', [])]]
while 'nextPageToken' in search_response:
options['pageToken'] = search_response['nextPageToken']
print 'fetching next page {}'.format(options['pageToken'])
search_response = svc.search().list(**options).execute()
pages.append([item['id']['videoId'] for item in search_response.get('items', [])])
return pages
def youtube_get_videos(svc, video_pages):
videos = []
for page in video_pages:
videostr = ','.join(page)
video_response = svc.videos().list(
id=videostr,
part='snippet,player,status'
).execute()
videos.extend([v for v in video_response.get('items', [])])
return videos
def video_results_to_steve_data(video_results):
data = []
for v in video_results:
d = video_to_dict(v)
if 'id' not in v:
# should never happen
continue
fn = 'json/{}.json'.format(v['id'])
data.append((fn, d))
return data
def video_to_dict(video):
"""Converts youtube#video to a python dict
:arg video: youtube#video response
:arg youtube_embed: the embed code to use for YouTube videos or
"object" or "iframe"
:returns: dict
"""
snippet = video.get('snippet', {})
status = video.get('status', {})
player = video.get('player', {})
thumbnails = snippet.get('thumbnails', {})
thumbnail = thumbnails.get('high', {})
cfg = get_project_config()
video_id = video['id']
item = {
'category': get_from_config(cfg, 'category'),
'title': snippet.get('title', ''),
'description': snippet.get('description', ''),
'copyright_text': status.get('license', ''),
'recorded': snippet.get('publishedAt', '')[0:10],
'thumbnail_url': thumbnail.get('url', ''),
'embed': player.get('embedHtml', ''),
'summary': '',
'language': 'Chinese',
'state': DRAFT,
'whiteboard': 'needs editing',
'quality_notes': '',
'slug': '',
'source_url': 'https://www.youtube.com/watch?v={}'.format(video_id)
}
return item
if __name__ == '__main__':
argparser.add_argument("--max-results", help="Max results", default=50)
args = argparser.parse_args()
cfg = get_project_config()
channel_id = get_from_config(cfg, 'channel_id', 'youtube')
svc = get_svc()
try:
video_ids = youtube_search_channel(svc, channel_id, max_results=args.max_results)
videos = youtube_get_videos(svc, video_ids)
data = video_results_to_steve_data(videos)
save_json_files(cfg, data)
except HttpError, e:
print "An HTTP error %d occurred: %s" % (e.resp.status, e.content)
[youtube]
channel_id = UCHLnNgRnfGYDzPCCH8qGbQw
api_key = YOUR_API_KEY
api_service_name = youtube
api_version = v3
url = http://www.youtube.com/channel/UCHLnNgRnfGYDzPCCH8qGbQw
[project]
category = PyCon APAC 2014
url = http://www.youtube.com/channel/UCHLnNgRnfGYDzPCCH8qGbQw
# If the url is a YouTube-based url, you can either have 'object'
# based embed code or 'iframe' based embed code. Specify that
# here.
youtube_embed = object
api_url = http://pyvideo.org/api/v2/
username = USERNAME
api_key = STEVE_KEY
[
{
"etag": "\"PSjn-HSKiX6orvNhGZvglLI2lvk/h0ltrO7NzbXR_PQmgg-5Xlvf4i4\"",
"id": "ySqW4WikKKY",
"kind": "youtube#video",
"player": {
"embedHtml": "<iframe type='text/html' src='http://www.youtube.com/embed/ySqW4WikKKY' width='640' height='360' frameborder='0' allowfullscreen='true'/>"
},
"snippet": {
"categoryId": "28",
"channelId": "UCHLnNgRnfGYDzPCCH8qGbQw",
"channelTitle": "PyCon Taiwan",
"description": "\u6881\u777f\u73ca (Jenny/jsliang) \u7562\u696d\u65bc\u4ea4\u5927\u8cc7\u5de5\uff0c\u76ee\u524d\u5728\u53f0\u7063 IBM \u64d4\u4efb\u5de5\u7a0b\u5e2b\u3002\u540c\u6642\u4e5f\u662f PyConTW 2013 \u7684\u7c4c\u5099\u4eba\u54e1\u4e4b\u4e00\uff0c\u4e3b\u8981\u8ca0\u8cac\u7db2\u7ad9\u524d\u7aef\u7684\u5de5\u4f5c\u3002\u5de5\u4f5c\u4e4b\u9918\u559c\u6b61\u64b0\u5beb\u4e00\u4e9b\u5c0f\u5c08\u6848\u81ea\u5a1b\uff0cGitHub ID: jsliang\n\n\u5c0f\u5b78\u6642\u70ba\u4e86\u88fd\u4f5c\u81ea\u5df1\u7db2\u7ad9\u7684\u7559\u8a00\u7248\u800c\u958b\u59cb\u5b78\u7fd2 PERL\uff0c\u5f9e\u6b64\u8dcc\u5165\u7a0b\u5f0f\u8a2d\u8a08\u7684\u5927\u5751\u3002\u73fe\u5728\u5de5\u4f5c\u4e0a\u4f7f\u7528\u7684\u8a9e\u8a00\u662f C/C++\uff0c\u4f46\u696d\u9918\u6642\u9593\u6700\u611b\u7528\u7684\u662f Python \u4ee5\u53ca HTML/CSS/JavaScript (\u4e5f\u559c\u6b61 SASS \u548c CoffeeScript)\u3002 -- http://www.linkedin.com/in/juishanliang",
"liveBroadcastContent": "none",
"publishedAt": "2013-06-24T03:03:02.000Z",
"thumbnails": {
"default": {
"height": 90,
"url": "https://i.ytimg.com/vi/ySqW4WikKKY/default.jpg",
"width": 120
},
"high": {
"height": 360,
"url": "https://i.ytimg.com/vi/ySqW4WikKKY/hqdefault.jpg",
"width": 480
},
"maxres": {
"height": 720,
"url": "https://i.ytimg.com/vi/ySqW4WikKKY/maxresdefault.jpg",
"width": 1280
},
"medium": {
"height": 180,
"url": "https://i.ytimg.com/vi/ySqW4WikKKY/mqdefault.jpg",
"width": 320
},
"standard": {
"height": 480,
"url": "https://i.ytimg.com/vi/ySqW4WikKKY/sddefault.jpg",
"width": 640
}
},
"title": "[PYCONTW 2013] \u7528 Python \u64b0\u5beb Sublime Text 2 \u7684\u5957\u4ef6 by \u6881\u777f\u73ca"
},
"status": {
"embeddable": true,
"license": "creativeCommon",
"privacyStatus": "public",
"publicStatsViewable": true,
"uploadStatus": "processed"
}
},
{
"etag": "\"PSjn-HSKiX6orvNhGZvglLI2lvk/REoAVw4PD96dk0lorsFFnOUQ3X4\"",
"id": "LSgOpvr8FII",
"kind": "youtube#video",
"player": {
"embedHtml": "<iframe type='text/html' src='http://www.youtube.com/embed/LSgOpvr8FII' width='640' height='360' frameborder='0' allowfullscreen='true'/>"
},
"snippet": {
"categoryId": "28",
"channelId": "UCHLnNgRnfGYDzPCCH8qGbQw",
"channelTitle": "PyCon Taiwan",
"description": "",
"liveBroadcastContent": "none",
"publishedAt": "2013-06-21T12:07:33.000Z",
"thumbnails": {
"default": {
"height": 90,
"url": "https://i.ytimg.com/vi/LSgOpvr8FII/default.jpg",
"width": 120
},
"high": {
"height": 360,
"url": "https://i.ytimg.com/vi/LSgOpvr8FII/hqdefault.jpg",
"width": 480
},
"medium": {
"height": 180,
"url": "https://i.ytimg.com/vi/LSgOpvr8FII/mqdefault.jpg",
"width": 320
},
"standard": {
"height": 480,
"url": "https://i.ytimg.com/vi/LSgOpvr8FII/sddefault.jpg",
"width": 640
}
},
"title": "[PyConTW 2013] MyHDL designing digital hardware with Python by Jan Decaluwe"
},
"status": {
"embeddable": true,
"license": "youtube",
"privacyStatus": "public",
"publicStatsViewable": true,
"uploadStatus": "processed"
}
},
{
"etag": "\"PSjn-HSKiX6orvNhGZvglLI2lvk/TJo0RjnjxfPVQC19eqLTCjR2mvo\"",
"id": "gaR7svYX8pw",
"kind": "youtube#video",
"player": {
"embedHtml": "<iframe type='text/html' src='http://www.youtube.com/embed/gaR7svYX8pw' width='640' height='360' frameborder='0' allowfullscreen='true'/>"
},
"snippet": {
"categoryId": "28",
"channelId": "UCHLnNgRnfGYDzPCCH8qGbQw",
"channelTitle": "PyCon Taiwan",
"description": "Speaker: Wisely Chen\n\nApache Spark\u2122 is a lightning fast engine for large-scale data processing. It is an in-memory cluster computing framework, originally developed in UC Berkeley. Base on it's project page's evaluation, machine learning programming can run program 100x faster than Hadoop MapReduce. And Spark can run on Hadoop 2's YARN cluster manager, and can read any existing Hadoop data. Currently, it supports Scala, Java and Python for writing spark programs. \n\nIn this talk, I will introduce the General concept of Spark's infrastructure, What is RDD (Resilient Distributed Datasets) in Spark, Introduction on PySpark, Demo of PySpark's speed and power, Head-to-head comparison between two programs doing same work - one written in Hadoop MapReduce and the other written using PySpark.\n\nI will also conclude about the companies currently using Spark's use cases.\n\n\nAbout the speaker\n\nSr. Software Engineer for the Yahoo! (Taiwan) Data Team. He has been responsible for data infrastructure, data solution, software release and continuous integration management. He is a lifelong student of software development/testing/deployment/CI processes and best practices and an avid coding puzzle competition fanatic as well as Open Source evangelist",
"liveBroadcastContent": "none",
"publishedAt": "2014-06-24T02:57:16.000Z",
"thumbnails": {
"default": {
"height": 90,
"url": "https://i.ytimg.com/vi/gaR7svYX8pw/default.jpg",
"width": 120
},
"high": {
"height": 360,
"url": "https://i.ytimg.com/vi/gaR7svYX8pw/hqdefault.jpg",
"width": 480
},
"maxres": {
"height": 720,
"url": "https://i.ytimg.com/vi/gaR7svYX8pw/maxresdefault.jpg",
"width": 1280
},
"medium": {
"height": 180,
"url": "https://i.ytimg.com/vi/gaR7svYX8pw/mqdefault.jpg",
"width": 320
},
"standard": {
"height": 480,
"url": "https://i.ytimg.com/vi/gaR7svYX8pw/sddefault.jpg",
"width": 640
}
},
"title": "PySpark: next generation cluster computing engine (PyCon APAC 2014)"
},
"status": {
"embeddable": true,
"license": "youtube",
"privacyStatus": "public",
"publicStatsViewable": true,
"uploadStatus": "processed"
}
},
{
"etag": "\"PSjn-HSKiX6orvNhGZvglLI2lvk/Fg9UAdtbt3L8u203b5cOb5goJoA\"",
"id": "OQiQKBj619U",
"kind": "youtube#video",
"player": {
"embedHtml": "<iframe type='text/html' src='http://www.youtube.com/embed/OQiQKBj619U' width='640' height='360' frameborder='0' allowfullscreen='true'/>"
},
"snippet": {
"categoryId": "28",
"channelId": "UCHLnNgRnfGYDzPCCH8qGbQw",
"channelTitle": "PyCon Taiwan",
"description": "",
"liveBroadcastContent": "none",
"publishedAt": "2013-06-21T14:29:43.000Z",
"thumbnails": {
"default": {
"height": 90,
"url": "https://i.ytimg.com/vi/OQiQKBj619U/default.jpg",
"width": 120
},
"high": {
"height": 360,
"url": "https://i.ytimg.com/vi/OQiQKBj619U/hqdefault.jpg",
"width": 480
},
"medium": {
"height": 180,
"url": "https://i.ytimg.com/vi/OQiQKBj619U/mqdefault.jpg",
"width": 320
},
"standard": {
"height": 480,
"url": "https://i.ytimg.com/vi/OQiQKBj619U/sddefault.jpg",
"width": 640
}
},
"title": "[PyConTW 2013][Lightning Talk] \u7528 Python \u8b93 Raspberry Pi \u548c\u81c9\u90e8\u8fa8\u8b58\u4f86\u500b\u5c0f\u5c0f\u76f8\u9047 (\u66ab\u5b9a) by \u738b\u8208\u8b19"
},
"status": {
"embeddable": true,
"license": "youtube",
"privacyStatus": "public",
"publicStatsViewable": true,
"uploadStatus": "processed"
}
},
{
"etag": "\"PSjn-HSKiX6orvNhGZvglLI2lvk/9U-JwS2CnazP82xqgo3_dQVIhMc\"",
"id": "YjiK5cjw0mY",
"kind": "youtube#video",
"player": {
"embedHtml": "<iframe type='text/html' src='http://www.youtube.com/embed/YjiK5cjw0mY' width='640' height='360' frameborder='0' allowfullscreen='true'/>"
},
"snippet": {
"categoryId": "28",
"channelId": "UCHLnNgRnfGYDzPCCH8qGbQw",
"channelTitle": "PyCon Taiwan",
"description": "David Cramer \u5728\u904e\u53bb\u7684\u516d\u5e74\u4e2d\u6d3b\u8e8d\u65bc Django \u8207 Python \u793e\u7fa4\uff0c\u4e26\u958b\u767c\u4e86\u8a31\u591a\u7684\u958b\u6e90\u7a0b\u5f0f\u5eab\u8207\u5de5\u5177\u3002\u4ed6\u662f Sentry \u7684\u4f5c\u8005\u3002Sentry \u662f\u4e00\u500b\u958b\u653e\u539f\u59cb\u78bc\u7684\u932f\u8aa4\u6536\u96c6\u7cfb\u7d71 (error aggregator)\u3002David \u4e4b\u524d\u5e36\u9818 Disqus \u7684 infrastructure \u5718\u968a\uff0c\u8b93\u7cfb\u7d71\u53ef\u4ee5\u627f\u8f09\u6bcf\u6708\u8fd1\u5341\u5104\u500b\u8a2a\u554f\u8005\u3002\u76ee\u524d\u4ed6\u4efb\u8077\u65bc\u65b0\u5275\u516c\u53f8 tenXer\u3002tenXer \u6e2c\u91cf\u6bcf\u5929\u7684\u5de5\u4f5c\u7e3e\u6548 (performance)\uff0c\u8b93\u4f60\u4e0d\u7ba1\u4f5c\u4ec0\u9ebc\uff0c\u90fd\u80fd\u627e\u51fa\u66f4\u6709\u751f\u7522\u529b\u7684\u5de5\u4f5c\u65b9\u5f0f\u3002 (blog -- http://justcramer.com/)",
"liveBroadcastContent": "none",
"publishedAt": "2013-06-24T03:43:10.000Z",
"thumbnails": {
"default": {
"height": 90,
"url": "https://i.ytimg.com/vi/YjiK5cjw0mY/default.jpg",
"width": 120
},
"high": {
"height": 360,
"url": "https://i.ytimg.com/vi/YjiK5cjw0mY/hqdefault.jpg",
"width": 480
},
"maxres": {
"height": 720,
"url": "https://i.ytimg.com/vi/YjiK5cjw0mY/maxresdefault.jpg",
"width": 1280
},
"medium": {
"height": 180,
"url": "https://i.ytimg.com/vi/YjiK5cjw0mY/mqdefault.jpg",
"width": 320
},
"standard": {
"height": 480,
"url": "https://i.ytimg.com/vi/YjiK5cjw0mY/sddefault.jpg",
"width": 640
}
},
"title": "[PYCONTW 2013] Building to Scale by David Cramer"
},
"status": {
"embeddable": true,
"license": "creativeCommon",
"privacyStatus": "public",
"publicStatsViewable": true,
"uploadStatus": "processed"
}
},
{
"etag": "\"PSjn-HSKiX6orvNhGZvglLI2lvk/owP-vkNUAcycxhsBs6AU7DP6yaw\"",
"id": "BOKcZjI5zME",
"kind": "youtube#video",
"player": {
"embedHtml": "<iframe type='text/html' src='http://www.youtube.com/embed/BOKcZjI5zME' width='640' height='360' frameborder='0' allowfullscreen='true'/>"
},
"snippet": {
"categoryId": "28",
"channelId": "UCHLnNgRnfGYDzPCCH8qGbQw",
"channelTitle": "PyCon Taiwan",
"description": "Speaker: A. Jesse Jiryu Davis\n\nYour Python program is too slow, and you need to optimize it. Where do you start? With the right tools, you can optimize your code where it counts. We'll explore the guts of the Python profiler Yappi to understand its features and limitations, and learn how to find the maximum performance wins with minimum effort.\n\n\nAbout the speaker\n\nAuthor of Motor, an async MongoDB driver for Tornado, and of Toro, a library of locks and queues for Tornado coroutines. Author of GreenletProfiler. Contributor to Python, PyMongo, MongoDB, Yappi, Tornado, and Tulip.",
"liveBroadcastContent": "none",
"publishedAt": "2014-06-27T02:08:16.000Z",
"thumbnails": {
"default": {
"height": 90,
"url": "https://i.ytimg.com/vi/BOKcZjI5zME/default.jpg",
"width": 120
},
"high": {
"height": 360,
"url": "https://i.ytimg.com/vi/BOKcZjI5zME/hqdefault.jpg",
"width": 480
},
"maxres": {
"height": 720,
"url": "https://i.ytimg.com/vi/BOKcZjI5zME/maxresdefault.jpg",
"width": 1280
},
"medium": {
"height": 180,
"url": "https://i.ytimg.com/vi/BOKcZjI5zME/mqdefault.jpg",
"width": 320
},
"standard": {
"height": 480,
"url": "https://i.ytimg.com/vi/BOKcZjI5zME/sddefault.jpg",
"width": 640
}
},
"title": "Python Performance Profiling: The Guts And The Glory (PyCon APAC 2014)"
},
"status": {
"embeddable": true,
"license": "youtube",
"privacyStatus": "public",
"publicStatsViewable": true,
"uploadStatus": "processed"
}
},
{
"etag": "\"PSjn-HSKiX6orvNhGZvglLI2lvk/zI718tjPFJThJZ7odZzbeamvtp0\"",
"id": "iQXt_7ISGHQ",
"kind": "youtube#video",
"player": {
"embedHtml": "<iframe type='text/html' src='http://www.youtube.com/embed/iQXt_7ISGHQ' width='640' height='360' frameborder='0' allowfullscreen='true'/>"
},
"snippet": {
"categoryId": "28",
"channelId": "UCHLnNgRnfGYDzPCCH8qGbQw",
"channelTitle": "PyCon Taiwan",
"description": "About Orange:\n\n\u7c21\u4ecb\nI am Orange :)\n\u73fe\u4efb\u5927\u5b78\u751f\u4e2d\n\n\u5c08\u9577\n\u4e3b\u8981\u5c08\u7cbe Web Security \u4ee5\u53ca Windows \u4e0a\u7684\u5f31\u9ede\u7814\u7a76\n\n\u7d93\u6b77\nCHROOT Security Group \u6210\u54e1\n\u53f0\u7063\u99ed\u5ba2\u5e74\u6703 2009 Wargame \u51a0\u8ecd\n\u884c\u653f\u9662\u570b\u5bb6\u6280\u670d\u4e2d\u5fc3\u8209\u8fa6\u8cc7\u5b89\u6280\u80fd\u91d1\u76fe\u734e\u7b2c\u516d\u5c46\u3001\u7b2c\u4e03\u5c46 \u51a0\u8ecd\n\u65e5\u672c\u8cc7\u5b89\u7814\u8a0e\u6703 AVTOKYO 2011 \u8b1b\u5e2b\n\u9999\u6e2f\u8cc7\u5b89\u7814\u8a0e\u6703 VXConf 2012 \u8b1b\u5e2b\n\u53f0\u7063 WebConf, PHPConf \u8b1b\u5e2b\n\n\u90e8\u843d\u683c\nblog.orange.tw",
"liveBroadcastContent": "none",
"publishedAt": "2013-06-23T00:09:09.000Z",
"thumbnails": {
"default": {
"height": 90,
"url": "https://i.ytimg.com/vi/iQXt_7ISGHQ/default.jpg",
"width": 120
},
"high": {
"height": 360,
"url": "https://i.ytimg.com/vi/iQXt_7ISGHQ/hqdefault.jpg",
"width": 480
},
"maxres": {
"height": 720,
"url": "https://i.ytimg.com/vi/iQXt_7ISGHQ/maxresdefault.jpg",
"width": 1280
},
"medium": {
"height": 180,
"url": "https://i.ytimg.com/vi/iQXt_7ISGHQ/mqdefault.jpg",
"width": 320
},
"standard": {
"height": 480,
"url": "https://i.ytimg.com/vi/iQXt_7ISGHQ/sddefault.jpg",
"width": 640
}
},
"title": "[PyConTW 2013] \u99ed\u5ba2\u770b Django by Orange Tsai"
},
"status": {
"embeddable": true,
"license": "youtube",
"privacyStatus": "public",
"publicStatsViewable": true,
"uploadStatus": "processed"
}
},
{
"etag": "\"PSjn-HSKiX6orvNhGZvglLI2lvk/WkTpuS90ltx1M9qSeIeIfPTHHyI\"",
"id": "kdzL3r-yJZY",
"kind": "youtube#video",
"player": {
"embedHtml": "<iframe type='text/html' src='http://www.youtube.com/embed/kdzL3r-yJZY' width='640' height='360' frameborder='0' allowfullscreen='true'/>"
},
"snippet": {
"categoryId": "28",
"channelId": "UCHLnNgRnfGYDzPCCH8qGbQw",
"channelTitle": "PyCon Taiwan",
"description": "Speaker: A. Jesse Jiryu Davis\n\nPython's asynchronous frameworks, like asyncio, Tornado, and Twisted, are increasingly important for writing high-performance web applications. Even if you're an experienced web programmer, you may lack a rigorous understanding of how these frameworks work and when to use them. Let's see how asyncio's event loop works, and learn how to efficiently handle very large numbers of concurrent connections.\n\nAttendees will learn when to use async and when not to. They'll learn about asyncio, a major new feature in the Python 3.4 standard library: what it is, how it works, and how to use it for high-concurrency web programming.\n\n\nAbout the speaker\n\nAuthor of Motor, an async MongoDB driver for Tornado, and of Toro, a library of locks and queues for Tornado coroutines. Author of GreenletProfiler. Contributor to Python, PyMongo, MongoDB, Yappi, Tornado, and Tulip.",
"liveBroadcastContent": "none",
"publishedAt": "2014-06-26T15:13:03.000Z",
"thumbnails": {
"default": {
"height": 90,
"url": "https://i.ytimg.com/vi/kdzL3r-yJZY/default.jpg",
"width": 120
},
"high": {
"height": 360,
"url": "https://i.ytimg.com/vi/kdzL3r-yJZY/hqdefault.jpg",
"width": 480
},
"maxres": {
"height": 720,
"url": "https://i.ytimg.com/vi/kdzL3r-yJZY/maxresdefault.jpg",
"width": 1280
},
"medium": {
"height": 180,
"url": "https://i.ytimg.com/vi/kdzL3r-yJZY/mqdefault.jpg",
"width": 320
},
"standard": {
"height": 480,
"url": "https://i.ytimg.com/vi/kdzL3r-yJZY/sddefault.jpg",
"width": 640
}
},
"title": "What Is Async, How Does It Work, and When Should I Use It? (PyCon APAC 2014)"
},
"status": {
"embeddable": true,
"license": "youtube",
"privacyStatus": "public",
"publicStatsViewable": true,
"uploadStatus": "processed"
}
},
{
"etag": "\"PSjn-HSKiX6orvNhGZvglLI2lvk/ljIDN15ANx70zut1HjVsh4rGKMI\"",
"id": "FvoLt-YZnb8",
"kind": "youtube#video",
"player": {
"embedHtml": "<iframe type='text/html' src='http://www.youtube.com/embed/FvoLt-YZnb8' width='640' height='360' frameborder='0' allowfullscreen='true'/>"
},
"snippet": {
"categoryId": "28",
"channelId": "UCHLnNgRnfGYDzPCCH8qGbQw",
"channelTitle": "PyCon Taiwan",
"description": "",
"liveBroadcastContent": "none",
"publishedAt": "2013-06-21T12:45:17.000Z",
"thumbnails": {
"default": {
"height": 90,
"url": "https://i.ytimg.com/vi/FvoLt-YZnb8/default.jpg",
"width": 120
},
"high": {
"height": 360,
"url": "https://i.ytimg.com/vi/FvoLt-YZnb8/hqdefault.jpg",
"width": 480
},
"medium": {
"height": 180,
"url": "https://i.ytimg.com/vi/FvoLt-YZnb8/mqdefault.jpg",
"width": 320
},
"standard": {
"height": 480,
"url": "https://i.ytimg.com/vi/FvoLt-YZnb8/sddefault.jpg",
"width": 640
}
},
"title": "[PyConTW 2013] StreetVoice \u5982\u4f55\u5c07\u4e00\u500b Windows&ASP \u7684\u516c\u53f8\u6539\u9020\u70ba Linux&Python by \u66fe\u660e\u8ce2 (\u5c0f\u6d77)"
},
"status": {
"embeddable": true,
"license": "youtube",
"privacyStatus": "public",
"publicStatsViewable": true,
"uploadStatus": "processed"
}
},
{
"etag": "\"PSjn-HSKiX6orvNhGZvglLI2lvk/3rQwJBL8EsCQX7zmc1Q5cjN06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment