追蹤 YouTube 影片觀看次數和留言

程式設計程度:初學者
時間長度:20 分鐘
專案類型:使用時間觸發條件的自動化動作

目標

  • 瞭解解決方案的功能。
  • 瞭解 Apps Script 服務在解決方案中的作用。
  • 設定指令碼。
  • 執行指令碼。

認識這項解決方案

這個解決方案會在 Google 試算表中追蹤公開 YouTube 影片的表現,包括觀看次數、喜歡次數和留言。觸發條件會每天檢查最新資訊,並在影片有新的留言活動時傳送電子郵件,方便你回覆問題和留言。

Google 試算表中 YouTube 資料的螢幕截圖

運作方式

這個指令碼會使用進階 YouTube 服務,針對各工作表「影片連結」欄中列出的影片網址,取得 YouTube 影片詳細資料和統計資料。如果列出的影片留言數量增加,指令碼會傳送電子郵件通知給工作表命名的電子郵件地址。

Apps Script 服務

本解決方案會使用下列服務:

必要條件

如要使用這個範例,您必須具備下列先決條件:

  • Google 帳戶 (Google Workspace 帳戶可能需要管理員核准)。
  • 可連上網際網路的網路瀏覽器。

設定指令碼

建立 Apps Script 專案

  1. 按一下下方按鈕,複製「追蹤 YouTube 影片觀看次數和評論」試算表。這個解決方案的 Apps Script 專案已附加到試算表中。
    「建立副本」
  2. 在複製的試算表中,將「Your_Email_Address」Your_Email_Address工作表的名稱變更為您的電子郵件地址。
  3. 新增要追蹤的 YouTube 影片網址,或使用提供的網址進行測試。網址開頭必須是 www.youtube.com/watch?v= 格式。
  4. 依序按一下「Extensions」>「Apps Script」。如果「服務」下方已列出「YouTube」,請略過接下來的 2 個步驟。
  5. 按一下「服務」旁的「新增服務」圖示
  6. 在清單中選取「YouTube Data API」,然後按一下「新增」

建立觸發條件

  1. 在 Apps Script 專案中,依序按一下「Triggers」>「Add trigger」
  2. 在「請選擇要執行的函式」中,選取「markVideos」
  3. 在「選取事件來源」中,選取「時間驅動」
  4. 在「選取時間型觸發條件類型」中,選取「日計時器」
  5. 在「選取時段」中,選擇偏好的時間。
  6. 出現提示時,請授權執行指令碼。如果 OAuth 同意畫面顯示「This app isn't verified」警告,請依序選取「Advanced」「Go to {Project Name} (unsafe)」(前往「{Project Name}」(不安全))。

執行指令碼

您設定的觸發條件會每天執行一次指令碼。您可以手動執行指令碼來測試。

  1. 在 Apps Script 專案中,按一下「Editor」圖示
  2. 在函式下拉式選單中,選取「markVideos」markVideos
  3. 按一下「執行」
  4. 切換回試算表,查看指令碼新增至試算表的資訊。
  5. 開啟電子郵件,查看內含留言數不為零的影片清單。日後指令碼執行時,只會傳送電子郵件,內容是自上次執行指令碼以來,留言數增加的影片。

查看程式碼

如要查看這個解決方案的 Apps Script 程式碼,請按一下下方的「查看原始碼」

查看原始碼

Code.gs

solutions/automations/youtube-tracker/Code.js
// To learn how to use this script, refer to the documentation:
// https://developers.google.com/apps-script/samples/automations/youtube-tracker

/*
Copyright 2022 Google LLC

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    https://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

// Sets preferences for email notification. Choose 'Y' to send emails, 'N' to skip emails.
const EMAIL_ON = 'Y';

// Matches column names in Video sheet to variables. If the column names change, update these variables.
const COLUMN_NAME = {
  VIDEO: 'Video Link',
  TITLE: 'Video Title',
};

/**
 * Gets YouTube video details and statistics for all
 * video URLs listed in 'Video Link' column in each
 * sheet. Sends email summary, based on preferences above, 
 * when videos have new comments or replies.
 */
function markVideos() {
  let ss = SpreadsheetApp.getActiveSpreadsheet();
  let sheets = SpreadsheetApp.getActiveSpreadsheet().getSheets();

  // Runs through process for each tab in Spreadsheet.
  sheets.forEach(function(dataSheet) {
    let tabName = dataSheet.getName();
    let range = dataSheet.getDataRange();
    let numRows = range.getNumRows();
    let rows = range.getValues();
    let headerRow = rows[0];

    // Finds the column indices.
    let videoColumnIdx = headerRow.indexOf(COLUMN_NAME.VIDEO);
    let titleColumnIdx = headerRow.indexOf(COLUMN_NAME.TITLE);

    // Creates empty array to collect data for email table.
    let emailContent = [];

    // Processes each row in spreadsheet.
    for (let i = 1; i < numRows; ++i) {
      let row = rows[i];
      // Extracts video ID.
      let videoId = extractVideoIdFromUrl(row[videoColumnIdx])
      // Processes each row that contains a video ID.
      if(!videoId) { 
        continue;
      }
      // Calls getVideoDetails function and extracts target data for the video.
      let detailsResponse = getVideoDetails(videoId);
      let title = detailsResponse.items[0].snippet.title;
      let publishDate = detailsResponse.items[0].snippet.publishedAt;
      let publishDateFormatted = new Date(publishDate);
      let views = detailsResponse.items[0].statistics.viewCount;
      let likes = detailsResponse.items[0].statistics.likeCount;
      let comments = detailsResponse.items[0].statistics.commentCount;
      let channel = detailsResponse.items[0].snippet.channelTitle;

      // Collects title, publish date, channel, views, comments, likes details and pastes into tab.
      let detailsRow = [title,publishDateFormatted,channel,views,comments,likes];
      dataSheet.getRange(i+1,titleColumnIdx+1,1,6).setValues([detailsRow]);

      // Determines if new count of comments/replies is greater than old count of comments/replies.
      let addlCommentCount = comments - row[titleColumnIdx+4];

      // Adds video title, link, and additional comment count to table if new counts > old counts.
      if (addlCommentCount > 0) {
        let emailRow = [title,row[videoColumnIdx],addlCommentCount]
        emailContent.push(emailRow);
      }
    }
    // Sends notification email if Content is not empty.
    if (emailContent.length > 0 && EMAIL_ON == 'Y') {
      sendEmailNotificationTemplate(emailContent, tabName);
    }
  });
}

/**
 * Gets video details for YouTube videos
 * using YouTube advanced service.
 */
function getVideoDetails(videoId) {
  let part = "snippet,statistics";
  let response = YouTube.Videos.list(part,
      {'id': videoId});
 return response;
}

/**
 * Extracts YouTube video ID from url.
 * (h/t https://stackoverflow.com/a/3452617)
 */
function extractVideoIdFromUrl(url) {
  let videoId = url.split('v=')[1];
  let ampersandPosition = videoId.indexOf('&');
  if (ampersandPosition != -1) {
    videoId = videoId.substring(0, ampersandPosition);
  }   
 return videoId;
}

/**
 * Assembles notification email with table of video details. 
 * (h/t https://stackoverflow.com/questions/37863392/making-table-in-google-apps-script-from-array)
 */
function sendEmailNotificationTemplate(content, emailAddress) {
  let template = HtmlService.createTemplateFromFile('email');
  template.content = content;
  let msg = template.evaluate();  
  MailApp.sendEmail(emailAddress,'New comments or replies on YouTube',msg.getContent(),{htmlBody:msg.getContent()});
}

email.html

solutions/automations/youtube-tracker/email.html
<!--
 Copyright 2022 Google LLC

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
-->

<body>
  Hello,<br><br>You have new comments and/or replies on videos: <br><br>
  <table border="1">
    <tr>
      <th>Video Title</th>
      <th>Link</th>
      <th>Number of new replies and comments</th>
    </tr>
    <? for (var i = 0; i < content.length; i++) { ?>
    <tr>
      <? for (var j = 0; j < content[i].length; j++) { ?>
      <td align="center"><?= content[i][j] ?></td>
      <? } ?>
    </tr>
    <? } ?>
  </table>
</body>

貢獻者

這個範例是由 Google 維護,並由 Google 開發人員專家提供協助。

後續步驟