YouTube 동영상 조회수 및 댓글 추적

코딩 수준: 초급
시간: 20분
프로젝트 유형: 시간 기반 트리거를 사용한 자동화

목표

  • 솔루션의 기능을 이해합니다.
  • 솔루션 내에서 Apps Script 서비스가 하는 작업을 이해합니다.
  • 스크립트를 설정합니다.
  • 스크립트를 실행합니다.

이 솔루션 정보

이 솔루션은 Google Sheets 스프레드시트에서 조회, 좋아요, 댓글을 포함한 공개 YouTube 동영상의 실적을 추적합니다. 트리거는 매일 업데이트된 정보를 확인하고 동영상에 새로운 댓글 활동이 있는 경우 사용자가 질문과 댓글에 참여할 수 있도록 이메일을 보냅니다.

Google 시트의 YouTube 데이터 스크린샷

사용 방법

이 스크립트는 고급 YouTube 서비스를 사용하여 각 시트의 동영상 링크 열에 나열된 동영상 URL의 YouTube 동영상 세부정보 및 통계를 가져옵니다. 나열된 동영상의 댓글 수가 증가하면 스크립트는 시트 이름이 지정된 이메일 주소로 이메일 알림을 보냅니다.

Apps Script 서비스

이 솔루션은 다음 서비스를 사용합니다.

기본 요건

이 샘플을 사용하려면 다음과 같은 기본 요건이 필요합니다.

  • Google 계정 (Google Workspace 계정은 관리자 승인이 필요할 수 있음)
  • 인터넷에 액세스할 수 있는 웹브라우저

스크립트 설정

Apps Script 프로젝트 만들기

  1. 다음 버튼을 클릭하여 YouTube 동영상 조회수 및 댓글 추적 스프레드시트의 사본을 만듭니다. 이 솔루션의 Apps Script 프로젝트는 스프레드시트에 첨부되어 있습니다.
    사본 만들기
  2. 복사된 스프레드시트에서 Your_Email_Address 시트의 이름을 이메일 주소로 변경합니다.
  3. 추적할 YouTube 동영상 URL을 추가하거나 제공된 URL을 테스트에 사용합니다. URL은 www.youtube.com/watch?v= 형식으로 시작해야 합니다.
  4. 확장 프로그램 > Apps Script를 클릭합니다. YouTube가 이미 서비스 아래에 있다면 다음 두 단계로 건너뛸 수 있습니다.
  5. 서비스 옆에 있는 서비스 추가 를 클릭합니다.
  6. 목록에서 YouTube Data API를 선택하고 추가를 클릭합니다.

트리거 만들기

  1. Apps Script 프로젝트에서 트리거 > 트리거 추가를 클릭합니다.
  2. 실행할 함수 선택에서 markVideos를 선택합니다.
  3. 이벤트 소스 선택에서 시간 기반을 선택합니다.
  4. 시간 기반 트리거 선택에서 요일 타이머를 선택합니다.
  5. 시간 선택에서 원하는 시간을 선택합니다.
  6. 메시지가 표시되면 스크립트를 승인합니다. OAuth 동의 화면에 이 앱이 확인되지 않았습니다라는 경고가 표시되면 고급 > {프로젝트 이름}으로 이동(안전하지 않음)을 선택하여 계속 진행합니다.

스크립트 실행

설정한 트리거는 스크립트를 하루에 한 번 실행합니다. 스크립트를 수동으로 실행하여 테스트할 수 있습니다.

  1. Apps Script 프로젝트에서 편집자 를 클릭합니다.
  2. 함수 드롭다운에서 markVideos를 선택합니다.
  3. 실행을 클릭합니다.
  4. 스프레드시트로 다시 전환하여 스크립트가 시트에 추가한 정보를 검토합니다.
  5. 이메일을 열어 댓글이 1개 이상인 동영상 목록이 포함된 이메일을 검토합니다. 스크립트가 향후에 실행되면 스크립트가 마지막으로 실행된 이후 댓글 수가 증가한 동영상이 포함된 이메일만 보냅니다.

코드 검토

이 솔루션의 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 Developer Expert의 도움을 받아 Google에서 관리합니다.

다음 단계