2017年12月4日月曜日

YouTube Data API を使って YouTube 再生リストを高評価順でソートできる表を作る【C#】

試作品

作ったものはこちら
引数つきでもアクセスできます。
http://tools.ehost.jp/youtube/Playlist/index/PLUL2Tx9e4jQxRfYXbOQB0UYYFXg_z-Yc6


概要

Youtube はチャンネル内の動画は「並べ替え」→「人気の動画」でソートすることができますが、再生リスト単位ではできません。
再生リストのキーを元に Youtube API から再生リストの動画情報を取得し、jQuery プラグインの DataTables でソートできるようにします。
https://www.youtube.com/playlist?list=PLUL2Tx9e4jQxRfYXbOQB0UYYFXg_z-Yc6
の list?= 以下「PLUL2Tx9e4jQxRfYXbOQB0UYYFXg_z-Yc6」が再生リストのキーです。


準備

まずはオフィシャルのドキュメントをご覧頂くのが良いかと思います。


Youtube API を利用するにはまず API キーを取得する必要があります。
API キーはリファラーなどでアクセス制限をつけることができます。

今回は C# と .NET用のGoogle APIのクライアントライブラリを使用します。
nuget パッケージで Google.Apis.YouTube.v3 をプロジェクトにインストールします。


Youtube API

https://www.googleapis.com/youtube/v3/videos?id=28LHGS9hn_g&part=snippet,contentDetails,statistics,status&key=取得したAPIキー
API キーを取得すれば上記のようなURLにアクセスすることで以下のような情報を取ってくる事ができるようになります。

{
 "kind": "youtube#videoListResponse",
 "etag": "\"7991kDR-QPaa9r0pePmDjBEa2h8/IUqB8ABuJ4Ti-yT_NEhPLuW8lKY\"",
 "pageInfo": {
  "totalResults": 1,
  "resultsPerPage": 1
 },
 "items": [
  {
   "kind": "youtube#video",
   "etag": "\"7991kDR-QPaa9r0pePmDjBEa2h8/-iOhnLdrI3sM37vS6XdtYJPit1s\"",
   "id": "28LHGS9hn_g",
   "snippet": {
    "publishedAt": "2014-12-24T06:16:45.000Z",
    "channelId": "UCwQNrx9GQZamvdxVuVgaMtQ",
    "title": "猫 赤ちゃんと初対面Cat First Meeting with Baby",
    "description": "出産のため入院していた嫁と赤ちゃんが帰ってきました。\n嫁との1週間ぶりの対面、赤ちゃんとの初対面。\nさて、シイの反応やいかに・・・?\n\n【日記:http://www.neko-jirushi.com/user_home/diary/diary_detail-84394-46706.html】\n【ブログ:http://catlife0601.blog.fc2.com/】",
    "thumbnails": {
     "default": {
      "url": "https://i.ytimg.com/vi/28LHGS9hn_g/default.jpg",
      "width": 120,
      "height": 90
     },
     "medium": {
      "url": "https://i.ytimg.com/vi/28LHGS9hn_g/mqdefault.jpg",
      "width": 320,
      "height": 180
     },
     "high": {
      "url": "https://i.ytimg.com/vi/28LHGS9hn_g/hqdefault.jpg",
      "width": 480,
      "height": 360
     },
     "standard": {
      "url": "https://i.ytimg.com/vi/28LHGS9hn_g/sddefault.jpg",
      "width": 640,
      "height": 480
     }
    },
    "channelTitle": "catlife",
    "tags": [
     "猫",
     "Cat",
     "シイ",
     "ペット",
     "動物"
    ],
    "categoryId": "15",
    "liveBroadcastContent": "none",
    "localized": {
     "title": "猫 赤ちゃんと初対面Cat First Meeting with Baby",
     "description": "出産のため入院していた嫁と赤ちゃんが帰ってきました。\n嫁との1週間ぶりの対面、赤ちゃんとの初対面。\nさて、シイの反応やいかに・・・?\n\n【日記:http://www.neko-jirushi.com/user_home/diary/diary_detail-84394-46706.html】\n【ブログ:http://catlife0601.blog.fc2.com/】"
    }
   },
   "contentDetails": {
    "duration": "PT1M45S",
    "dimension": "2d",
    "definition": "hd",
    "caption": "false",
    "licensedContent": true,
    "projection": "rectangular"
   },
   "status": {
    "uploadStatus": "processed",
    "privacyStatus": "public",
    "license": "youtube",
    "embeddable": true,
    "publicStatsViewable": true
   },
   "statistics": {
    "viewCount": "1482776",
    "likeCount": "2274",
    "dislikeCount": "81",
    "favoriteCount": "0",
    "commentCount": "59"
   }
  }
 ]
}

取得できるデータはリソースと呼ばれ以下の種類があります。

リソースの種類

activity 特定のユーザーが YouTube サイトで行った操作に関する情報が格納されています。アクティビティ フィードで報告されるユーザー操作は、動画の評価、動画の共有、お気に入りへの動画の追加、チャンネルのお知らせメッセージの投稿などです。
channel 単一の YouTube チャンネルに関する情報が格納されています。
channelBanner 新しくアップロードされた画像をチャンネル用のバナー画像として設定するために使う URL を示します。
guideCategory コンテンツや人気などの指標に基づいて YouTube がチャンネルに関連付けるカテゴリを示します。guideCategory により、YouTube ユーザーが目的のコンテンツを容易に見つけられるようにチャンネルを整理できます。チャンネルは 1 つ以上のガイド カテゴリに関連付けられる場合がありますが、何らかのガイド カテゴリに属することが保証されているわけではありません。
playlist 単一の YouTube 再生リストを表します。再生リストとは、順序を付けて表示し、他のユーザーと共有できる動画のコレクションを指します。
playlistItem 再生リストを構成する動画などのリソースを示します。また、playlistItem リソースには、対象となるリソースが再生リストでどのように使用されるのかを説明する詳細な情報も格納されています。
search result API リクエストで指定した検索パラメータに一致する YouTube 動画、チャンネル、または再生リストに関する情報が格納されています。検索結果は、動画など一意に識別可能なリソースを出力しますが、検索結果自体は永続的なデータを持ちません。
subscription YouTube ユーザーの登録チャンネルに関する情報が格納されています。subscription は、新しい動画がチャンネルに追加された場合や、別のユーザーが YouTube で動画のアップロード、動画の評価、動画へのコメントといった何らかの操作を行った場合に、ユーザーに通知します。
thumbnail リソースに関連付けられたサムネイル画像を示します。
video 単一の YouTube 動画を表します。
videoCategory アップロードした動画に関連付けられているか、関連付けることができるカテゴリを示します。


API に指定できるパラメータはリソースによって異なりますが、主な2つを紹介します。

part パラメータ

必須項目です。カンマ区切りで複数指定することができ、上記 videos リソースの例で言うと、part=snippet,contentDetails,statistics,status の部分です。
取得するデータの items 要素の中身でどの部分を取得するかを指定します。


fields パラメータ

カンマ区切りで複数指定することができ、fields=pageInfo,items(snippet/title,snippet/thumbnails/default) のように記述します。
part パラメータでは子要素を全て含みますが、その内容をさらに詳細にフィルタリングすることができます。
(正直 part と fields は冗長な気もいたしますが…)


.NET用のGoogle APIのクライアントライブラリを使用したデータ取得

.NET用のGoogle APIのクライアントライブラリのガイドやリファレンスはこちら


やりたい事は YouTube 再生リスト内の動画を評価順にソートすることなのですが、まず playlist リソースから再生リストの情報を取ってきます。
続いて playlistItem リソースから再生リスト内の動画情報を取得しますが、この動画情報の中には評価は含まれていません。
面倒ではありますが、いったん動画の Id を取得するにとどめて、その動画 Id で videos リソースから評価情報を取得いたします。
それぞれリソースから取得できる件数は最大50件までなので、50件を越える場合には複数回リソースにアクセスして取得することになります。
コードの一例は以下の通りです。

//YouTubeServiceクラスを生成
var youtube = new YouTubeService(new BaseClientService.Initializer()
{
    ApiKey = "APIキー"
});

//Playlist検索
var requestPlaylist = youtube.Playlists.List("snippet");
requestPlaylist.Id = key;
requestPlaylist.Fields = "pageInfo,items(snippet/title,snippet/thumbnails/default)";
var responsePlaylist = requestPlaylist.Execute();
var vm = responsePlaylist.Items.Select(x => new PlaylistViewModel()
{
    Id = key,
    Title = x.Snippet.Title,
    Url = "https://www.youtube.com/playlist?list=" + key,
    ThumbnailUrl = x.Snippet.Thumbnails.Default__.Url,
    Videos = new List<videoviewmodel>()
}).FirstOrDefault();

//Playlist内の動画id一覧取得
List<string> videoIds = new List<string>();
var requestPlaylistItems = youtube.PlaylistItems.List("id,contentDetails");
var responsePlaylistItems = new PlaylistItemListResponse();
requestPlaylistItems.PlaylistId = key;
requestPlaylistItems.MaxResults = 50;
requestPlaylistItems.Fields = "nextPageToken,pageInfo,items(contentDetails/videoId)";
do
{
    requestPlaylistItems.PageToken = responsePlaylistItems.NextPageToken;
    responsePlaylistItems = requestPlaylistItems.Execute();
    videoIds.AddRange(responsePlaylistItems.Items.Select(x => x.ContentDetails.VideoId));
} while (responsePlaylistItems.NextPageToken != null && responsePlaylistItems.NextPageToken != "");

//動画情報の取得
var requestVideos = youtube.Videos.List("snippet,statistics");
var responseVideos = new VideoListResponse();
var size = 50;
var currentPage = 1;
var totalCount = videoIds.Count;
requestVideos.MaxResults = size;
requestVideos.Fields = "items(id,snippet/publishedAt,snippet/title,snippet/thumbnails/default,statistics/likeCount,statistics/viewCount)";
do
{
    requestVideos.Id = string.Join(",", videoIds.Skip(size*(currentPage-1)).Take(size));
    responseVideos = requestVideos.Execute();
    vm.Videos.AddRange(
        responseVideos.Items.Select(x => new VideoViewModel
        {
            Id = x.Id,
            Title = x.Snippet.Title,
            LikeCount = (int)x.Statistics.LikeCount,
            ViewCount = (int)x.Statistics.ViewCount,
            PublishedAt = (DateTime)x.Snippet.PublishedAt,
            ThumbnailUrl = x.Snippet.Thumbnails.Default__.Url,
            Url = "https://www.youtube.com/watch?v=" + x.Id
        })
        );
    currentPage++;
} while (totalCount > size * (currentPage - 1));

上記では playlistItems からいったん動画 Id のリストを全て取得しましたが、1ページ分(50件)取得する毎に videos リソースからデータを取ってきた方が楽そうですね。

(参考)




0 件のコメント:

コメントを投稿