Now, when the script refuses to run because there is no state file and «-p» has not been specified, it exits with «1» instead of «0»; changed lots of text in help and messages; bumped version to 0.4.1
This commit is contained in:
parent
afc1eba399
commit
b5b8c773fb
1 changed files with 92 additions and 91 deletions
183
gancioff
183
gancioff
|
@ -18,7 +18,7 @@
|
||||||
|
|
||||||
$SNAME='GancioFF';
|
$SNAME='GancioFF';
|
||||||
$ENAME=strtolower($SNAME);
|
$ENAME=strtolower($SNAME);
|
||||||
$SVERS='0.4';
|
$SVERS='0.4.1';
|
||||||
|
|
||||||
require __DIR__.'/lib/gettlds.php';
|
require __DIR__.'/lib/gettlds.php';
|
||||||
require __DIR__.'/lib/mastodon-postLength.php';
|
require __DIR__.'/lib/mastodon-postLength.php';
|
||||||
|
@ -33,19 +33,23 @@ $help=
|
||||||
|
|
||||||
[[[ DESCRIPTION ]]]
|
[[[ DESCRIPTION ]]]
|
||||||
|
|
||||||
This is {$SNAME} v{$SVERS}, a CLI PHP script that can be used to periodically
|
This is {$SNAME} v{$SVERS}, a CLI PHP script that can be used to periodically
|
||||||
fetch the RSS feed from an instance of Gancio (https://gancio.org) and post
|
fetch the RSS feed from an instance of Gancio (https://gancio.org) and post
|
||||||
its new entries – the events – on the fediverse through a Mastodon account,
|
its new entries – the events announcements – on the fediverse through a
|
||||||
keeping track of already posted events’ GUIDs (Global Unique IDentifiers) in
|
Mastodon account, recording into a state file a reference to each already
|
||||||
order to post only the new ones on each run.
|
posted announcement in order to post only new or changed ones on each run.
|
||||||
It can be useful, for example, when the admins of a Gancio instance chose not
|
It can be useful, for example, when the admins of a Gancio instance chose not
|
||||||
to use its federation feature because it would be too heavy on its server: in
|
to use its federation feature because it would be too heavy on its server:
|
||||||
this case {$SNAME} is a quite light alternative, moving from the server
|
in fact, {$SNAME} is a light alternative to federating the Gancio instance,
|
||||||
running Gancio to the one running Mastodon the burden of posting each event to
|
moving from its server to the one running Mastodon the burden of posting each
|
||||||
all the instances that host at least one follower, and of sending them the
|
announcement to each fediverse instance hosting at least one follower, and of
|
||||||
image a Gancio user can and almost always do attach to each event, because
|
sending them the image a Gancio user can attach to each announcement, because
|
||||||
{$SNAME} will fetch it only once and attach it to the post for the event.
|
{$SNAME} will fetch it only once and attach it to the Mastodon post; moreover,
|
||||||
{$SNAME} is meant to be periodically run, every half an hour or so, by a cron
|
by default, if an announcement on the Gancio instance fits into a Mastodon
|
||||||
|
post {$SNAME} doesn’t place a link to the original announcement into the post,
|
||||||
|
thus further reducing the burden due to the requests the Gancio instance gets
|
||||||
|
from every Mastodon instance trying to generate a “link preview”.
|
||||||
|
{$SNAME} is meant to be run periodically, every half an hour or so, by a cron
|
||||||
job, or systemd timer, or the likes (you can find a sample «{$ENAME}.timer»
|
job, or systemd timer, or the likes (you can find a sample «{$ENAME}.timer»
|
||||||
and a commented sample «{$ENAME}.service» in the «systemd» directory).
|
and a commented sample «{$ENAME}.service» in the «systemd» directory).
|
||||||
In order to work, {$SNAME} needs a configuration file path to be passed to it
|
In order to work, {$SNAME} needs a configuration file path to be passed to it
|
||||||
|
@ -53,17 +57,17 @@ as an argument on the command line.
|
||||||
|
|
||||||
[[[ CONFIGURATION FILE ]]]
|
[[[ CONFIGURATION FILE ]]]
|
||||||
|
|
||||||
The configuration file needs to be like this:
|
The configuration file needs to be like this:
|
||||||
|
|
||||||
--- Example configuration file ---
|
--- Example configuration file ---
|
||||||
# Lines beginnig with a «#» and empty lines will be ignored
|
# Lines beginnig with a «#» and empty lines will be ignored
|
||||||
|
|
||||||
# «feed_url» is required to specify the URL to fetch the RSS feed from;
|
# «feed_url» is required to specify the URL to fetch the RSS feed from.
|
||||||
# for example:
|
# For example:
|
||||||
feed_url = https://gancio.some.domain/feed/rss?show_recurrent=true
|
feed_url = https://gancio.some.domain/feed/rss?show_recurrent=true
|
||||||
|
|
||||||
# «fedi_hostname» is required to specify the hostname of the Mastodon instance
|
# «fedi_hostname» is required to specify the hostname of the Mastodon instance
|
||||||
# you want to post to; for example:
|
# you want to post to. For example:
|
||||||
fedi_hostname = mastodon.another.domain
|
fedi_hostname = mastodon.another.domain
|
||||||
|
|
||||||
# «fedi_token» is required to specify an «app token» to access the account
|
# «fedi_token» is required to specify an «app token» to access the account
|
||||||
|
@ -77,15 +81,15 @@ fedi_hostname = mastodon.another.domain
|
||||||
fedi_token = w6oQ_Ot2LSAm_Q31hrvp0asfl22ip3O4ipYq1kV1ceY
|
fedi_token = w6oQ_Ot2LSAm_Q31hrvp0asfl22ip3O4ipYq1kV1ceY
|
||||||
|
|
||||||
# «state_file_absolute_path» is required to specify the absolute path of the
|
# «state_file_absolute_path» is required to specify the absolute path of the
|
||||||
# state file where {$SNAME} will store the GUIDs of already posted events and
|
# state file where {$SNAME} will store the references to already posted
|
||||||
# the timestamps of the moments when it posted them (on each run, {$SNAME}
|
# announcements (on every run, {$SNAME} will check this file for entries older
|
||||||
# will check for entries older than one year and discard them, in order to
|
# than one year and discard them, to avoid the state file to grow too much).
|
||||||
# avoid the state file to grow too much). For example:
|
# For example:
|
||||||
state_file_absolute_path = /var/local/cache/gancio.some.domain.feed.state
|
state_file_absolute_path = /var/local/cache/gancio.some.domain.feed.state
|
||||||
|
|
||||||
# «posts_language» is required to specify the ISO 639-1 code for the language
|
# «posts_language» is required to specify the ISO 639-1 code for the language
|
||||||
# of posts (see https://www.loc.gov/standards/iso639-2/php/code_list.php for
|
# of posts (see https://www.loc.gov/standards/iso639-2/php/code_list.php for
|
||||||
# a complete list); for example:
|
# a complete list). For example:
|
||||||
posts_language = it
|
posts_language = it
|
||||||
|
|
||||||
# «posts_visibility» is optional and lets you override the default “public”
|
# «posts_visibility» is optional and lets you override the default “public”
|
||||||
|
@ -97,29 +101,25 @@ posts_language = it
|
||||||
# «private» (AKA «followers only»: posts will be visible only by followers and
|
# «private» (AKA «followers only»: posts will be visible only by followers and
|
||||||
# won’t be boostable by anyone), and «direct» (since {$SNAME} posts won’t ever
|
# won’t be boostable by anyone), and «direct» (since {$SNAME} posts won’t ever
|
||||||
# explicitly mention any account, posts with this visibility will be visible
|
# explicitly mention any account, posts with this visibility will be visible
|
||||||
# only from the Mastodon account in use). For example:
|
# only from the Mastodon account in use, which may be good for testing).
|
||||||
|
# For example:
|
||||||
post_visibility = unlisted
|
post_visibility = unlisted
|
||||||
|
|
||||||
# «max_post_length» is optional and lets you override the automatically
|
# «max_post_length» is optional and lets you override the automatically
|
||||||
# detected maximum length that a post can have on the instance specified with
|
# detected maximum length that a post can have on the instance specified with
|
||||||
# «fedi_hostname»; it can be used for testing purposes or just to keep the
|
# «fedi_hostname»; it can be used for testing purposes or just to keep the
|
||||||
# posts shorter than they would be otherwise; for example:
|
# posts shorter than they would be otherwise. For example:
|
||||||
max_post_length = 840
|
max_post_length = 840
|
||||||
|
|
||||||
# «always_link_gancio_post» is optional and if unspecified it defaults to
|
# «always_link_gancio_post» is optional and if unspecified it defaults to
|
||||||
# «false», which means that {$SNAME} adds to the Mastodon post a link to the
|
# «false», which means that {$SNAME} adds to the Mastodon post a link to the
|
||||||
# original Gancio post only if the latter is too long to fit into the first
|
# original Gancio post only if the latter is too long to fit into the first
|
||||||
# (i.e. into the Mastodon instance “max post length”, or into the
|
# (i.e. into the maximum post length allowed by the Mastodon instance, or into
|
||||||
# «max_post_length» specified in this configuration file - see above); this
|
# the «max_post_length» specified in this configuration file - see above);
|
||||||
# way, {$SNAME} reduces the burden on the Gancio instance that is due to the
|
# this further reduces the burden on the Gancio instance (see the second
|
||||||
# requests that it gets from every Mastodon instance where a Mastodon post
|
# paragraph of the «Description» section).
|
||||||
# with a link to the original Gancio post will end up, in order for each of
|
|
||||||
# them to generate a “link preview”; such burden gets reduced in different
|
|
||||||
# measures depending on the average length of a post on the Gancio instance
|
|
||||||
# and on the “max post length” on the Mastodon instance that {$SNAME} is using
|
|
||||||
# to post (or on the «max_post_length» explicitly specified in this file).
|
|
||||||
# If set to «true», {$SNAME} will instead always add a link to the original
|
# If set to «true», {$SNAME} will instead always add a link to the original
|
||||||
# Gancio post.
|
# Gancio announcement.
|
||||||
always_link_gancio_post = true
|
always_link_gancio_post = true
|
||||||
--- End of example configuration file ---
|
--- End of example configuration file ---
|
||||||
|
|
||||||
|
@ -129,30 +129,32 @@ always_link_gancio_post = true
|
||||||
Show this help text and exit.
|
Show this help text and exit.
|
||||||
-p / --do-post <y|n>
|
-p / --do-post <y|n>
|
||||||
When a state file already exists, this option defaults to «y» («yes»), which
|
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
|
means that {$SNAME} will try to post all the new or changed announcements it
|
||||||
feed; if set to «n» («no»), {$SNAME} will not try to post them, but it will
|
may find in the feed; if set to «n» («no»), {$SNAME} will not try to post
|
||||||
save their GUIDs into the state file nonetheless, so they won’t be posted
|
them, but it will still record a reference to each of them into the state
|
||||||
again on subsequent runs.
|
file, so they won’t be posted again on subsequent runs (unless they were
|
||||||
This is mainly useful on {$SNAME}’s first run on a given feed, i.e. when
|
changed in the meantime).
|
||||||
the state file specified in the configuration file doesn’t exist yet and thus
|
This option is mainly useful on {$SNAME}’s first run on a given feed, i.e.
|
||||||
all the events in the feed will be considered “new”: in this case, {$SNAME}
|
when the state file specified in the configuration file doesn’t exist yet and
|
||||||
refuses to run unless you explicitly set this option to «y» or «n»: this is a
|
thus all the announcements in the feed will be considered “new”: in this
|
||||||
way to prevent you from unintentionally flooding your Mastodon instance with
|
case, {$SNAME} refuses to run unless you explicitly set this option to «y» or
|
||||||
all the events in the feed.
|
«n»: this is a way to prevent you from unintentionally flooding your Mastodon
|
||||||
|
instance’s «Local» timeline, and possibly your followers’ «Home» timelines,
|
||||||
|
with all the announcements in the feed.
|
||||||
When “test mode” is active (see the next option description), setting this
|
When “test mode” is active (see the next option description), setting this
|
||||||
option has no effect.
|
option has no effect.
|
||||||
-t / --test
|
-t / --test
|
||||||
Do a test: {$SNAME} will try as always to read the configuration file, fetch
|
Do a test: {$SNAME} will try as always to read the configuration file, fetch
|
||||||
the defined Mastodon instance’s info, load the state file and fetch the feed,
|
the defined Mastodon instance’s 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
|
but it will post only the first of the announcements it may find there, with
|
||||||
«direct», even if according to the state file it has already been posted, and
|
a visibility of «direct», even if according to the state file it has already
|
||||||
won’t update the state file.
|
been posted, and won’t update the state file.
|
||||||
This option also activates “verbose mode” (see below).
|
This option also activates “verbose mode” (see below).
|
||||||
-v / --verbose
|
-v / --verbose
|
||||||
When this option is not set {$SNAME} prints only warning and error messages;
|
When this option is not set {$SNAME} prints only warning and error messages;
|
||||||
when it is set it also prints informational messages about what it’s doing.
|
when it is set it also prints informational messages about what it’s doing.
|
||||||
--
|
--
|
||||||
Treat every possible subsequent argument as non-options. Useful only in the
|
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.
|
very improbable case your config file is named «--help» or as another option.
|
||||||
|
|
||||||
[[[ EXIT VALUES ]]]
|
[[[ EXIT VALUES ]]]
|
||||||
|
@ -163,8 +165,8 @@ always_link_gancio_post = true
|
||||||
|
|
||||||
[[[ DISCLAIMER AND LICENSE ]]]
|
[[[ DISCLAIMER AND LICENSE ]]]
|
||||||
|
|
||||||
This program comes with ABSOLUTELY NO WARRANTY; for details see the source.
|
This program comes with ABSOLUTELY NO WARRANTY; for details see the source.
|
||||||
This is free software, and you are welcome to redistribute it under certain
|
This is free software, and you are welcome to redistribute it under certain
|
||||||
conditions; see <http://www.gnu.org/licenses/> for details.\n";
|
conditions; see <http://www.gnu.org/licenses/> for details.\n";
|
||||||
|
|
||||||
$confFP=null;
|
$confFP=null;
|
||||||
|
@ -294,14 +296,13 @@ if (is_null($conf['max_post_length'])) {
|
||||||
}
|
}
|
||||||
//print_r($conf);
|
//print_r($conf);
|
||||||
|
|
||||||
$guids=[];
|
$refs=[];
|
||||||
vecho($opts['verbose'],"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 the references to already posted announcements from state file «{$conf['state_file_absolute_path']}».\n");
|
||||||
if (file_exists($conf['state_file_absolute_path'])) {
|
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 it’s not a file.\n",1);
|
if (!is_file($conf['state_file_absolute_path'])) dieYoung("Error: «{$conf['state_file_absolute_path']}» exists but it’s not a file.\n",1);
|
||||||
if (!is_readable($conf['state_file_absolute_path'])) dieYoung("Error: «{$conf['state_file_absolute_path']}» exists but it’s not readable.\n",1);
|
if (!is_readable($conf['state_file_absolute_path'])) dieYoung("Error: «{$conf['state_file_absolute_path']}» exists but it’s not readable.\n",1);
|
||||||
if (!is_writeable($conf['state_file_absolute_path'])) dieYoung("Error: «{$conf['state_file_absolute_path']}» exists but it’s not writable.\n",1);
|
if (!is_writeable($conf['state_file_absolute_path'])) dieYoung("Error: «{$conf['state_file_absolute_path']}» exists but it’s not writable.\n",1);
|
||||||
$guids=[];
|
$refs=[];
|
||||||
$buff=file($conf['state_file_absolute_path'],);
|
|
||||||
$graceTime=365*24*60*60;
|
$graceTime=365*24*60*60;
|
||||||
$graceLine=time()-$graceTime;
|
$graceLine=time()-$graceTime;
|
||||||
$i=0;
|
$i=0;
|
||||||
|
@ -309,25 +310,25 @@ if (file_exists($conf['state_file_absolute_path'])) {
|
||||||
foreach ($buff as $key=>$val) {
|
foreach ($buff as $key=>$val) {
|
||||||
if (preg_match('#^(\d+)\t([a-z0-9]{64})\t(\S+)$#',$val,$matches)===1) {
|
if (preg_match('#^(\d+)\t([a-z0-9]{64})\t(\S+)$#',$val,$matches)===1) {
|
||||||
if ($matches[1]+0>=$graceLine)
|
if ($matches[1]+0>=$graceLine)
|
||||||
$guids[$matches[3]]=['timestamp'=>$matches[1], 'hash'=>$matches[2]];
|
$refs[$matches[3]]=['timestamp'=>$matches[1], 'hash'=>$matches[2]];
|
||||||
else
|
else
|
||||||
$i++;
|
$i++;
|
||||||
} else {
|
} else {
|
||||||
dieYoung("Error: in state file «{$conf['state_file_absolute_path']}», line ".($key+1)." has unexpected format.\n",1);
|
dieYoung("Error: in state file «{$conf['state_file_absolute_path']}», line ".($key+1)." has unexpected format.\n",1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
unset($buff);
|
||||||
$fh=fopen($conf['state_file_absolute_path'],'w');
|
$fh=fopen($conf['state_file_absolute_path'],'w');
|
||||||
foreach ($guids as $key=>$val)
|
foreach ($refs as $key=>$val)
|
||||||
fwrite($fh,"{$val['timestamp']}\t{$val['hash']}\t{$key}\n");
|
fwrite($fh,"{$val['timestamp']}\t{$val['hash']}\t{$key}\n");
|
||||||
fclose($fh);
|
fclose($fh);
|
||||||
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");
|
vecho($opts['verbose'],'Info: got '.count($refs)." reference(s) to already posted announcement(s) from state file «{$conf['state_file_absolute_path']}»; removed {$i} reference(s) older than one year.\n");
|
||||||
} elseif (is_null($opts['do-post']) && !$opts['test']) {
|
} elseif (is_null($opts['do-post']) && !$opts['test']) {
|
||||||
echo "State file «{$conf['state_file_absolute_path']}» doesn’t 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 won’t be posted again on subsequent runs (you can use «-h» or «--help» to display help).\n";
|
dieyoung("State file «{$conf['state_file_absolute_path']}» doesn’t exist yet, so this is probably a first run on feed «{$conf['feed_url']}»; thus, all the announcements {$SNAME} may find in the feed will be considered new and, as a precaution against unintentionally flooding your Mastodon instance’s «Local» timeline, and possibly your followers’ «Home» timelines, 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 the references to the announcements will be recorded in the state file, so the announcements won’t be posted again on subsequent runs (unless they were changed in the meantime).\n",1);
|
||||||
exit(0);
|
|
||||||
} else {
|
} else {
|
||||||
vecho($opts['verbose'],"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();
|
//print_r($refs);die();
|
||||||
if (is_null($opts['do-post']) || $opts['test']) $opts['do-post']=true;
|
if (is_null($opts['do-post']) || $opts['test']) $opts['do-post']=true;
|
||||||
|
|
||||||
vecho($opts['verbose'],"Info: trying to fetch feed from «{$conf['feed_url']}».\n");
|
vecho($opts['verbose'],"Info: trying to fetch feed from «{$conf['feed_url']}».\n");
|
||||||
|
@ -350,7 +351,7 @@ foreach ($feed->channel->item as $item) {
|
||||||
$index++;
|
$index++;
|
||||||
//print_r($item);
|
//print_r($item);
|
||||||
if (!isset($item->guid) || !isset($item->title) || !isset($item->link) || !isset($item->description) || !isset($item->pubDate)) {
|
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");
|
fwrite(STDERR,"Warning: announcement #{$index} has unexpected format, skipping.\n");
|
||||||
} else {
|
} else {
|
||||||
$guid=$item->guid->__toString();
|
$guid=$item->guid->__toString();
|
||||||
$file=null;
|
$file=null;
|
||||||
|
@ -384,17 +385,17 @@ foreach ($feed->channel->item as $item) {
|
||||||
$pcats='';
|
$pcats='';
|
||||||
}
|
}
|
||||||
$hash=hash('sha256',$hash);
|
$hash=hash('sha256',$hash);
|
||||||
if (array_key_exists($guid,$guids)) {
|
if (array_key_exists($guid,$refs)) {
|
||||||
if ($hash==$guids[$guid]['hash']) {
|
if ($hash==$refs[$guid]['hash']) {
|
||||||
vecho($opts['verbose'],"Info: event «{$guid}» is not new and has not changed; skipping.\n");
|
vecho($opts['verbose'],"Info: announcement «{$guid}» is not new and has not changed; skipping.\n");
|
||||||
$state='old';
|
$state='old';
|
||||||
} else {
|
} else {
|
||||||
vecho($opts['verbose'],"Info: event «{$guid}» is not new, but it has changed; processing.\n");
|
vecho($opts['verbose'],"Info: announcement «{$guid}» is not new, but it has changed; processing.\n");
|
||||||
$state='changed';
|
$state='changed';
|
||||||
$itemsToPost++;
|
$itemsToPost++;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
vecho($opts['verbose'],"Info: event «{$guid}» is new; processing.\n");
|
vecho($opts['verbose'],"Info: announcement «{$guid}» is new; processing.\n");
|
||||||
$state='new';
|
$state='new';
|
||||||
$itemsToPost++;
|
$itemsToPost++;
|
||||||
}
|
}
|
||||||
|
@ -413,43 +414,43 @@ foreach ($feed->channel->item as $item) {
|
||||||
}
|
}
|
||||||
//echo "--- #{$index}: {$guid} ---\n{$post}\n--- (length: ".postLength($post,$tldsregex['tlds']).") ---\n\n";
|
//echo "--- #{$index}: {$guid} ---\n{$post}\n--- (length: ".postLength($post,$tldsregex['tlds']).") ---\n\n";
|
||||||
if (postLength($post,$tldsregex['tlds'])>$conf['max_post_length']) {
|
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; won’t post.\n");
|
fwrite(STDERR,"Warning: could not shorten post for announcement «{$guid}» to make it fit into {$conf['max_post_length']} characters; won’t post.\n");
|
||||||
} elseif ($state=='new' || $state=='changed') {
|
} elseif ($state=='new' || $state=='changed') {
|
||||||
if ($opts['do-post']) {
|
if ($opts['do-post']) {
|
||||||
$doPost=false;
|
$doPost=false;
|
||||||
$postData=[];
|
$postData=[];
|
||||||
//print_r($file);
|
//print_r($file);
|
||||||
if (is_null($file)) {
|
if (is_null($file)) {
|
||||||
vecho($opts['verbose'],"Info: {$state} event «{$guid}» has no attachment.\n");
|
vecho($opts['verbose'],"Info: {$state} announcement «{$guid}» has no attachment.\n");
|
||||||
$doPost=true;
|
$doPost=true;
|
||||||
} elseif ($file['length']>$conf['max_image_size']) {
|
} 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']}»; won’t post status for {$state} event «{$guid}».\n");
|
fwrite(STDERR,"Warning: the size of attachment «{$file['ulr']}» is greater than image upload max size on «{$conf['fedi_hostname']}»; won’t post status for {$state} announcement «{$guid}».\n");
|
||||||
} else {
|
} else {
|
||||||
vecho($opts['verbose'],"Info: {$state} event «{$guid}» has an attachment; processing.\n");
|
vecho($opts['verbose'],"Info: {$state} announcement «{$guid}» has an attachment; processing.\n");
|
||||||
$res=curl($file['url']);
|
$res=curl($file['url']);
|
||||||
if ($res['content']===false) {
|
if ($res['content']===false) {
|
||||||
fwrite(STDERR,"Warning: could not connect to «{$file['url']}» (error: «{$res['error']}»); won’t post status for {$state} event «{$guid}».\n");
|
fwrite(STDERR,"Warning: could not connect to «{$file['url']}» (error: «{$res['error']}»); won’t post status for {$state} announcement «{$guid}».\n");
|
||||||
} elseif ($res['httpcode']!='200') {
|
} elseif ($res['httpcode']!='200') {
|
||||||
fwrite(STDERR,"Warning: «{$file['url']}» returned http code «{$res['httpcode']}»; won’t post status for {$state} event «{$guid}».\n");
|
fwrite(STDERR,"Warning: «{$file['url']}» returned http code «{$res['httpcode']}»; won’t post status for {$state} announcement «{$guid}».\n");
|
||||||
} else {
|
} else {
|
||||||
// we don't use CURLStringFile because in php 7.3 it is not available
|
// 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 dell’evento'];
|
//$pd=['file'=>new CURLStringFile($res['content'],'file',$file['type']), 'description'=>'Flyer dell’evento'];
|
||||||
$tfp=__DIR__.'/storage/'.basename($file['url']);
|
$tfp=__DIR__.'/storage/'.basename($file['url']);
|
||||||
if (@file_put_contents($tfp,$res['content'])===false) {
|
if (@file_put_contents($tfp,$res['content'])===false) {
|
||||||
fwrite(STDERR,"Warning: could not save «{$tfp}»; won’t post status for {$state} event «{$guid}».\n");
|
fwrite(STDERR,"Warning: could not save «{$tfp}»; won’t post status for {$state} announcement «{$guid}».\n");
|
||||||
} else {
|
} else {
|
||||||
$pd=['file'=>curl_file_create($tfp,$file['type'],'file'), 'description'=>'Flyer dell’evento'];
|
$pd=['file'=>curl_file_create($tfp,$file['type'],'file'), 'description'=>'Flyer dell’evento'];
|
||||||
$url="https://{$conf['fedi_hostname']}/api/v2/media";
|
$url="https://{$conf['fedi_hostname']}/api/v2/media";
|
||||||
$res=curl($url,'/api/v2/media',["Authorization: Bearer {$conf['fedi_token']}", 'Accept: application/json'],$pd);
|
$res=curl($url,'/api/v2/media',["Authorization: Bearer {$conf['fedi_token']}", 'Accept: application/json'],$pd);
|
||||||
if ($res['content']===false) {
|
if ($res['content']===false) {
|
||||||
fwrite(STDERR,"Warning: could not connect to «{$url}» (error: «{$res['error']}»); won’t post status for {$state} event «{$guid}».\n");
|
fwrite(STDERR,"Warning: could not connect to «{$url}» (error: «{$res['error']}»); won’t post status for {$state} announcement «{$guid}».\n");
|
||||||
} elseif (is_null($res['content']=@json_decode($res['content'],true))) {
|
} elseif (is_null($res['content']=@json_decode($res['content'],true))) {
|
||||||
fwrite(STDERR,"Warning: «{$url}» did not return valid JSON; won’t post status for {$state} event «{$guid}».\n");
|
fwrite(STDERR,"Warning: «{$url}» did not return valid JSON; won’t post status for {$state} announcement «{$guid}».\n");
|
||||||
} elseif ($res['httpcode']!='200' && $res['httpcode']!='202') {
|
} elseif ($res['httpcode']!='200' && $res['httpcode']!='202') {
|
||||||
(isset($res['content']['error'])) ? $buff=" (error: «{$res['content']['error']}»)" : $buff='';
|
(isset($res['content']['error'])) ? $buff=" (error: «{$res['content']['error']}»)" : $buff='';
|
||||||
fwrite(STDERR,"Warning: «{$url}» returned http code «{$res['httpcode']}»{$buff}; won’t post status for {$state} event «{$guid}».\n");
|
fwrite(STDERR,"Warning: «{$url}» returned http code «{$res['httpcode']}»{$buff}; won’t post status for {$state} announcement «{$guid}».\n");
|
||||||
} elseif (!isset($res['content']['id'])) {
|
} elseif (!isset($res['content']['id'])) {
|
||||||
fwrite(STDERR,"Warning: no «id» in JSON from «{$url}»; file has not been uploaded successfully; won’t post status for {$state} event «{$guid}».\n");
|
fwrite(STDERR,"Warning: no «id» in JSON from «{$url}»; file has not been uploaded successfully; won’t post status for {$state} announcement «{$guid}».\n");
|
||||||
} else {
|
} else {
|
||||||
$id=$res['content']['id'];
|
$id=$res['content']['id'];
|
||||||
if ($res['httpcode']=='202') {
|
if ($res['httpcode']=='202') {
|
||||||
|
@ -464,11 +465,11 @@ foreach ($feed->channel->item as $item) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!is_null($id)) {
|
if (!is_null($id)) {
|
||||||
vecho($opts['verbose'],"Info: successfully posted attachment for {$state} event «{$guid}».\n");
|
vecho($opts['verbose'],"Info: successfully posted attachment for {$state} announcement «{$guid}».\n");
|
||||||
$postData['media_ids[]']=$id;
|
$postData['media_ids[]']=$id;
|
||||||
$doPost=true;
|
$doPost=true;
|
||||||
} else {
|
} else {
|
||||||
fwrite(STDERR,"Warning: server took too long to process file, or could not; won’t post status for {$state} event «{$guid}».\n");
|
fwrite(STDERR,"Warning: server took too long to process file, or could not; won’t post status for {$state} announcement «{$guid}».\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (@unlink($tfp)===false) fwrite(STDERR,"Warning: could not delete «{$tfp}».\n");
|
if (@unlink($tfp)===false) fwrite(STDERR,"Warning: could not delete «{$tfp}».\n");
|
||||||
|
@ -483,28 +484,28 @@ foreach ($feed->channel->item as $item) {
|
||||||
$headers=["Authorization: Bearer {$conf['fedi_token']}", 'Accept: application/json', 'Idempotency-Key: '.md5(implode('-',$postData).time())];
|
$headers=["Authorization: Bearer {$conf['fedi_token']}", 'Accept: application/json', 'Idempotency-Key: '.md5(implode('-',$postData).time())];
|
||||||
$res=curl($url,'/api/v1/statuses',$headers,$postData);
|
$res=curl($url,'/api/v1/statuses',$headers,$postData);
|
||||||
if ($res['content']===false) {
|
if ($res['content']===false) {
|
||||||
fwrite(STDERR,"Warning: could not connect to «{$url}» (error: «{$res['error']}»); could not post status for {$state} event «{$guid}».\n");
|
fwrite(STDERR,"Warning: could not connect to «{$url}» (error: «{$res['error']}»); could not post status for {$state} announcement «{$guid}».\n");
|
||||||
} elseif (is_null($res['content']=@json_decode($res['content'],true))) {
|
} elseif (is_null($res['content']=@json_decode($res['content'],true))) {
|
||||||
fwrite(STDERR,"Warning: «{$url}» did not return good JSON; could not post status for {$state} event «{$guid}».\n");
|
fwrite(STDERR,"Warning: «{$url}» did not return good JSON; could not post status for {$state} announcement «{$guid}».\n");
|
||||||
} elseif ($res['httpcode']!='200') {
|
} elseif ($res['httpcode']!='200') {
|
||||||
(isset($res['content']['error'])) ? $buff=" (error: «{$res['content']['error']}»)" : $buff='';
|
(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 {$state} event «{$guid}».\n");
|
fwrite(STDERR,"Warning: «{$url}» returned http code «{$res['httpcode']}»{$buff}; could not post status for {$state} announcement «{$guid}».\n");
|
||||||
} elseif (!isset($res['content']['url'])) {
|
} elseif (!isset($res['content']['url'])) {
|
||||||
fwrite(STDERR,"Warning: JSON from «{$url}» had unexpected format; could not post status for {$state} event «{$guid}».\n");
|
fwrite(STDERR,"Warning: JSON from «{$url}» had unexpected format; could not post status for {$state} announcement «{$guid}».\n");
|
||||||
} else {
|
} else {
|
||||||
vecho($opts['verbose'],"Info: successfully posted status for {$state} event «{$guid}» (URL: «{$res['content']['url']}»).\n");
|
vecho($opts['verbose'],"Info: successfully posted status for {$state} announcement «{$guid}» (URL: «{$res['content']['url']}»).\n");
|
||||||
//print_r($res['content']);
|
//print_r($res['content']);
|
||||||
$guids[$guid]=['timestamp'=>time(), 'hash'=>$hash];
|
$refs[$guid]=['timestamp'=>time(), 'hash'=>$hash];
|
||||||
$goodPostsCount++;
|
$goodPostsCount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
vecho($opts['verbose'],"Info: would have tried to post status for {$state} event «{$guid}».\n");
|
vecho($opts['verbose'],"Info: would have tried to post status for {$state} announcement «{$guid}».\n");
|
||||||
if ($state=='new' || $state=='changed') $guids[$guid]=['timestamp'=>time(), 'hash'=>$hash];
|
if ($state=='new' || $state=='changed') $refs[$guid]=['timestamp'=>time(), 'hash'=>$hash];
|
||||||
$goodPostsCount++;
|
$goodPostsCount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!$opts['test'] && array_key_exists($guid,$guids)) fwrite($fh,"{$guids[$guid]['timestamp']}\t{$guids[$guid]['hash']}\t{$guid}\n");
|
if (!$opts['test'] && array_key_exists($guid,$refs)) fwrite($fh,"{$refs[$guid]['timestamp']}\t{$refs[$guid]['hash']}\t{$guid}\n");
|
||||||
}
|
}
|
||||||
if ($opts['test']) break;// to test a single post
|
if ($opts['test']) break;// to test a single post
|
||||||
}
|
}
|
||||||
|
@ -514,13 +515,13 @@ if (!$opts['test']) {
|
||||||
}
|
}
|
||||||
if (!$opts['test']) {
|
if (!$opts['test']) {
|
||||||
if ($opts['do-post'])
|
if ($opts['do-post'])
|
||||||
vecho($opts['verbose'],"Info: succesfully posted {$goodPostsCount} of {$itemsToPost} new or edited event(s) (of {$itemsCount} total events in the feed).\n");
|
vecho($opts['verbose'],"Info: succesfully posted {$goodPostsCount} of {$itemsToPost} new or edited announcement(s) (of {$itemsCount} total announcements in the feed).\n");
|
||||||
else
|
else
|
||||||
vecho($opts['verbose'],"Info: would have tried to post {$itemsToPost} new or changed event(s) of {$itemsCount} total events in the feed.\n");
|
vecho($opts['verbose'],"Info: would have tried to post {$itemsToPost} new or changed announcement(s) of {$itemsCount} total announcements in the feed.\n");
|
||||||
} elseif ($goodPostsCount==1) {
|
} elseif ($goodPostsCount==1) {
|
||||||
vecho($opts['verbose'],"Info: successfully posted the first of {$itemsCount} total events in the feed ({$itemsToPost} are new or changed).\n");
|
vecho($opts['verbose'],"Info: successfully posted the first of {$itemsCount} total announcements in the feed ({$itemsToPost} are new or changed).\n");
|
||||||
} else {
|
} else {
|
||||||
vecho($opts['verbose'],"Info: failed to post the first of {$itemsCount} total events in the feed ({$itemsToPost} are new or changed).\n");
|
vecho($opts['verbose'],"Info: failed to post the first of {$itemsCount} total announcements in the feed ({$itemsToPost} are new or changed).\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
exit(0);
|
exit(0);
|
||||||
|
|
Loading…
Reference in a new issue