App-SpreadRevolutionaryDate
view release on metacpan or search on metacpan
bin/spread-revolutionary-date view on Meta::CPAN
#!/usr/bin/perl
#
# This file is part of App-SpreadRevolutionaryDate
#
# This software is Copyright (c) 2019-2026 by Gérald Sédrati.
#
# This is free software, licensed under:
#
# The GNU General Public License, Version 3, June 2007
#
use 5.014;
use utf8;
BEGIN {
$ENV{OUTPUT_CHARSET} = 'UTF-8';
}
# PODNAME: spread-revolutionary-date
# ABSTRACT: Spread date and time from Revolutionary (Republican) Calendar
use App::SpreadRevolutionaryDate;
App::SpreadRevolutionaryDate->new->spread;
__END__
=pod
=encoding UTF-8
=head1 NAME
spread-revolutionary-date - Spread date and time from Revolutionary (Republican) Calendar
=head1 VERSION
version 0.54
=head1 DESCRIPTION
C<spread-revolutionary-date> is a L<Free Software|https://www.gnu.org/philosophy/free-sw.html> that spreads the current date, expressed in the L<French Revolutionary calendar|https://en.wikipedia.org/wiki/French_Republican_calendar>, to various socia...
Moreover, you can easily extend these defaults targets with any desired one, see L</"EXTENDING TO NEW TARGETS">, and even spread something else than the revolutionary date, see L</msgmaker> option and L</"EXTENDING TO NEW MESSAGE MAKERS">.
The French Revolutionary calendar, also called Republican calendar, was introduced during the L<French Revolution|https://en.wikipedia.org/wiki/French_Revolution>, and used from late 1793 to 1805, and also during the L<Paris Commune|https://en.wikipe...
You B<must> have a registered account on each of the targets you want to spread the revolutionary date. And you must get credentials for C<spread-revolutionary-date> to post on C<Mastodon>, C<Bluesky> and C<Twitter>, and also for IA generated message...
The revolutionary date and time is computed thanks to the L<DateTime::Calendar::FrenchRevolutionary> Perl module, by Jean Forget.
=head1 USAGE
# Just execute the script in your shell
# to spread current date to configured accounts
# to Bluesky, Twitter, Mastodon, Freenode and Liberachat:
$ spread-revolutionary-date
# Or, since this script does nothing but calling
# the L<App::SpreadRevolutionaryDate> Perl module,
# use this one-liner:
$ perl -MApp::SpreadRevolutionaryDate \
-e 'App::SpreadRevolutionaryDate->new->spread;'
# Test spreading to Mastodon only:
$ spread-revolutionary-date \
--targets=Mastodon --test
# Test spreading to Twitter only in English:
$ spread-revolutionary-date \
--targets=Twitter \
--test \
--locale en
# Spread acab time to Twitter and Liberachat
# explicit channels
$ spread-revolutionary-date \
--targets=Twitter \
--targets=Liberachat \
--liberachat_channels='#revolution' \
--liberachat_channels='#acab' \
--revolutionarydate_acab
# Prompt user for a message to spread to Mastodon
$ spread-revolutionary-date \
--targets=Mastodon \
--msgmaker=UserPrompt
# Spread message as command line parameter to
# Mastodon, Bluesky, Twitter, Liberachat and Freenode
$ spread-revolutionary-date \
--msgmaker=UserPrompt \
--promptuser_default
# Spread message and image as command line parameter to
# Mastodon and Bluesky
$ spread-revolutionary-date \
--msgmaker=UserPrompt \
--targets=Mastodon \
--targets=Bluesky \
--promptuser_default \
'This is my message to the world'
--promptuser_img_path= \
/my/path/to/image.png
--promptuser_img_alt= \
'Alternative text for image'
# Spread message and image form web as command line parameter to
# Mastodon and Bluesky
$ spread-revolutionary-date \
bin/spread-revolutionary-date view on Meta::CPAN
=head3 --gemini_search "<SomePrompt>=1" | -gs "<SomePrompt>=1"
Same as L</process> configuration option above.
=head3 --gemini_img_path "<SomePrompt>=<path/to/image/file>" | -gip "<SomePrompt>=</path/to/image/file>"
Same as L</img_path (for Gemini)> configuration option above.
=head3 --gemini_img_alt "<SomePrompt>=<alternative text>" | -gia "<SomePrompt>=<alternative text>"
Same as L</img_alt (for Gemini)> configuration option above.
=head3 --gemini_img_url "<SomePrompt>=<img_url>" | -giu "<SomePrompt>=<img_url>"
Same as L</img_url (for Gemini)> configuration option above.
=head1 EXTENDING TO NEW TARGETS
Starting from version 0.07, this distribution takes advantage of L<Moose>, the postmodern object system for Perl 5, allowing to easily extend C<spread-revolutionary-date> to other targets than the default ones (C<Mastondon>, C<Bluesky>, C<Twitter>, C...
To add a new target, you should write a new class in the C<App::SpreadRevolutionaryDate::Target::> namespace (that is: the class should be C<App::SpreadRevolutionaryDate::Target::Mytarget> for a new C<Mytarget> target), that consumes the L<App::Sprea...
The name of the target should be added as a value of the L</targets> option.
Such a target class is actually just a wrapper. Usually a target has to use an existing specific C<worker> module (which can be a C<Moose> class or not) to perform the actual work of posting a message according the specific target protocol, after ha...
To perform authentication and to post a message, there is a strong likelihood that the new target requires specific parameters (e.g.: tokens, keys, account name, password, channels, etc.). These parameters should be defined as required attributes of ...
Should you extend C<spread-revolutionary-date> to a new target, we advise you to have a look on how default targets are implemented: L<App::SpreadRevolutionaryDate::Target::Bluesky> with L<App::SpreadRevolutionaryDate::Target::Mastodon> with L<Mastod...
Your new C<App::SpreadRevolutionaryDate::Target::Mytarget> target class should consumes the L<App::SpreadRevolutionaryDate::Target> role, by specifying the C<worker> class:
use Moose;
with 'App::SpreadRevolutionaryDate::Target'
=> {worker => 'My::Worker::Class'};
Then, you have to add a hook, being called before C<Moose> constructor, so to pass as an additional argument to C<Moose> constructor, an instance of your C<worker> class as C<obj> attribute of your new target class. You may need some configuration pa...
around BUILDARGS => sub {
my ($orig, $class) = @_;
my $args = $class->$orig(@_);
my $args->{obj} = My::Worker::Class->new(worker_param => $args->{worker_param});
return $args;
}
Starting from version 0.39, you may have noticed that C<Mastodon> and C<Bluesky> targets can now spread not only a text message, but also an image, with an alternative text for accessibily purpose. If the alternative text is not provided, it is set w...
This feature is not available now for I<IRC> targets, C<Liberachat> and C<Freenode>, since theses targets are mostly for text messages.
Also, we do not plan to extend this feature to C<Twitter> target, since we recommand to not use this social network for political reasons.
Starting from version 0.45, C<Mastodon> and C<Bluesky> classes have a C<max_lenght> attribute (set to 300 for C<Mastodon> and set to 250 for C<Bluesky>), which is used to split a longer message into a thread of multiple posts. Again, we do not plan t...
=head1 EXTENDING TO NEW MESSAGE MAKERS
It is even easier to spread whatever you want instead of the revolutionary date. You should write a new class in the C<App::SpreadRevolutionaryDate::MsgMaker::> namespace (that is: the class should be C<App::SpreadRevolutionaryDate::MsgMaker::MyMsgMa...
The name of the message maker should be set as a value of the L</msgmaker> option.
Such a message maker class is actually just a wrapper. Usually a message maker has to use an existing specific module (which can be a C<Moose> class or not) to craft the message. L<App::SpreadRevolutionaryDate::MsgMaker::RevolutionaryDate> uses L<Dat...
If your new message maker class needs specific parameters (other than C<locale>, which comes with L<App::SpreadRevolutionaryDate::MsgMaker> role), they should be defined as attributes of this class. Values for such attributes should be set in the L<...
Have a look to L<App::SpreadRevolutionaryDate::MsgMaker::PromptUser> or L<App::SpreadRevolutionaryDate::MsgMaker::Telechat> classes, they show simple examples on how to extend C<spread-revolutionary-date> to a new message maker.
=head2 Gemini message maker
From version 0.45, a new message maker is included which requests I<Gemini> AI. This allows to extend C<spread-revolutionary-date> just by configuring a few options. The most practical way to configure these options is to prepare everything by settin...
This way, you can setup different prompts in your configuration file. Here is an example with 4 different prompts configured:
[Gemini]
# See https://ai.google.dev/gemini-api/docs/api-key
api_key = 'GEMINI_API_KEY'
prompt FamousBirthday = 'Which famous people have their birthday on $month_name $day? Give a list of up to 6 people, then after the list give the unformatted URL of the Wikipedia page of only one of them, no comments and no need for an intro...
intro FamousBirthday = 'FamousBirthday=Famous people born on $month_name $day for better or for worse:'
prompt MacronJokeColuche = 'Invente-moi une blague dans le style de Coluche sur Emmanuel Macron. Pas besoin de dire "D\'accord, voici une blague" ou "Bien sûr, voici une blague dans le style de Coluche sur Emmanuel Macron" avant la blague.'
img_path MacronJokeColuche = '/usr/local/share/perl/5.32.1/auto/share/dist/App-SpreadRevolutionaryDate/images/coluche_macron.png'
img_alt MacronJokeColuche = 'Caricature de Coluche disant : « Câest lâhistoire dâun mecâ¦Â » avec une caricature de macron'
prompt BlanquiRevival = 'Invente-moi un dicton révolutionnaire dans le style d\'Auguste Blanqui. Ne fais pas d\'introduction.'
img_url BlanquiRevival = 'https://example.com/imgs/my_image.jgp'
prompt MeteoParis = 'Quelle est la météo aujourd\'hui à Paris, avec la température, selon meteo-paris.com, ne devine pas, va chercher l\'information.'
search MeteoParis = 1
and, then choose the prompt to use at execution time, like:
$ spread-revolutionary-date --msgmaker=Gemini --gemini_process=FamousBirthday --locale=en
$ spread-revolutionary-date --msgmaker=Gemini --gemini_process=MacronJokeColuche
$ spread-revolutionary-date --msgmaker=Gemini --gemini_process=BlanquiRevival
$ spread-revolutionary-date --msgmaker=Gemini --gemini_process=MeteoParis
These examples show how you can tweak your message to be spread. Let's review all these options:
First, you have to define credentials to use the I<Gemini API>, by defining the L</api_key> option. For this you need to get a I<Gemini API key>, by following instructions on L<https://ai.google.dev/gemini-api/docs/api-key>.
Then for each prompt, you have to choose an identifier, which is one word in camel case, like C<FamousBirthday>, C<MacronJokeColuche>, C<BlanquiRevival> or C<MeteoParis>. This prompt identifier should be the value of the C<< --gemini_process <ThisPro...
All other options are relative to one particular prompt, and therefore prefixed with the corresponding identifier. Under the hood, these options are hashes keyed with prompt identifiers:
=over
=item L</prompt>
This is the option where you can define your prompt. It is advised to test this prompt to have I<Gemini> answer as you wish. For instance, I<Gemini> often start its answers to your prompt by: âSure, here is âwhat you've asked forâ, and you woul...
You can test your prompt with interactive form to I<Gemini> at L<https://gemini.google.com/app> or with C<spread-revolutionary-date> with options C<--test> and C<--targets=Mastodon> for example.
The spread message will be I<Gemini> answer, optionally prepended with a configured introduction (see bellow), and ending with hashtags C<#IAGenerated> C<#PromptIdentifier>.
Prompts often need to mention informations relative to today, such as the C<FamousBirthday> example below, or it could be that you wanna ask I<Gemni> for today's weather, or traffic jams occuring the same day of the week as today, etc. As a syntactic...
'Which famous people have their birthday on June 21? Give a list of up to 6 people, then after the list give the unformatted URL of the Wikipedia page of only one of them, no comments and no need for an introduction like "Here are some famous peopl...
You should be careful that such variables are not interpreted by the C<Shell> before calling C<spread-revolutionary-date>, specially if specified as command line parameters. You can prevent such intepretation by the C<Shell> by enclosing the option i...
=item L</intro>
You may want that the spread message to start with your own introducing words before displaying I<Gemini> answer. You can specify this with the L</intro> option.
Likewise, this option use the same syntactic sugar relative to methods of L<DateTime> module. For example, the message spread on June 21st by the C<FamousBirthday> example bellow, would be something like
Famous people born on June 21 for better or for worse:
First Name
Second Name
Third Name
Fourth Name
Fifth Name
Sixth Name
https://en.wikipedia.org/wiki/Third_Name
#IAGenerated #FamousBirthday
=item L</search>
I<Gemini> answer is based on data that have been used to train the AI. But sometimes you want accurate answers grounded on some real time searches. In this case, you should specify the L</search> option with a true value, and I<Gemini> answers will b...
This is used in the C<MeteoParis> example bellow, to have I<Gemini> search for today's weather in Paris from C<meteo-paris.com> website.
=item L</img_path>
This option allows to add a local image on the spread message.
=item L</img_alt>
This option specifies an alternative text to an image added on the spread message. If unset, the alternative text will be the name of the file specified in L</img_path> or L</img_url> options.
=item L</img_url>
This option allows to add a remote image on the spread message.
=back
Finally, one word of localization: you don't need it, since I<Gemini> will answer in the language you've used in your prompt. Or you can ask in your prompt to be answered in another language, like:
prompt FamousBirthday = 'Which famous people have their birthday on $month_name $day? Give a list of up to 6 people, then after the list give the unformatted URL of the Wikipedia page of only one of them, no comments and no need for an intro...
The only place where you should be concerned by localization is when you define an introduction to be prepended to I<Gemini> answer. Since it is a configured static string, it should be written in the desired language, like:
intro FamousBirthday = 'FamousBirthday=Berühmte Personen, die am $day $month_name geboren wurden, im Guten wie im Schlechten:'
Also, if you use some syntactic sugars relative to methods of L<DateTime> module that are localizable, like C<month_name>, you should use the L</locale> option to have it translated in the desired language.
And now you are ready to spread whatever your like, with just some configuration tweaks!
Be aware that I<Gemini>, like any other AI, has no concept of truth. It can only give formally probable answers, based on its training data. So do not ask somehing where truth matters⦠Also, all data you're sending to I<Gemini> are assumed to not b...
=head1 INTERNATIONALIZATION AND LOCALIZATION
Starting from version 0.11, this distribution uses the widespread internationalization and localization system L<gettext|https://en.wikipedia.org/wiki/Gettext>, commonly used for writing multilingual programs. See L<GNU gettext documentation|https://...
Translators can find a portable object template C<po/App-SpreadRevolutionaryDate.pot> which includes all translatable strings used by C<spread-revolutionary-date> (but not translations of days, months, feasts used in the French Revolutionary Calendar...
msgid "Please, enter message to spread"
A German translator would have to replace the next line:
msgstr ""
by:
msgstr "Bitte geben Sie die Nachricht zu verbreiten ein"
When the string to be translated includes some words in curly braces, these words are actually named variables and should be left as is in the translation. E.g.:
msgid "or {abort} to abort"
msgstr "oder {abort}, um abzubrechen"
And that's it! As of version 0.11 of C<spread-revolutionary-date>, there is only about a dozen of strings to translate, mainly for C<PromptUser> message maker. But with the possibility to extend to other message makers, you may need more and more str...
Translating days, months and feasts used in the C<RevolutionaryDate> message maker do not use the C<gettext> system. Mainly because it uses L<DateTime::Calendar::FrenchRevolutionary> which proposes French and English translations in dedicated Perl mo...
Just copy the French class (from C<lib/App/SpreadRevolutionaryDate/MsgMaker/RevolutionaryDate/Locale/fr.pm> file) into the desired language, change the name of the class and replace every French string. E.g.: the names of the months should be replace...
has '+months' => (
default => sub {[
'Vendémiaire', 'Brumaire', 'Frimaire',
'Nivôse', 'Pluviôse', 'Ventôse',
'Germinal', 'Floréal', 'Prairial',
'Messidor', 'Thermidor', 'Fructidor',
'jour complémentaire',
]},
);
by names in German:
has '+months' => (
default => sub {[
'Herbstmonat', 'Nebelmonat', 'Reifmonat',
'Schneemonat', 'Regenmonat', 'Windmonat',
'Keimmonat', 'Blütenmonat', 'Wiesenmonat',
'Erntemonat', 'Hitzemonat', 'Fruchtmonat',
'Ergänzungstage',
]},
);
Feasts include a special trick, because they can be used in sentences like I<this is C<feast name> day> or I<c'est le jour de la C<feast name>>. Depending on the language, it could then be prefixed or suffixed: in English it is suffixed by C< day>, w...
Note also that any space in the name of the feast of the day should be replaced by an underscore (C<_>).
Finally, these translation classes include a mapping between the feast of the day and the wikipedia entry for this word. This is useful when the feast of the day corresponds to an ambiguous entry, or a different word, in wikipedia. If the wikipedia e...
has '+wikipedia_entries' => (
default => sub {{
2 => {
'water chestnut' => 'Water_caltrop',
},
8 => {
'hoe' => 'Hoe_(tool)',
},
}},
);
Because of the trick on prefix and suffix for feasts and the needed mapping for wikipedia entries, using the C<gettext> system would be quite difficult. It wouldn't be an issue for translating names of months or days. But for consistency reasons, I'd...
=head1 SEE ALSO
=over
=item L<App::SpreadRevolutionaryDate>
=item L<DateTime::Calendar::FrenchRevolutionary>
=item L<AppConfig>
=item L<App::SpreadRevolutionaryDate::BlueskyLite>
=item L<Twitter::API>
=item L<Mastodon::Client>
=item L<Bot::BasicBot>
=back
=head1 AUTHOR
Gérald Sédrati <gibus@cpan.org>
=head1 COPYRIGHT AND LICENSE
This software is Copyright (c) 2019-2026 by Gérald Sédrati.
This is free software, licensed under:
The GNU General Public License, Version 3, June 2007
=cut
( run in 0.762 second using v1.01-cache-2.11-cpan-8f98c5d2c55 )