Zenn
📺

子供のYouTubeアクティビティをチェックできるようにした話

2025/02/19に公開
1

現代の子育てにおいて、YouTubeを完全に遮断することは難しいものです。私が子供の頃、リアルタイムでTVを視聴するか、ビデオやDVDといった録画媒体から限られた選択肢の映像を見ていた子供時代でした。今の子供は、幼き頃からYouTubeのような配信プラットフォームで無尽蔵のコンテンツを薦められています。新規ジャンルの開拓や大人も知らないニッチな知識を得られるというメリットもありますが、隙間時間があればYouTube、外出先でもYouTubeをせがまれて、その中毒性の高さに驚かされることも多々ありました。

とはいえ、小学校低学年くらいまでであれば、親の管理下でYouTubeを見ていましたが、一定の年齢を過ぎると、子供自身でYouTubeの検索やサジェスチョンから新しい動画を見ていくようになっていきます。我が家でも子供がいつの間にかゲームYouTuberばかりを見ている傾向が強くなってきたので、どうしたものかと考えることになりました。幸い、YouTubeではトラッキングデータを抽出することはできるので、そのデータを加工して、アクティビティを確認できるツールを作ってみました。

構想

YouTube履歴から得られる情報はタイトル、投稿者、視聴開始時刻のタイムスタンプの3点でした。また職業柄、結構な数のダッシュボードやレポートシステムを作ってきましたが、多くの場合、利用回数は時間とともに逓減することがほとんどです。レポーティングシステムを作ろうとすると、ついついビジュアライズにこだわったりリッチな情報を付随したくなるものですが、今回の用途では、simple is bestを念頭に、以下2点の切り口で必要な情報を精査しました。

  1. 視聴時間の切り口
    1. 総視聴時間
    2. 日別視聴時間
  2. コンテンツの切り口
    1. チャンネル別視聴時間
    2. 望ましくないコンテンツの抽出

視聴時間

視聴開始時刻のタイムスタンプのみだったので、1つ前のデータと差分比較で視聴時間を計算しています。また視聴間隔が90分以上の場合は1セッションと区切るように設定しました。セッション終わりや1日に1本しか動画を見ていない場合は差分が取れないので、セッション中央値や事前設定された概算数値で埋めるようにしています。

コンテンツ

視聴時間が付与できれば、チャンネル別視聴時間は集計するのみ。望ましくないコンテンツの抽出はOpenAIのAPIを叩いて、"yyyy/mm生まれの子供に悪影響を及ぼすタイトルか"という判定を4段階で行い、Potentially Harmful(Level 3)/Harmful(Level 4)は報告する仕様にしてみました。

実装

今回はGoogleサービスの簡易な自動化ツールであるGAS(Google Apps Script)を利用しています。ダッシュボード作成やメッセンジャーアプリとの連携も視野に入れましたが、数値/コンテンツの確認が主な目的だったので、あまり複雑なものにはせず、ほぼGoogleのエコシステムで完結できたかと思います。

配信内容

GASを使って、シンプルに指定メールアドレスにテキスト+グラフ添付という形で配信する形式にしました。コマンドを実行すると、レポーティング内容は、私と妻宛てにメールで下記の内容が送信されます。(下記例ではタイトル/チャンネル名は架空のものに変更しています)


Here is your latest YouTube watch time report.
Period: 2025-01-24 (Thu) - 2025-02-13 (Wed)

++++++++++++++++++++++++++++++
Total Watch Time: 11h 41m
++++++++++++++++++++++++++++++

■■■ Overview:
YouTube Watch History Analysis:

  • Safe (Level 1): 131 videos
  • Mildly Inappropriate (Level 2): 3 videos
  • Potentially Harmful (Level 3): 1 videos
  • Harmful (Level 4): 0 videos

【コラボ企画】貸切ホテルで狂気のピエロに襲われるかくれんぼがヤバすぎた…【絶叫】

■■■ Top 10 Most-Watched Channels:

  • クラフトライフ: 6h 30m
  • クラフトワールド: 0h 58m
  • ゲームマスターXYZ: 0h 51m
  • akane-iro: 0h 39m
  • MENプレイ: 0h 32m
  • スポーツNOW: 0h 24m
  • クリエイターズTV: 0h 18m
  • オーディンスタジオ: 0h 16m
  • ヒカルのプレイ: 0h 8m
  • フットボールハイライト: 0h 7m

■■■ Daily Watch Time:
Date: TotalWatchTime (StartTime)

  • 2025-01-24 (Thu): 0h 40m (11:27)
  • 2025-01-25 (Fri): ---- (--:--)
  • 2025-01-26 (Sat): 0h 57m (08:49)
  • 2025-01-27 (Sun): ---- (--:--)
  • 2025-01-28 (Mon): ---- (--:--)
  • 2025-01-29 (Tue): 0h 10m (17:04)
  • 2025-01-30 (Wed): ---- (--:--)
  • 2025-01-31 (Thu): ---- (--:--)
  • 2025-02-01 (Fri): 2h 11m (15:52)
  • 2025-02-02 (Sat): 0h 45m (15:30)
  • 2025-02-03 (Sun): 1h 23m (15:59)
  • 2025-02-04 (Mon): ---- (--:--)
  • 2025-02-05 (Tue): 0h 21m (17:00)
  • 2025-02-06 (Wed): ---- (--:--)
  • 2025-02-07 (Thu): 1h 9m (14:55)
  • 2025-02-08 (Fri): ---- (--:--)
  • 2025-02-09 (Sat): 2h 26m (06:53)
  • 2025-02-10 (Sun): ---- (--:--)
  • 2025-02-11 (Mon): ---- (--:--)
  • 2025-02-12 (Tue): ---- (--:--)
  • 2025-02-13 (Wed): 1h 39m (15:30)

====================


pros and cons

作って良かった点

  • 子供の視聴時間がある程度の品質で可視化された
    • 主観を排除して子供とデータで話ができる
    • 過去、YouTubeを見るために早起きしていたのでそれが確認できる
    • 子供の主要な視聴チャンネルが把握できる
      • クラフトゲームを見ているのは知っていたが、かなりゲームで占めていた
      • もう一つの趣味であるサッカーは意外と見ていなかった
  • 悪影響を与えそうなタイトルをチェックできる
    • サジェストにも影響でるので、チェックしたら履歴から削除

いまいちな点

  • 完全自動化ならず
    • YouTubeのTakeoutが隔月×6回でしかスケジュール設定できない
    • 月1回レポートにするなら2月連続で指定日に抽出設定が必要
    • 更には子供アカウントの制約が...
  • 子供アカウントの制約
    • 子供のアカウントからGASで自動操作できない
    • 子供のアカウントではメールも転送できない
  • 取得可能な情報が少ない
    • タイトル/投稿者/視聴開始時間から可能な範囲で作成
    • YouTubeAPIでもう少しリッチな情報取れれば...

レポート作成後、子供と話し合ってみた結果、彼の想像以上に動画を見ていたことに驚いていました。また親のほうも忙しさにかまけて、YouTubeの連続視聴を許容していましたことを反省。子供が動画以外の時間を過ごせるための下準備を進めていこうと思いました。

技術面の話

今回は初めてGASを利用するということだったので、シンプルかつ、Googleサービス優先するという方針で挑みました。利用サービスとその目的は下記のとおり。

  • Google TakeOut: YouTubeデータの取得および定期実行設定
  • ドキュメント: 親子間の視聴データの受け渡しおよび各種データの保管場所
  • スプレッドシート: jsonデータの展開、グラフ作成
  • Gmail: レポートメール送信
  • GAS: 各種サービスの連携/実行およびレポート用数値計算
  • OpenAI: 動画タイトルの危険度判定

データフローはこんな感じで推移します。

実装時に気を付けたポイント

コードはこちらのgit レポジトリにございます。

データ取得

子供専用アカウントでYouTubeを閲覧しているので、視聴履歴データは子供用のアカウントから取得します。子供のアカウント経由でGoogleのTakeOutというサービスへアクセスし、YouTubeの視聴データを抽出することができます。抽出したデータは、メールでダウンロードリンクを添付 or 各種ストレージサービスへ格納という形で受領できます。今回はGoogleドキュメントへの格納を選択しました。

残念ながら、現時点でレポートの完全自動化ができなかった2つの障壁がこのステップにあります。

1つ目は、定期配信設定の頻度。抽出時に設定可能なスケジュールが隔月のみで1年間。1年という期間は許容範囲ですが、隔月だと間隔が空きすぎるので、月間スケジュールでは運用したい場合は2か月連続で抽出設定を行う必要があります。

2つ目は子供用のアカウントの制約。子供用のアカウントだとメールの自動転送やGASが利用禁止となっていました。そのため、メールを親用のアカウントへ転送することやGoogleDocsの親子用データシェアフォルダへの自動配置設定スクリプトなどといったアイディアが使えず、手動格納するはめになりました。
ただ、この点はBoxなどの外部ストレージへの保存も選択可能なので、将来的にはクリアにすることはできるかと思っています。

zipファイルの展開

TakeOutから配布されたデータは多重ネストのzipだったので、GASの標準ユーティリティでは取り出せませんでした。幸い、GAS上でも利用可能なzipライブラリがありましたので、こちらの記事を参考にし、ライブラリ化することで、無事にzipファイルを展開することができました。

視聴データの推定補完

視聴時間は直前データとの差分比較で抽出しています。その場合、以下の問題点が発生しました。なお、以下では一定の連続視聴期間をセッションと表現しています。

  1. セッション間の区切りで数時間-数十時間単位の視聴時間が発生する
  2. 最終タイムスタンプのデータはデータが算出できない

そこで以下の対策を取りました。

  1. セッション内での最終データはセッション内での中央値で穴埋めする
  2. セッション内でデータが1件の場合は20分という暫定値で穴埋めする

こうすることである程度推定ではありますが、現実と近い数値を算出することができるようになりました。

タイトルの有害判定

Googleのエコシステムならgemini使うべきなんでしょうが、あまり使ったことがないので、ある程度、土地勘のあるOpenAIのAPIを活用することにしました。悪影響を及ぼすかどうかは年齢によって基準値が変わりそうだったので、GASのScript PropertiesbirthYearMonthを設定して、実年齢に合わせて判定するようにしています。

function analyzeWithOpenAI(titles, birthYearMonth) {
  var apiKey = PropertiesService.getScriptProperties().getProperty("OPENAI_API_KEY");

  if (!apiKey) {
    Logger.log("❌ API key is missing in Script Properties.");
    return { error: "API key is missing. Please set OPENAI_API_KEY in Script Properties." };
  }

  var url = "https://api.openai.com/v1/chat/completions";

  var riskCounts = { "1 (Safe)": 0, "2 (Mildly inappropriate)": 0, "3 (Potentially harmful)": 0, "4 (Harmful)": 0 };
  var harmfulTitles = [];
  var analyzedResults = [];

  titles.forEach(title => {
    var messages = [
      { role: "user", content: `Evaluate the following YouTube video title for harmful content for a child born in ${birthYearMonth}.
                                 Classify it into four levels:
                                 - 1 (Safe)
                                 - 2 (Mildly inappropriate)
                                 - 3 (Potentially harmful)
                                 - 4 (Harmful)

                                 Return only the numeric classification.

                                 Title: ${title}` }
    ];

    var payload = {
      model: "gpt-4o",
      messages: messages,
      temperature: 0.3
    };

GASの実行時間

OpenAIのAPIを叩く際、タイトルごとに分割して実行しています。途中で500m秒のsleep timeを入れているので、apiリクエスト処理を無視しても720件がGAS上でのmax処理件数です。

今回は2週間で72件程度の量だったので問題ないですが、よりヘビーに利用したり、Short動画のように次々動画を探し回ったりすると破綻します。将来的には5分以上視聴といったフィルタリングをした上で、タイトル判定をしたり、複数タイトルをバッチで処理したりといった工夫が必要になるかと思います。

GASのモジュールシステム

機能別に関数ファイルを用意して、importしようとしたらGASにはモジュールシステムがありませんでした。そのため、関数名だけで該当モジュールファイルを判断しなければならず、ファイルが増えてくると結構大変でした。GAS自体があまり複雑なものを作る想定ではないからでしょうが、ちょっとはまったポイントでした。

今後

手動運用ではありますが、月1回程度はレポートシステム稼働させようかと思っています。親子でYouTubeと向き合うための一つのトピックができたって感じです。本来は本家でもこういうレポートを作ってくれることを望みますが、あくまでnice to haveなので期待薄かなぁ。

参考

1

Discussion

ログインするとコメントできます