Google Calendar APIでイベントを取得しTwitter APIでX(Twitter)に自動投稿させる #works

  • スポンサーリンク

  • スポンサーリンク

背景

従来の方法

・公開されているGoogle Calendarでイベントを作成する→IFTTTでトリガー→IFTTTでTwitter(現在のX)に自動投稿する
→その時に方法をまとめた記事:https://www.nakamurayuji.com/archives/126

今回実装するに至った経緯

・TwitterのAPI有料化に伴い、IFTTTのTwitter自動投稿が有料プランに移行してしまった→ https://ifttt.com/explore/updates-to-twitter-2023
・そこで、IFTTTをあきらめ、自力でプログラム作成を行うものとした

今回の実現方法

概要

・Google Calendar APIで公開カレンダーイベントを取得し、Twitter APIによってTwitter(X)に投稿する。そのためのプログラム作成を行いました。

実装概要

・Mac Book Air M1,2020(macOS Ventura 13.4.1)において、Docker + Laravel Sail環境を構築し、バッチプログラムを手動実行する。
※Laravel Sail使わなくても単純にPHPが動作するDockerコンテナだけでも問題ないと思いますが、Sailの紹介も兼ねて。

開発

API事前準備

  • Google Calendar APIの準備を行います。
    Google Cloud Platformにアクセスし、Google Calendar APIの準備を行います
    ・プロジェクト作成
    ・Google Calendar API有効化
    ・認証情報→APIキー作成
    ・サービスアカウント作成
    ・鍵を取得、JSONにてダウンロードしておく。
    ・サービスアカウントを該当カレンダーに追加し権限は、「予定の変更」にする
    ・また該当カレンダーのカレンダーIDも取得しておきます。
  • Twitter API v2の準備を行います。
    開発者ポータルにアクセスし、Twitterアプリの登録を行い下記を取得しておきます。
    ・API key
    ・API Key Secret
    ・AccessToken
    ・AccessTokenSecret
  • アプリケーション開発

  • Mac に Docker Desktop(4.20.1) をインストールします(Docker version 24.0.2)
  • Laravel Framework 10.17.1 / Sail 8.2(PHP 8.2.8)をインストールします
    公式ドキュメント:https://readouble.com/laravel/10.x/ja/installation.html#laravel-and-docker

    % cd {sailインストールフォルダ} 
    % curl -s "https://laravel.build/calendar_twitter" | bash
    
    Thank you! We hope you build something incredible. Dive in with:
    
    % vi ~/.zshrc
    
    # .zshrcの中に下記を記述
    alias sail='[ -f sail ] && bash sail || bash ./vendor/bin/sail'
    
    % sail up -d
    
  • http://localhost/
    にてアクセスして下記のようなLaravel画面が表示されたらここまでOK
  • Laravelの.envファイルに、Google API、Twitter APIの情報などを定義しておきます。

    TWITTER_CONSUMER_KEY=***********
    TWITTER_CUSTOMER_SECRET=***********
    TWITTER_ACCESS_TOKEN=***********
    TWITTER_ACCESS_TOKEN_SECRET=***********
    GOOGLE_CALENDAR_ID=***********
    
  • Google APIの準備で作成しておいた鍵ファイル(JSON)を下記に配置します。
    storage/app/api-key/*********.json
  • Google Calendar APIの PHPライブラリ→googleapis/google-api-php-clientを導入します。
    % sail composer require google/apiclient:^2.12.1
    
  • Twitter APIの PHPライブラリ→TwitterOAuthを導入します。
    % sail composer require abraham/twitteroauth
    
  • プログラミングを行なっていきます。
    • (1)バッチプログラム作成
      sail artisan make:command GoogleToTwitter
      

      ▼App\Console\Commands\GoogleToTwitter

      <?php
      namespace App\Console\Commands;
      use Illuminate\Console\Command;
      use App\Services\TwitterService;
      use App\Services\GoogleCalendarService;
      
      class GoogleToTwitter extends Command
      {
          /**
           * The name and signature of the console command.
           *
           * @var string
           */
          protected $signature = 'batch:google-to-twitter';
      
          /**
           * The console command description.
           *
           * @var string
           */
          protected $description = 'Google Calendar publish to Twitter';
      
          /**
           * Execute the console command.
           */
          public function handle()
          {
              $events = GoogleCalendarService::get();
              foreach ($events as $event) {
                  list($message, $summary) = TwitterService::makeTweets($event);
                  //Twitterに投稿
                  $ret = TwitterService::tweet($message);
                  //$ret正常だったらGoogleCalendarのタイトルから識別子削除
                  if ($ret) {
                      echo 'Tweetしました:' . $message . "\n";
                      GoogleCalendarService::delete_hashtag($summary);
                  }
              }
          }
      }
      
    • (2)Google API使っての取得、更新の実装

      ▼App\Services\GoogleCalendarService.php

      <?php
      namespace App\Services;
      
      use Google_Client;
      use Google_Service_Calendar;
      use Google_Service_Calendar_Event;
      
      class GoogleCalendarService
      {
          /**
           * get from Google Calendar for tweets
           */
          public static function get()
          {
              date_default_timezone_set('Asia/Tokyo');
              $calendarId = env('GOOGLE_CALENDAR_ID');
              //予定取得
              $client = self::getClient(Google_Service_Calendar::CALENDAR_READONLY);
              $service = new Google_Service_Calendar($client);
      
              $optParams = array(
                  'orderBy' => 'updated', //最新更新日時昇順
                  'singleEvents' => true, //ひとつのインスタンス単位で取得する(繰り返しイベントは複数のインスタンスが取得される)
                  'q' => "#public_capture",   //この文字列がある場合のみ投稿対象とする
                  'timeMin' => date('c',strtotime("now")),//現在以降の予定を取得対象
                  'timeMax' => date('c',strtotime("+6 month")),//半年後までの予定を取得対象
              );
              $results = $service->events->listEvents($calendarId, $optParams);
              $events = $results->getItems();
              //取得したカレンダー情報から必要な情報を配列にしていく
              $event_lists = [];
              foreach ($events as $event) {
                  $event_lists[] = [
                      'id' => $event['id'],
                      'summary' => $event['summary'],
                      'link' => $event['htmlLink'],
                      'location' => $event['location'] ? $event['location'] : '',
                  ];
              }
              return $event_lists;
          }
      
          /**
           * update summary of Google Calendar event
           */
          public static function delete_hashtag($summary)
          {
              date_default_timezone_set('Asia/Tokyo');
              $calendarId = env('GOOGLE_CALENDAR_ID');
              //予定取得
              $client = self::getClient(Google_Service_Calendar::CALENDAR_EVENTS);
              $service = new Google_Service_Calendar($client);
              $event = $service->events->get($calendarId, $summary['event_id']);
              $event->setSummary($summary['summary']);    //サマリ置き換え(#ハッシュタグ部分削除して文字列に置換)
              $updatedEvent = $service->events->update($calendarId, $event->getId(), $event);
          }
      
      
          /**
           * Get Google client
           * param $mode
           */
          public static function getClient($mode = Google_Service_Calendar::CALENDAR_READONLY)
          {
              $client = new Google_Client();
      
              //アプリケーション名
              $client->setApplicationName('GoogleCalendarAPI get and update');
              //権限の指定
              $client->setScopes($mode);
              //JSONファイルの指定
              $client->setAuthConfig(storage_path('app/api-key/calendarinfoug-8e5adc4b45a9.json'));
              return $client;
          }
      }
      
      
    • (3)Twitter API使っての取得、更新の実装

      ▼App\Services\TwitterService.php

      <?php
      namespace App\Services;
      use Abraham\TwitterOAuth\TwitterOAuth;
      use Illuminate\Support\Facades\Log;
      class TwitterService
      {
          CONST MAX_STRING_NUMBERS = 140;
          CONST URL_STRING = 23;  //22=URL文字数,改行コードが1文字
          /**
           * Twitter投稿文字列生成.
           */
          public static function makeTweets($event)
          {
              //URL以外の文字数
              $rest_number = self::MAX_STRING_NUMBERS - self::URL_STRING;
      
              //投稿テキスト生成
              $summary = trim(str_replace('#public_capture' , '' ,$event['summary']));
              $message = $summary . "\n" . $event['location'];
              //規定文字数を超えた場合は後半を削除
              if (($rest_number - strlen($message)) < 0) {
                  $message = mb_substr($message, 0, $rest_number);
              }
              $message = $message . "\n" .$event['link'];
              $change_summary = [
                  'event_id' => $event['id'],
                  'summary' => $summary,
              ];
              return [$message, $change_summary];
          }
      
          /**
           * Twitter投稿.
           */
          public static function tweet($message)
          {
              $status = false;
              try {
                  $twitter = new TwitterOAuth(
                      config('twitter.key'),
                      config('twitter.secret'),
                      config('twitter.token'),
                      config('twitter.token_secret'),
                  );
          
                  $twitter->setApiVersion('2');
                  $ret = $twitter->post( 'tweets' , ['text' => $message] , true);
                  $res = get_object_vars($ret);
                  if (isset($res['data'])) {$status = true;}
              } catch (Exception $e) {
                  Log::debug('例外エラー発生:' . print_r($e->getMessage(),true));
              }
              return $status;
          }
      }
      

実装後の運用の流れ

公開のGoogle Calendarのタイトルに「#public_capture」という文字列を含めイベントを作成する
例:

・作成しておいたバッチプログラムを手動実行させる。すると下記処理の流れでイベントが自動投稿される

sail artisan batch:google-to-twitter

(1)Google Calendar APIにてタイトルに「#public_capture」を含むイベントを全件取得する
(2)取得したイベントをTwitter投稿文字数以内に整形、その際に「#public_capture」という文字列は削除する
(3)Twitter APIを用いてTwitter(X)に投稿
例:https://twitter.com/info_by_ug/status/1691064661771481088

(4)投稿成功したら、取得したGoogle Calendarイベントのタイトルから「#public_capture」を削除して、更新する(と重複投稿されない)
例:

  • スポンサーリンク

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

CAPTCHA