Now, if an event has changed, gancioff reposts it; many other minor changes; bumped version to 0.4

This commit is contained in:
pezcurrel 2024-10-26 23:11:05 +02:00
parent aaec817480
commit fdf343abf7

208
gancioff
View file

@ -18,7 +18,7 @@
$SNAME='GancioFF';
$ENAME=strtolower($SNAME);
$SVERS='0.3';
$SVERS='0.4';
require __DIR__.'/lib/gettlds.php';
require __DIR__.'/lib/mastodon-postLength.php';
@ -127,12 +127,6 @@ always_link_gancio_post = true
-h / --help
Show this help text and exit.
-t / --test
Do a test: {$SNAME} will try as always to read the configuration file, fetch
the defined Mastodon instances info, load the state file and fetch the feed,
but it will post only the first event it may find there, with a visibility of
«direct», even if according to the state file it has already been posted, and
wont update the state file.
-p / --do-post <y|n>
When a state file already exists, this option defaults to «y» («yes»), which
means that {$SNAME} will try to post all the new events it may find in the
@ -145,10 +139,18 @@ always_link_gancio_post = true
refuses to run unless you explicitly set this option to «y» or «n»: this is a
way to prevent you from unintentionally flooding your Mastodon instance with
all the events in the feed.
When “test mode” is active (see the previous option description), setting
this option has no effect.
When “test mode” is active (see the next option description), setting this
option has no effect.
-t / --test
Do a test: {$SNAME} will try as always to read the configuration file, fetch
the defined Mastodon instances info, load the state file and fetch the feed,
but it will post only the first event it may find there, with a visibility of
«direct», even if according to the state file it has already been posted, and
wont update the state file.
This option also activates “verbose mode” (see below).
-v / --verbose
Show some more messages about what the script is doing.
When this option is not set {$SNAME} prints only warning and error messages;
when it is set it also prints informational messages about what its doing.
--
Treat every possible subsequent argument as non-options. Useful only in the
very improbable case your config file is named «--help» or as another option.
@ -195,6 +197,7 @@ for ($i=1; $i<$argc; $i++) {
exit(0);
} elseif ($argv[$i]=='-t' || $argv[$i]=='--test') {
$opts['test']=true;
$opts['verbose']=true;
} elseif ($argv[$i]=='-p' || $argv[$i]=='--do-post') {
if ($i+1>=$argc) dieYoung("Error: option «{$argv[$i]}» requires an argument; use «-h» or «--help» to display help.\n",1);
if ($argv[$i+1]=='y')
@ -235,20 +238,20 @@ if ($opts['update-language-codes']) {
if ($res['content']===false) dieYoung("Error: could not connect to «{$url}».\n",1);
if ($res['httpcode']!='200') dieYoung("Error: got http code «{$res['httpcode']}» from «{$url}».\n",1);
$res=explode("\r\n",$res['content']);
// alb|sqi|sq|Albanian|albanais
// tup|||Tupi languages|tupi, langues
// alb|sqi|sq|Albanian|albanais
// tup|||Tupi languages|tupi, langues
foreach ($res as $val)
if (preg_match('#^[a-z]{3}\|([a-z]{3})?\|([a-z]{2})\|.+\|.+$#',$val,$matches)===1)
$langCodes[]=$matches[2];
$count=count($langCodes);
if (@file_put_contents($langsFP,implode("\n",$langCodes)."\n")===false) dieYoung("Error: could not save the {$count} ISO 639-1 language code(s) i got from «{$url}» into «{$langsFP}».\n",1);
echo "Info: successfully saved the {$count} ISO 639-1 language code(s) i got from «{$url}» into «{$langsFP}».\n";
vecho($opts['verbose'],"Info: successfully saved the {$count} ISO 639-1 language code(s) i got from «{$url}» into «{$langsFP}».\n");
exit(0);
}
if (($langs=@file($langsFP,FILE_IGNORE_NEW_LINES|FILE_SKIP_EMPTY_LINES))===false) dieYoung("Error: could not load ISO 639-1 language codes from «{$langsFP}».\n",1);
if (is_null($confFP)) dieYoung("Error: you have not specified a configuration file; use «-h» or «--help» to display help.\n",1);
echo "Info: trying to load configuration file «{$confFP}» from directory «".getcwd()."».\n";
vecho($opts['verbose'],"Info: trying to load configuration file «{$confFP}» from directory «".getcwd()."».\n");
if (!file_exists($confFP)) dieYoung("Error: «{$confFP}» does not exist.\n",1);
if (!is_file($confFP)) dieYoung("Error: «{$confFP}» is not a file.\n",1);
if (!is_readable($confFP)) dieYoung("Error: «{$confFP}» is not readable.\n",1);
@ -259,7 +262,7 @@ if (!in_array($conf['posts_visibility'],['public', 'unlisted', 'private', 'direc
if (!is_null($conf['max_post_length'])) {
if (preg_match('#^\d+$#',$conf['max_post_length'])!==1 || $conf['max_post_length']+0<10) dieYoung("Error: configuration file: «max_post_length» must be an integer greater than or equal to 10.\n",1);
$conf['max_post_length']+=0;
echo "Info: got «{$conf['max_post_length']}» as «max_post_length» from configuration file.\n";
vecho($opts['verbose'],"Info: got «{$conf['max_post_length']}» as «max_post_length» from configuration file.\n");
}
if (!is_bool($conf['always_link_gancio_post']) && preg_match('#^(true|false)$#',$conf['always_link_gancio_post'])!==1) {
dieYoung("Error: configuration file: «always_link_gancio_post» must be «true» or «false».\n",1);
@ -267,12 +270,12 @@ if (!is_bool($conf['always_link_gancio_post']) && preg_match('#^(true|false)$#',
($conf['always_link_gancio_post']=='true') ? $conf['always_link_gancio_post']=true : $conf['always_link_gancio_post']=false;
}
if ($opts['test']) $conf['posts_visibility']='direct';
echo "Info: got good configuration from configuration file.\n";
vecho($opts['verbose'],"Info: got good configuration from configuration file.\n");
$tldsregex=gettlds(__DIR__.'/storage/tlds.txt',true);
$url="https://{$conf['fedi_hostname']}/api/v2/instance";
echo "Info: trying to fetch instance info from «{$url}».\n";
vecho($opts['verbose'],"Info: trying to fetch instance info from «{$url}».\n");
$res=curl($url,null,["Authorization: Bearer {$conf['fedi_token']}", 'Accept: application/json']);
if ($res['content']===false) dieYoung("Error: could not connect to «{$url}» (error: «{$res['error']}»).\n",1);
$res['content']=@json_decode($res['content'],true);
@ -282,17 +285,17 @@ if ($res['httpcode']!='200') dieYoung("Error: got http code «{$res['httpcode']}
if (!isset($res['content']['configuration']['media_attachments']['image_size_limit'])) dieYoung("Error: JSON from «{$url}» doesnt declare «image_size_limit».\n",1);
if (!is_int($res['content']['configuration']['media_attachments']['image_size_limit'])) dieYoung("Error: JSON from «{$url}» declares «image_size_limit» with an unexpected format.\n",1);
$conf['max_image_size']=$res['content']['configuration']['media_attachments']['image_size_limit']+0;
echo "Info: got «{$conf['max_image_size']}» as «max_image_size» from «{$url}».\n";
vecho($opts['verbose'],"Info: got «{$conf['max_image_size']}» as «max_image_size» from «{$url}».\n");
if (!isset($res['content']['configuration']['statuses']['max_characters'])) dieYoung("Error: JSON from «{$url}» doesnt declare «max_characters».\n",1);
if (!is_int($res['content']['configuration']['statuses']['max_characters'])) dieYoung("Error: JSON from «{$url}» declares «max_characters» with an unexpected format.\n",1);
if (is_null($conf['max_post_length'])) {
$conf['max_post_length']=$res['content']['configuration']['statuses']['max_characters']+0;
echo "Info: got «{$conf['max_post_length']}» as «max_post_length» from «{$url}».\n";
vecho($opts['verbose'],"Info: got «{$conf['max_post_length']}» as «max_post_length» from «{$url}».\n");
}
//print_r($conf);
$guids=[];
echo "Info: trying to load GUIDs of already posted events from state file «{$conf['state_file_absolute_path']}».\n";
vecho($opts['verbose'],"Info: trying to load GUIDs of already posted events from state file «{$conf['state_file_absolute_path']}».\n");
if (file_exists($conf['state_file_absolute_path'])) {
if (!is_file($conf['state_file_absolute_path'])) dieYoung("Error: «{$conf['state_file_absolute_path']}» exists but its not a file.\n",1);
if (!is_readable($conf['state_file_absolute_path'])) dieYoung("Error: «{$conf['state_file_absolute_path']}» exists but its not readable.\n",1);
@ -304,10 +307,10 @@ if (file_exists($conf['state_file_absolute_path'])) {
$i=0;
$fh=fopen($conf['state_file_absolute_path'],'w');
foreach ($buff as $key=>$val) {
if (preg_match('#^(\d+)\t(\S+)$#',$val,$matches)===1) {
if (preg_match('#^(\d+)\t([a-z0-9]{64})\t(\S+)$#',$val,$matches)===1) {
if ($matches[1]+0>=$graceLine) {
fwrite($fh,"{$matches[1]}\t{$matches[2]}\n");
$guids[$matches[2]]=$matches[1];
fwrite($fh,"{$matches[1]}\t{$matches[2]}\t{$matches[3]}\n");
$guids[$matches[3]]=['timestamp'=>$matches[1], 'hash'=>$matches[2]];
} else {
$i++;
}
@ -316,16 +319,17 @@ if (file_exists($conf['state_file_absolute_path'])) {
}
}
fclose($fh);
echo 'Info: got '.count($guids)." GUID(s) for already posted event(s) from state file «{$conf['state_file_absolute_path']}»; removed {$i} line(s) older than one year.\n";
vecho($opts['verbose'],'Info: got '.count($guids)." GUID(s) for already posted event(s) from state file «{$conf['state_file_absolute_path']}»; removed {$i} line(s) older than one year.\n");
} elseif (is_null($opts['do-post']) && !$opts['test']) {
dieYoung("Error: state file «{$conf['state_file_absolute_path']}» doesnt exist yet, so this is probably a first run on feed «{$conf['feed_url']}»; thus, all the events {$SNAME} may find in the feed will be considered new and, as a precaution against flooding your local timeline, you have to explicitly declare whether you want it to post them all, or not, by explicitly setting option «-p» or «--do-post» to «y» («yes») or «n» («no»); mind that in both cases they will be recorded as posted in the state file, and wont be posted again on subsequent runs (you can use «-h» or «--help» to display help).\n",1);
echo "State file «{$conf['state_file_absolute_path']}» doesnt exist yet, so this is probably a first run on feed «{$conf['feed_url']}»; thus, all the events {$SNAME} may find in the feed will be considered new and, as a precaution against flooding your local timeline, you have to explicitly declare whether you want it to post them all, or not, by explicitly setting option «-p» or «--do-post» to «y» («yes») or «n» («no»); mind that in both cases they will be recorded as posted in the state file, and wont be posted again on subsequent runs (you can use «-h» or «--help» to display help).\n";
exit(0);
} else {
echo "Info: state file «{$conf['state_file_absolute_path']}» was not found.\n";
vecho($opts['verbose'],"Info: state file «{$conf['state_file_absolute_path']}» was not found.\n");
}
//print_r($guids);die();
if (is_null($opts['do-post']) || $opts['test']) $opts['do-post']=true;
$newItemsCount=0;
echo "Info: trying to fetch feed from «{$conf['feed_url']}».\n";
vecho($opts['verbose'],"Info: trying to fetch feed from «{$conf['feed_url']}».\n");
$feed=curl($conf['feed_url'],null,['Accept: application/xml']);
if ($feed['content']===false) dieYoung("Error: could not connect to «{$conf['feed_url']}» (error: «{$feed['error']}»).\n",1);
if ($feed['httpcode']!='200') dieYoung("Error: «{$conf['feed_url']} returned http code «{$res['httpcode']}».\n",1);
@ -335,49 +339,65 @@ if ($feed===false) dieYoung("Error: got no valid XML from «{$conf['feed_url']}
if (!isset($feed->channel->item) || !is_iterable($feed->channel->item) || !is_countable($feed->channel->item)) dieYoung("Error: feed from «{$conf['feed_url']}» had unexpected format.\n",1);
$itemsCount=$feed->channel->item->count();
if ($itemsCount==0) exitYoung("Info: feed from «{$conf['feed_url']}» was empty, bye.\n");
foreach ($feed->channel->item as $item)
if (isset($item->guid) && $item->guid->__toString()!='' && !array_key_exists($item->guid->__toString(),$guids))
$newItemsCount++;
echo "Info: got good feed with {$itemsCount} events ({$newItemsCount} new) from «{$conf['feed_url']}».\n";
if (!$opts['test'] && $newItemsCount==0) exitYoung("Info: feed from «{$conf['feed_url']}» had no new events, bye.\n");
if (!$opts['test'] && ($fh=@fopen($conf['state_file_absolute_path'],'a'))===false) dieYoung("Error: could not open «{$conf['state_file_absolute_path']}» in «append» mode.\n",1);
$tsfp="{$conf['state_file_absolute_path']}.tmp";
if (!$opts['test'] && ($fh=@fopen($tsfp,'w'))===false) dieYoung("Error: could not open «{$tsfp}» in «write» mode.\n",1);
$itemsToPost=0;
$goodPostsCount=0;
$index=0;
foreach ($feed->channel->item as $item) {
$index++;
// print_r($item);
if (!isset($item->guid) || ($guid=$item->guid->__toString())=='') {
fwrite(STDERR,"Warning: event #{$index} has no GUID, skipping.\n");
} elseif (!array_key_exists($guid,$guids) || $opts['test']) {
//print_r($item);
if (!isset($item->guid) || !isset($item->title) || !isset($item->link) || !isset($item->description) || !isset($item->pubDate)) {
fwrite(STDERR,"Warning: event #{$index} has unexpected format, skipping.\n");
} else {
$guid=$item->guid->__toString();
$file=null;
if (isset($item->enclosure[0]['url']) && isset($item->enclosure[0]['type']) && isset($item->enclosure[0]['length']))
$hash=$item->title.$item->pubDate;
if (isset($item->enclosure[0]['url']) && isset($item->enclosure[0]['type']) && isset($item->enclosure[0]['length'])) {
$file=['url'=>$item->enclosure[0]['url']->__toString(), 'type'=>$item->enclosure[0]['type']->__toString(), 'length'=>$item->enclosure[0]['length']->__toString()];
if (isset($item->description)) {
$buff=$item->description->__toString();
if ($buff=='') {
$ptext='';
} elseif (preg_match('#^\n?<h3>(.+)</h3><strong>(.+)</strong><br/><small>\((\w+)\W+(\d+)\W+(\w+)\W+(\d+:\d+)\)</small><br/>(.+)$#iuU',$buff,$matches)===1) {
// print_r($matches);
$matches[1]=hent($matches[1]);
$matches[2]=hent($matches[2]);
$ptext="{$matches[1]}\n\n".ucfirst($matches[3])." {$matches[4]} {$matches[5]} alle {$matches[6]} presso {$matches[2]}\n\n".html2text($matches[7]);
} else {
$ptext=html2text($item->description);
}
$hash.=$item->enclosure[0]['url'].$item->enclosure[0]['type'].$item->enclosure[0]['length'];
}
if (isset($item->link) && $item->link->__toString()!='') {
$plink="\n\n".$item->link->__toString();
$buff=$item->description->__toString();
if ($buff=='') {
$ptext='';
} elseif (preg_match('#^\n?<h3>(.+)</h3><strong>(.+)</strong><br/><small>\((\w+)\W+(\d+)\W+(\w+)\W+(\d+:\d+)\)</small><br/>(.+)$#iuU',$buff,$matches)===1) {
//print_r($matches);
$matches[1]=hent($matches[1]);
$matches[2]=hent($matches[2]);
$ptext="{$matches[1]}\n\n".ucfirst($matches[3])." {$matches[4]} {$matches[5]} alle {$matches[6]} presso {$matches[2]}\n\n".html2text($matches[7]);
} else {
$plink='';
$ptext=html2text($item->description);
}
$hash.=$buff;
$plink="\n\n".$item->link->__toString();
$hash.=$item->link;
if (isset($item->category) && is_countable($item->category) && is_iterable($item->category) && $item->category->count()>0) {
$pcats=[];
foreach ($item->category as $val) $pcats[]=hashtag($val->__toString());
foreach ($item->category as $val) {
$pcats[]=hashtag($val->__toString());
$hash.=$val;
}
$pcats="\n\n".implode(' ',$pcats);
} else {
$pcats='';
}
$hash=hash('sha256',$hash);
if (array_key_exists($guid,$guids)) {
if ($hash==$guids[$guid]['hash']) {
vecho($opts['verbose'],"Info: event «{$guid}» is not new and has not changed; skipping.\n");
$state='old';
} else {
vecho($opts['verbose'],"Info: event «{$guid}» is not new, but it has changed; processing.\n");
$state='changed';
$itemsToPost++;
}
} else {
vecho($opts['verbose'],"Info: event «{$guid}» is new; processing.\n");
$state='new';
$itemsToPost++;
}
if ($opts['test']) $state='new';
$post="{$ptext}{$plink}{$pcats}";
if (postLength($post,$tldsregex['tlds'])<=$conf['max_post_length'] && !$conf['always_link_gancio_post']) {
$plink='';
@ -387,47 +407,48 @@ foreach ($feed->channel->item as $item) {
$post="{$ptext}{$plink}{$pcats}";
while (postLength($post,$tldsregex['tlds'])>$conf['max_post_length'] && $ptext!='') {
$ptext=preg_replace('#\S+\W*$#','',$ptext);
// echo "[[[{$ptext}]]]\n";
//echo "[[[{$ptext}]]]\n";
$post="{$ptext}[…]{$plink}{$pcats}";
}
//echo "--- #{$index}: {$guid} ---\n{$post}\n--- (length: ".postLength($post,$tldsregex['tlds']).") ---\n\n";
if (postLength($post,$tldsregex['tlds'])>$conf['max_post_length']) {
fwrite(STDERR,"Warning: could not shorten post for event «{$guid}» to make it fit into {$conf['max_post_length']} characters; wont post.\n");
} else {
if ($opts['verbose']) echo "--- #{$index}: {$guid} ---\n{$post}\n--- (length: ".postLength($post,$tldsregex['tlds']).") ---\n\n";
} elseif ($state=='new' || $state=='changed') {
if ($opts['do-post']) {
$doPost=false;
$postData=[];
// print_r($file);
//print_r($file);
if (is_null($file)) {
if ($opts['verbose']) echo "Info: event «{$guid}» has no attachment.\n";
vecho($opts['verbose'],"Info: {$state} event «{$guid}» has no attachment.\n");
$doPost=true;
} elseif ($file['length']>$conf['max_image_size']) {
fwrite(STDERR,"Warning: the size of attachment «{$file['ulr']}» is greater than image upload max size on «{$conf['fedi_hostname']}»; wont post status for event «{$guid}».\n");
fwrite(STDERR,"Warning: the size of attachment «{$file['ulr']}» is greater than image upload max size on «{$conf['fedi_hostname']}»; wont post status for {$state} event «{$guid}».\n");
} else {
vecho($opts['verbose'],"Info: {$state} event «{$guid}» has an attachment; processing.\n");
$res=curl($file['url']);
if ($res['content']===false) {
fwrite(STDERR,"Warning: could not connect to «{$file['url']}» (error: «{$res['error']}»); wont post status for event «{$guid}».\n");
fwrite(STDERR,"Warning: could not connect to «{$file['url']}» (error: «{$res['error']}»); wont post status for {$state} event «{$guid}».\n");
} elseif ($res['httpcode']!='200') {
fwrite(STDERR,"Warning: «{$file['url']}» returned http code «{$res['httpcode']}»; wont post status for event «{$guid}».\n");
fwrite(STDERR,"Warning: «{$file['url']}» returned http code «{$res['httpcode']}»; wont post status for {$state} event «{$guid}».\n");
} else {
// we don't use CURLStringFile because in php 7.3 it is not available
// $pd=['file'=>new CURLStringFile($res['content'],'file',$file['type']), 'description'=>'Flyer dellevento'];
// we don't use CURLStringFile because in php 7.3 it is not available
//$pd=['file'=>new CURLStringFile($res['content'],'file',$file['type']), 'description'=>'Flyer dellevento'];
$tfp=__DIR__.'/storage/'.basename($file['url']);
if (@file_put_contents($tfp,$res['content'])===false) {
fwrite(STDERR,"Warning: could not save «{$tfp}»; wont post status for event «{$guid}».\n");
fwrite(STDERR,"Warning: could not save «{$tfp}»; wont post status for {$state} event «{$guid}».\n");
} else {
$pd=['file'=>curl_file_create($tfp,$file['type'],'file'), 'description'=>'Flyer dellevento'];
$url="https://{$conf['fedi_hostname']}/api/v2/media";
$res=curl($url,'/api/v2/media',["Authorization: Bearer {$conf['fedi_token']}", 'Accept: application/json'],$pd);
if ($res['content']===false) {
fwrite(STDERR,"Warning: could not connect to «{$url}» (error: «{$res['error']}»); wont post status for event «{$guid}».\n");
fwrite(STDERR,"Warning: could not connect to «{$url}» (error: «{$res['error']}»); wont post status for {$state} event «{$guid}».\n");
} elseif (is_null($res['content']=@json_decode($res['content'],true))) {
fwrite(STDERR,"Warning: «{$url}» did not return valid JSON; wont post status for event «{$guid}».\n");
fwrite(STDERR,"Warning: «{$url}» did not return valid JSON; wont post status for {$state} event «{$guid}».\n");
} elseif ($res['httpcode']!='200' && $res['httpcode']!='202') {
(isset($res['content']['error'])) ? $buff=" (error: «{$res['content']['error']}»)" : $buff='';
fwrite(STDERR,"Warning: «{$url}» returned http code «{$res['httpcode']}»{$buff}; wont post status for event «{$guid}».\n");
fwrite(STDERR,"Warning: «{$url}» returned http code «{$res['httpcode']}»{$buff}; wont post status for {$state} event «{$guid}».\n");
} elseif (!isset($res['content']['id'])) {
fwrite(STDERR,"Warning: no «id» in JSON from «{$url}»; file has not been uploaded successfully; wont post status for event «{$guid}».\n");
fwrite(STDERR,"Warning: no «id» in JSON from «{$url}»; file has not been uploaded successfully; wont post status for {$state} event «{$guid}».\n");
} else {
$id=$res['content']['id'];
if ($res['httpcode']=='202') {
@ -442,10 +463,11 @@ foreach ($feed->channel->item as $item) {
}
}
if (!is_null($id)) {
vecho($opts['verbose'],"Info: successfully posted attachment for {$state} event «{$guid}».\n");
$postData['media_ids[]']=$id;
$doPost=true;
} else {
fwrite(STDERR,"Warning: server took too long to process file, or could not; wont post status for event «{$guid}».\n");
fwrite(STDERR,"Warning: server took too long to process file, or could not; wont post status for {$state} event «{$guid}».\n");
}
}
if (@unlink($tfp)===false) fwrite(STDERR,"Warning: could not delete «{$tfp}».\n");
@ -460,46 +482,44 @@ foreach ($feed->channel->item as $item) {
$headers=["Authorization: Bearer {$conf['fedi_token']}", 'Accept: application/json', 'Idempotency-Key: '.md5(implode('-',$postData).time())];
$res=curl($url,'/api/v1/statuses',$headers,$postData);
if ($res['content']===false) {
fwrite(STDERR,"Warning: could not connect to «{$url}» (error: «{$res['error']}»); could not post status for event «{$guid}».\n");
fwrite(STDERR,"Warning: could not connect to «{$url}» (error: «{$res['error']}»); could not post status for {$state} event «{$guid}».\n");
} elseif (is_null($res['content']=@json_decode($res['content'],true))) {
fwrite(STDERR,"Warning: «{$url}» did not return good JSON; could not post status for event «{$guid}».\n");
fwrite(STDERR,"Warning: «{$url}» did not return good JSON; could not post status for {$state} event «{$guid}».\n");
} elseif ($res['httpcode']!='200') {
(isset($res['content']['error'])) ? $buff=" (error: «{$res['content']['error']}»)" : $buff='';
fwrite(STDERR,"Warning: «{$url}» returned http code «{$res['httpcode']}»{$buff}; could not post status for event «{$guid}».\n");
fwrite(STDERR,"Warning: «{$url}» returned http code «{$res['httpcode']}»{$buff}; could not post status for {$state} event «{$guid}».\n");
} elseif (!isset($res['content']['url'])) {
fwrite(STDERR,"Warning: JSON from «{$url}» had unexpected format; could not post status for event «{$guid}».\n");
fwrite(STDERR,"Warning: JSON from «{$url}» had unexpected format; could not post status for {$state} event «{$guid}».\n");
} else {
echo "Info: successfully posted status for event «{$guid}» (URL: «{$res['content']['url']}»).\n";
// print_r($res['content']);
$now=time();
$guids[$guid]=$now;
if (!$opts['test']) fwrite($fh,"{$now}\t{$guid}\n");
vecho($opts['verbose'],"Info: successfully posted status for {$state} event «{$guid}» (URL: «{$res['content']['url']}»).\n");
//print_r($res['content']);
$guids[$guid]=['timestamp'=>time(), 'hash'=>$hash];
$goodPostsCount++;
}
}
} else {
echo "Info: would have posted status for event «{$guid}».\n";
$now=time();
$guids[$guid]=$now;
if (!$opts['test']) fwrite($fh,"{$now}\t{$guid}\n");
vecho($opts['verbose'],"Info: would have tried to post status for {$state} event «{$guid}».\n");
if ($state=='new' || $state=='changed') $guids[$guid]=['timestamp'=>time(), 'hash'=>$hash];
$goodPostsCount++;
}
}
} else {
if ($opts['verbose']) echo "Info: event «{$guid}» has already been posted on ".date('c',$guids[$guid]).", skipping.\n";
if (!$opts['test'] && array_key_exists($guid,$guids)) fwrite($fh,"{$guids[$guid]['timestamp']}\t{$guids[$guid]['hash']}\t{$guid}\n");
}
if ($opts['test']) break;// to test a single post
}
if (!$opts['test']) fclose($fh);
if (!$opts['test']) {
fclose($fh);
rename($tsfp,$conf['state_file_absolute_path']);
}
if (!$opts['test']) {
if ($opts['do-post'])
echo "Info: succesfully posted {$goodPostsCount} of {$newItemsCount} new event(s) (of {$itemsCount} total events in the feed).\n";
vecho($opts['verbose'],"Info: succesfully posted {$goodPostsCount} of {$itemsToPost} new or edited event(s) (of {$itemsCount} total events in the feed).\n");
else
echo "Info: would have tried to post {$newItemsCount} new event(s) of {$itemsCount} total events in the feed.\n";
vecho($opts['verbose'],"Info: would have tried to post {$itemsToPost} new or changed event(s) of {$itemsCount} total events in the feed.\n");
} elseif ($goodPostsCount==1) {
echo "Info: successfully posted the first of {$itemsCount} total events in the feed ({$newItemsCount} are new).\n";
vecho($opts['verbose'],"Info: successfully posted the first of {$itemsCount} total events in the feed ({$itemsToPost} are new or changed).\n");
} else {
echo "Info: failed to post the first of {$itemsCount} total events in the feed ({$newItemsCount} are new).\n";
vecho($opts['verbose'],"Info: failed to post the first of {$itemsCount} total events in the feed ({$itemsToPost} are new or changed).\n");
}
exit(0);
@ -561,6 +581,10 @@ function hent($str) {
return html_entity_decode($str,ENT_QUOTES,'UTF-8');
}
function vecho($do,$msg) {
if ($do) echo $msg;
}
function sighandler($sig) {
global $fh;
if (isset($fh)) fclose($fh);
@ -569,11 +593,13 @@ function sighandler($sig) {
}
function dieYoung($msg,$ec) {
if (isset($fh)) fclose($fh);
fwrite(STDERR,$msg);
die($ec);
}
function exitYoung($msg) {
if (isset($fh)) fclose($fh);
echo $msg;
exit(0);
}