Month: February 2021

ゴーストと天気予報と灯(akari.dll)のお話

 - by Don

気象庁の中の人より、非公式ながらAPIっぽいものが利用できるとの発信がありました。

天気予報といえば実に伺かっぽいです。天気予報の機能があるゴーストさんもそれなりに見受けられた気がします。しかしおそらく大体のゴーストはどこかのWebページをスクレイピングしていたのではないかと想像します。しかしこの非公式APIを利用できればもう少しまともな実装ができそうです。

JSONパーサSAORIを求めて

2021-03-22追記。黄桃の誄歌-Etu-様にて「YAYA as SAORI jsonパーサ」が公開されております。追記ここまで。

この非公式APIはJSON形式で出力しているようです。ゴーストから利用するにはJSONを解析したいところです。JSONが扱えるSAORIを探してみましたがなかなか見つかりません。しかしJSONを扱えるSHIORIを見つけました。

夜天燈火

灯(akari.dll)という名のSHIORIで、ドキュメントを見るに、辞書型の変数をサポートしているようです。そして_json2azvという内部関数を使えば辞書型や配列型の変数として読み込んでくれると。また_customrequest関数を独自に定義することでSAORIとして使用することも可能なようです。

ワクワクが止まりません。もはや天気予報などそっちのけでこのSHIORIへの興味が湧いてきました。

サンプルゴーストの639C 灯花さんの中身を見て構造を理解しようと思っていたら、サンプルとしてこんな機能が用意されていました。

akari-weather-forecast

気象庁のWebページをスクレイピングして天気予報してる…。運命に導かれたかのような錯覚に陥ります。

do-you-wanna-do-like-this

「こういうことがやりたいんでしょ?」と言われているような気分です。いや、当初はそうだったけど。今は興味の対象は貴女なのです。

しかも現在の気象庁のWebページは昔と構造が変わっており天気予報機能は正常に動いておりません。スクレイピングの宿命ですね。冒頭の非公式APIを読み取るように変更すれば動きそうです。

fix-bug-if-you-want-akari

ああ、そうか。何と素晴らしいサンプルゴーストなのでしょう。灯の使い方を指南してくれるばかりでなく、練習問題まで用意してくれていたのですね。やってやろうじゃないの。

ghost\master\res\util.azr を以下のように書き換えます。

// 地域を選択させるサクラスクリプトを返します。
string weather_news_arealist()
{
	string	strAreas;
	array	arKeys	=	_dickeyget( dictWeatherAreas );

	strAreas	+= "\_q";
	for( int i=0; arKeys[i]!=nil; i++ )
	{
		if( i%2 == 0 )	strAreas += "\n";
		strAreas	+= "\![*]\q["+arKeys[i]+",OnWeatherNewsAreaSelected,"+arKeys[i]+"]  ";
	}

	return strAreas;
}

// weather_news_arealist()によるサクラスクリプトから、地域を選択した時に呼ばれます。
OnWeatherNewsAreaSelected( dict ref )
{
	_create_thread( "TH_OnWeatherNewsAreaSelected", ref["Reference0"] );
}

// OnWeatherNewsAreaSelectedから別スレッドで起動される関数です。
// 天気予報を取得してキャラクターに喋らせます。
TH_OnWeatherNewsAreaSelected( string strArea )
{
	dict	dictWN	=	weather_news( strArea );
	
	string	strTalk	=	"\0\s[0]\b[2]"+strArea+"の天気は…\n";
	strTalk	+=	dictWN["text"];
	strTalk	+=	"\n\n(※出典:気象庁ホームページ)\e";

	_speak( strTalk );
}

/*
weather_news
・この関数の結果を使用するときは、「出典:気象庁ホームページ」を記載してください。
・引数であるstrAreaNameには転記を知りたい地域の名前を指定して下さい。
 指定できる地域の名前は、dictWeatherAreasという辞書型変数のキー値です。
・dictWeatherAreasはこの関数の後ろにグローバル変数として定義されています。
*/ 
dict weather_news( string strAreaName )
{
	string strAreaFileName = dictWeatherAreas[strAreaName];
	if( strAreaFileName == "" ) strAreaFileName = dictWeatherAreas["東京都"];
	
	array	arHtml = _httpget( "https://www.jma.go.jp/bosai/forecast/data/overview_forecast/"+strAreaFileName+".json", "utf8" );
	dict	dictWeather;
	dictWeather = _json2azv(arHtml);
	
	return dictWeather;
}
	dict dictWeatherAreas = ${
		$("宗谷地方", "011000" ), $("上川・留萌地方", "012000" ),
		$("網走・北見・紋別地方", "013000" ), $("釧路・根室地方", "014100" ),
		$("胆振・日高地方", "015000" ), $("石狩・空知・後志地方", "016000" ),
		$("渡島・檜山地方", "017000" ), $("青森県", "020000" ),
		$("秋田県", "050000" ), $("岩手県", "030000" ),
		$("山形県", "060000" ), $("宮城県", "040000" ),
		$("福島県", "070000" ), $("茨城県", "080000" ),
		$("群馬県", "100000" ), $("栃木県", "090000" ),
		$("埼玉県", "110000" ), $("千葉県", "120000" ),
		$("東京都", "130000" ), $("神奈川県", "140000" ),
		$("山梨県", "190000" ), $("長野県", "200000" ),
		$("新潟県", "150000" ), $("富山県", "160000" ),
		$("石川県", "170000" ), $("福井県", "180000" ),
		$("静岡県", "220000" ), $("岐阜県", "210000" ),
		$("愛知県", "230000" ), $("三重県", "240000" ),
		$("大阪府", "270000" ), $("兵庫県", "280000" ),
		$("京都府", "260000" ), $("滋賀県", "250000" ),
		$("奈良県", "290000" ), $("和歌山県", "300000" ),
		$("島根県", "320000" ), $("広島県", "340000" ),
		$("鳥取県", "310000" ), $("岡山県", "330000" ),
		$("香川県", "370000" ), $("愛媛県", "380000" ),
		$("徳島県", "360000" ), $("高知県", "390000" ),
		$("山口県", "350000" ), $("福岡県", "400000" ),
		$("佐賀県", "410000" ), $("長崎県", "420000" ),
		$("熊本県", "430000" ), $("大分県", "440000" ),
		$("宮崎県", "450000" ), $("鹿児島県", "460100" ),
		$("沖縄本島地方", "471000" ), $("大東島地方", "472000" ),
		$("宮古島地方", "473000" ), $("八重山地方", "474000" )
	};

これで無事に天気予報ができるようになりました。

weather-forecast-fixed

改善点があるとすればdictWeatherAreasの内容もベタ書きするのでなく非公式APIからリストとして取得してくるのが良さそうですが、今回はここまで。習作としてsupplementのNARにしておきます。自分が書いたコード部分のライセンスはパブリックドメインです。

639C_tomoka_supplement.nar

参考

新しい気象庁サイトからJSONデータが取得できる件 | MindTech

ゴーストからTwitterに投稿する(其の参―中級編)

 - by Don

目次

準備

上級編を見てわかる通り、普通にやると準備が大変です。なので中級編では筆者が準備した環境を中継して投稿する方法を紹介します。

「概要」で説明した通り、以下のものが必要になります。

  • BOT用Twitterアカウント
  • Twitter APIの認証キー(2つ)※Twitter開発者登録は不要
    • ACCESS_TOKEN(アプリに対しアカウント毎に割り当てられる)
    • ACCESS_TOKEN_SECRET(アプリに対しアカウント毎に割り当てられる)
  • PHPが使用可能なサーバ(PHP7でなくても可)

BOT用TwitterアカウントとPHPが使用可能なサーバは例によって各自用意してください。

Twitter APIの認証キー(2つ)は以下のリンクから取得してきてください。

UKABOT

適当な名前のPHPファイルを作成してサーバにアップロードします。今回はsample.phpとしました。このファイルにコードを記述していきます。

<?php
define('ACCESS_TOKEN', 'XXXXXXXXXXXXXXXXXXXX');
define('ACCESS_TOKEN_SECRET', 'XXXXXXXXXXXXXXXXXXXX');

$url = 'http://nikolat.starfree.jp/rentalbot/sendtweet.php';
$mes = 'サーバから送信テスト';
$post_data = array('access_token' => ACCESS_TOKEN, 'access_token_secret' => ACCESS_TOKEN_SECRET, 'status' => $mes);

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url); 
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($post_data));
$res =  curl_exec($ch);
curl_close($ch); 

header('Content-Type: text/plain; charset=UTF-8');
print 'おしまい';

文字コードはUTF-8にしておきましょう。XXXの部分は自身が取得した2つのAPIの認証キーに書き換えてください。これを保存してWebブラウザからこのphpファイルがあるURLにアクセスしてみましょう。ブラウザには「おしまい」と表示され、BOTのアカウントに「サーバから送信テスト」と投稿されるはずです。

今はWebブラウザからアクセスしましたが、最終的にはSSPからアクセスし、メッセージを転送することを目標としています。

送信するテキストの部分を以下のように書き換えましょう。

<?php
define('ACCESS_TOKEN', 'XXXXXXXXXXXXXXXXXXXX');
define('ACCESS_TOKEN_SECRET', 'XXXXXXXXXXXXXXXXXXXX');

$url = 'http://nikolat.starfree.jp/rentalbot/sendtweet.php';
$mes = $_POST['message'];
$post_data = array('access_token' => ACCESS_TOKEN, 'access_token_secret' => ACCESS_TOKEN_SECRET, 'status' => $mes);

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url); 
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($post_data));
$res =  curl_exec($ch);
curl_close($ch); 

header('Content-Type: text/plain; charset=UTF-8');
print 'おしまい';

そしてSSPから以下のSakuraScriptを入力します。

\![execute,http-post,【URL】,--param=message=SSPから送信テスト]

【URL】は先ほどWebブラウザからアクセスしたphpファイルがあるURLに置き換えてください。BOTのアカウントに「SSPから送信テスト」と投稿されるはずです。

これでゴーストからTwitterに投稿することができました。

エラー処理

上記のコードは最小限の構成になっています。エラー処理くらいは加えたほうが良いでしょう。

<?php
header('Content-Type: text/plain; charset=UTF-8');

define('ACCESS_TOKEN', 'XXXXXXXXXXXXXXXXXXXX');
define('ACCESS_TOKEN_SECRET', 'XXXXXXXXXXXXXXXXXXXX');

$url = 'http://nikolat.starfree.jp/rentalbot/sendtweet.php';
$key = 'message';
if (!isset($_POST[$key])) {
  print 'メッセージのパラメータ名が違います。';
  exit();
}
$mes = $_POST[$key];
$post_data = array('access_token' => ACCESS_TOKEN, 'access_token_secret' => ACCESS_TOKEN_SECRET, 'status' => $mes);

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url); 
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($post_data));
$res =  curl_exec($ch);
if(curl_error($ch)) {
  print curl_error($ch);
} else {
  print $res;
}
curl_close($ch); 

ここで表示されるはずのメッセージはSakuraScriptを実行したゴーストのフォルダ内 ghost\master\var\sample.php に格納されています。

注意事項

ここで解説した方法は筆者のサーバを経由して投稿する方法になります。筆者がサーバの利用継続手続きを失念したり、筆者のTwitterアカウントが凍結されたりすれば動かなくなりますが、泣かないでください。

ゴーストからTwitterに投稿する(其の弐―上級編)

 - by Don

目次

準備

「概要」で説明した通り、以下のものが必要になります。

  • BOT用Twitterアカウント
  • Twitter APIの認証キー(4つ)※Twitter開発者登録が必要
    • CONSUMER_KEY(アプリ毎に割り当てられる)
    • CONSUMER_SECRET(アプリ毎に割り当てられる)
    • ACCESS_TOKEN(アプリに対しアカウント毎に割り当てられる)
    • ACCESS_TOKEN_SECRET(アプリに対しアカウント毎に割り当てられる)
  • PHP7が使用可能なサーバ
  • OAuthライブラリ(TwitterOAuth)

BOT用Twitterアカウントは各自用意してください。

Twitter APIの認証キー取得についても、Web上に解説記事がたくさんあるのでここで解説することはしません。筆者がざっと探してみた限りでは以下の記事がわかりやすいと思いました。BOTに投稿させるため、BOT自身のアカウントで登録した方が良いです。※Twitterアプリ開発経験者や複数BOT作成予定の人はこの限りではありません

PHP7が使用可能なサーバも各自用意してください。筆者は駄でべWikiを参考にスターサーバー(フリープラン)を利用しています。(PHPのバージョンをしっかり確認してください。PHP5ではダメです。)

最後にTwitterOAuthの入手ですが、ここでは最新版ではなくversion 1.1.0をこちらから入手します。

twitteroauth

理由は、最新版では依存モジュールがあって色々めんどくさいからです。動けばいい、の精神で古いバージョンを使用します。

展開したフォルダはtwitteroauthとリネームしてサーバにアップロードします。同一ディレクトリ内に適当な名前のPHPファイルを作成します。

directory-sample

今回はsample.phpとしました。このファイルにコードを記述していきます。

<?php
require 'twitteroauth/autoload.php';
use Abraham\TwitterOAuth\TwitterOAuth;

define('CONSUMER_KEY', 'XXXXXXXXXXXXXXXXXXXX');
define('CONSUMER_SECRET', 'XXXXXXXXXXXXXXXXXXXX');
define('ACCESS_TOKEN', 'XXXXXXXXXXXXXXXXXXXX');
define('ACCESS_TOKEN_SECRET', 'XXXXXXXXXXXXXXXXXXXX');

$mes = 'サーバから送信テスト';

$twitter = new TwitterOAuth(CONSUMER_KEY, CONSUMER_SECRET, ACCESS_TOKEN, ACCESS_TOKEN_SECRET);

$res = $twitter->post('statuses/update', array('status' => $mes));
print 'おしまい';

文字コードはUTF-8にしておきましょう。XXXの部分は自身が取得した4つのAPIの認証キーに書き換えてください。これを保存してWebブラウザからこのphpファイルがあるURLにアクセスしてみましょう。ブラウザには「おしまい」と表示され、BOTのアカウントに「サーバから送信テスト」と投稿されるはずです。

今はWebブラウザからアクセスしましたが、最終的にはSSPからアクセスし、メッセージを転送することを目標としています。

送信するテキストの部分を以下のように書き換えましょう。

<?php
require 'twitteroauth/autoload.php';
use Abraham\TwitterOAuth\TwitterOAuth;

define('CONSUMER_KEY', 'XXXXXXXXXXXXXXXXXXXX');
define('CONSUMER_SECRET', 'XXXXXXXXXXXXXXXXXXXX');
define('ACCESS_TOKEN', 'XXXXXXXXXXXXXXXXXXXX');
define('ACCESS_TOKEN_SECRET', 'XXXXXXXXXXXXXXXXXXXX');

$mes = $_POST['message'];

$twitter = new TwitterOAuth(CONSUMER_KEY, CONSUMER_SECRET, ACCESS_TOKEN, ACCESS_TOKEN_SECRET);
 
$res = $twitter->post('statuses/update', array('status' => $mes));
print 'おしまい';

そしてSSPから以下のSakuraScriptを入力します。

\![execute,http-post,【URL】,--param=message=SSPから送信テスト]

【URL】は先ほどWebブラウザからアクセスしたphpファイルがあるURLに置き換えてください。BOTのアカウントに「SSPから送信テスト」と投稿されるはずです。

これでゴーストからTwitterに投稿することができました。

エラー処理

上記のコードは最小限の構成になっています。エラー処理くらいは加えたほうが良いでしょう。

<?php
require 'twitteroauth/autoload.php';
use Abraham\TwitterOAuth\TwitterOAuth;

define('CONSUMER_KEY', 'XXXXXXXXXXXXXXXXXXXX');
define('CONSUMER_SECRET', 'XXXXXXXXXXXXXXXXXXXX');
define('ACCESS_TOKEN', 'XXXXXXXXXXXXXXXXXXXX');
define('ACCESS_TOKEN_SECRET', 'XXXXXXXXXXXXXXXXXXXX');

$key = 'message';
if (!isset($_POST[$key])) {
  print 'メッセージのパラメータ名が違います。';
  exit();
}
$mes = $_POST[$key];

$twitter = new TwitterOAuth(CONSUMER_KEY, CONSUMER_SECRET, ACCESS_TOKEN, ACCESS_TOKEN_SECRET);
 
$res = $twitter->post('statuses/update', array('status' => $mes));

if($twitter->getLastHttpCode() == 200) {
  print '投稿が完了しました。';
} else {
  print '投稿に失敗しました。';
}

ここで表示されるはずのメッセージはSakuraScriptを実行したゴーストのフォルダ内 ghost\master\var\sample.php に格納されています。

ゴーストからTwitterに投稿する(其の壱―概要)

 - by Don

本稿では伺かのゴーストからTwitterに投稿する方法について記述します。

ゴーストからのweb拍手送信を応用した内容となっています。
こちらを実践したことがある、または仕組みが理解できることを前提としています。

本稿は以下のように3部に分けて解説していきます。

「概要」では、大まかな仕組みと流れについて説明していきます。

「上級編」では、具体的に必要な準備や記述すべきコードを説明していきます。これが基本であり理想とされる対応となります。

「中級編」では、「上級編」で必要とされた準備のうちの一部を筆者が肩代わりすることで少しだけ敷居を下げた方法を説明していきます。本格的に対応する前に試用したい場合などにご利用ください。

ゴーストから自分の用意したサーバにメッセージを送信する

ゴーストからのweb拍手送信の動作原理を解説すると、SSPのSakuraScriptである\![execute,http-post]を使用してサーバにメッセージを送信し、サーバ側でメッセージを保存することでゴースト作者が閲覧できるようになっています。

send-webclap

ゴーストからTwitterへの投稿は、これの応用で、このサーバからTwitterにメッセージを転送することで実現します。

send-to-twitter

上級編

「上級編」では、PHP7を使用してTwitterにメッセージを転送するプログラムの記述を解説します。そのため以下のものを準備する必要があります。

  • BOT用Twitterアカウント
  • Twitter APIの認証キー(4つ)※Twitter開発者登録が必要
    • CONSUMER_KEY(アプリ毎に割り当てられる)
    • CONSUMER_SECRET(アプリ毎に割り当てられる)
    • ACCESS_TOKEN(アプリに対しアカウント毎に割り当てられる)
    • ACCESS_TOKEN_SECRET(アプリに対しアカウント毎に割り当てられる)
  • PHP7が使用可能なサーバ
  • OAuthライブラリ(TwitterOAuth)

※PHPとはWebプログラミングに使われるプログラミング言語の一つで、伺かで言えば「里々」みたいなものです。コピペで動くように解説するつもりなので必ずしもPHPに習熟する必要はありませんが、自分流にカスタマイズする場合はある程度習得することが望ましいです。なお、筆者はあまりPHPに詳しくありません。

中級編

「中級編」では、筆者のBOT用登録済みアプリを使って筆者サーバを経由して投稿する形式を取ります。そのため必要な準備は以下のものだけになります。

  • BOT用Twitterアカウント
  • Twitter APIの認証キー(2つ)※Twitter開発者登録は不要
    • ACCESS_TOKEN(アプリに対しアカウント毎に割り当てられる)
    • ACCESS_TOKEN_SECRET(アプリに対しアカウント毎に割り当てられる)
  • PHPが使用可能なサーバ(PHP7でなくても可)

forward-to-twitter

GAEで動かしていたアプリの移転

 - by Don

Google App Engineに依存して動作させていたゴーストやプラグインの移転作業を行いました。

びーふれんず
Twitterへの投稿機能を復活させました。ついでに画像投稿機能も復活させました。(@beefriends)
ついっとゅう
スターサーバーへ移転しました。今のところtweetの取得はできますがDMの取得や投稿は正常に動いておりません。昔の古い仕様のままなので折を見て改修したいところです。
【きょうの伺か】+
スターサーバーへ移転しました。(@osusume_ukagaka)

新しいサーバがどの程度使えるかまだ様子見の段階ですが、とりあえず動いたので一安心です。