YouTubeの急上昇を自前で作ってみたかった📺


はじめに

YouTube をみていて昔の動画が突然伸びているとかあると思います。(テレビ出演とか、有名人が宣伝するとか)

YouTube を投稿してる人はわかると思うんですが、YouTube Studio という管理ツール?の中にチャンネル アナリティクスがあり、色々な分析をしてくれます。投稿している人はこれをみて突然の伸びに気付けるとおもうんですが、ただの視聴者である僕などは気付けません。(気付く必要がないけど)

なので今回は自前で作ってみました。(指定のチャンネルだけ)
自分の好きなチャンネルの人気くらい知っておきたいですからね!!

仕組み

最終的には1週間おきくらいに実行して、「先週の人気動画」のような形での実装を考えてますので、必要なのは 動画のID と 再生回数(前回実行時と今)があればできそうです。データベースほどではないので、今回はスプレッドシートとの連携が簡単な gas をつかって実装しました。

  1. 指定のチャンネルの動画一覧を取得(IDと再生回数)
  2. スプレッドシートから前回実行時の動画一覧を取得
  3. ①と②を比べて差の大きい動画を抽出
  4. 動画を Slack に投稿
  5. ①をスプレッドシートに上書き

簡単に書くとこんな感じです。
新しく公開されたり、非公開になってしまったり、削除されたり、逆に非公開から公開になったりと考慮した方がいいことはあるんですが、↑の実装であれば①と②の両方に動画がない時は差を取るはないので上手く考慮できたと思います。(新着動画は初動で伸びがちだから省いてOK)

ソースコード

const main = () => {

  // 調べるチャンネルのID
  const channelId = 'UCZx7esGXyW6JXn98byfKEIA';

  // 前回実行から一番再生された動画
  let hotVideo = ['', 0];

  const latestVideos = getVideoList(channelId);
  const oldVideos = SpreadsheetApp.getActiveSheet().getDataRange().getValues();

  for (const latestVideo of latestVideos) {
    for (const oldVideo of oldVideos) {
      if (latestVideo[0] === oldVideo[0]) {
        hotVideo = hotVideo[1] < latestVideo[1] - oldVideo[1] ? [latestVideo[0], latestVideo[1] - oldVideo[1]] : hotVideo;
        break;
      }
    }
  }

  // シートを更新
  SpreadsheetApp.getActiveSheet().getRange(1, 1, latestVideos.length, 2).setValues(latestVideos);

  // Slackへ投稿
  postSlack(hotVideo);

};

/**
 * 指定のチャンネルの動画を取得する
 *
 * @param {string} channelId - 取得したいチャンネルIDを指定
 * @returns {Array} - [動画ID, 再生回数] を一要素にした二次元配列
 */
const getVideoList = channelId => {
  const videos = [];
  let nextToken = '';

  while (nextToken !== undefined) {
    const results = YouTube.Search.list('snippet', {
      channelId: channelId,
      maxResults: 50,
      pageToken: nextToken,
    });

    for (const result of results.items) {
      if (result.id.kind === 'youtube#video') {
        const statistics = YouTube.Videos.list('statistics', {
          id: result.id.videoId
        });

        videos.push([result.id.videoId, statistics.items[0].statistics.viewCount]);
      }
    }

    nextToken = results.nextPageToken;
  }

  return videos;
};


/**
 * Slackへ投稿する
 *
 * @param {Array} hotVideo - 投稿する動画のIDと期間で再生された回数
 */
const postSlack = hotVideo => {
  const url = 'https://www.youtube.com/watch?v=' + hotVideo[0];
  const webHookUrl = SLACK_WEBHOOK_URL;
  const name = '急上昇';
  const icon = ':arrow_heading_up:';
  const message = '一番再生された動画' + '(前回から ' + hotVideo[1] + ' 回再生されました。) ' + url;

  const json = {
    'username': name,
    'icon_emoji': icon,
    'text': message
  };

  const payload = JSON.stringify(json);

  const param = {
    'method': 'post',
    'contextType': 'application/json',
    'payload': payload
  };

  UrlFetchApp.fetch(webHookUrl, param);
};

ちょっと説明(?)

// 調べるチャンネルのID
const channelId = 'UCZx7esGXyW6JXn98byfKEIA';

以前にも記事にした ぷらそにか というグループ


// 前回実行から一番再生された動画
let hotVideo = ['', 0];

const latestVideos = getVideoList(channelId);
const oldVideos = SpreadsheetApp.getActiveSheet().getDataRange().getValues();

for (const latestVideo of latestVideos) {
  for (const oldVideo of oldVideos) {
    if (latestVideo[0] === oldVideo[0]) {
      hotVideo = hotVideo[1] < latestVideo[1] - oldVideo[1] ? [latestVideo[0], latestVideo[1] - oldVideo[1]] : hotVideo;
    }
  }
}

人気動画を探すところ、、、綺麗にしてほしい、、、。


const webHookUrl = SLACK_WEBHOOK_URL;

プロジェクトのプロパティにトークンとかを設定すると安全?なのでそうしてます。環境変数的な?

結果

装飾は前に Python ですが書いたので今回はやめました(めんどくs)
↓でいい感じに装飾してるので、
https://qiita.com/bakuwarorin/items/d5fad6f2d64085145a07

スケジュール実行

月曜の朝に動かすようにしました。
たまーに2回以上動いたりしちゃうんですが、問題ないと思います。(変な投稿ができるけど)

おわり

これで人気になった動画を逃さなくなりそうです、よかった。
簡単な仕組みですが作りたいのができたから満足