File Coverage

blib/lib/Bot/Cobalt/Plugin/Twitter.pm
Criterion Covered Total %
statement 28 114 24.5
branch 0 26 0.0
condition 0 13 0.0
subroutine 10 21 47.6
pod 4 12 33.3
total 42 186 22.5


line stmt bran cond sub pod time code
1             package Bot::Cobalt::Plugin::Twitter;
2             # ABSTRACT: Bot::Cobalt plugin for automatic tweeting
3             $Bot::Cobalt::Plugin::Twitter::VERSION = '0.003';
4 1     1   51629 use strict;
  1         3  
  1         23  
5 1     1   5 use warnings;
  1         2  
  1         22  
6              
7 1     1   382 use Bot::Cobalt;
  1         8952  
  1         5  
8 1     1   1461 use Bot::Cobalt::Common;
  1         190790  
  1         12  
9              
10 1     1   9735 use HTML::Entities qw(decode_entities);
  1         4638  
  1         64  
11 1     1   454 use Mojo::UserAgent;
  1         268434  
  1         9  
12 1     1   506 use Net::Twitter;
  1         1039871  
  1         43  
13 1     1   705 use Text::Unidecode qw(unidecode);
  1         1166  
  1         72  
14 1     1   393 use URI::Find::Simple qw(list_uris);
  1         2571  
  1         1034  
15              
16             my $status_rx = qr/twitter\.com\/\w+\/status\/(\d+)/;
17              
18 1     1 0 241 sub new { bless {}, shift }
19 0     0 0   sub twitter { shift->{twitter} }
20              
21 0     0 1   sub display_tweets { shift->{display_tweets} }
22 0     0 1   sub tweet_topics { shift->{tweet_topics} }
23 0     0 1   sub tweet_links { shift->{tweet_links} }
24 0     0 1   sub retweet_tweets { shift->{retweet_tweets} }
25 0     0 0   sub ua { shift->{useragent} }
26              
27             sub Cobalt_register {
28 0     0 0   my $self = shift;
29 0           my $core = shift;
30 0           my $conf = $core->get_plugin_cfg($self);
31              
32 0   0       $self->{display_tweets} = $conf->{display_tweets} // 1;
33 0   0       $self->{tweet_topics} = $conf->{tweet_topics} // 1;
34 0           $self->{tweet_links} = $conf->{tweet_links};
35 0           $self->{retweet_tweets} = $conf->{retweet_tweets};
36 0           $self->{useragent} = Mojo::UserAgent->new;
37              
38 0           eval {
39             $self->{twitter} = Net::Twitter->new(
40             traits => [ qw(API::RESTv1_1 RetryOnError) ],
41             consumer_key => $conf->{consumer_key},
42             consumer_secret => $conf->{consumer_secret},
43             access_token => $conf->{access_token},
44             access_token_secret => $conf->{access_token_secret},
45 0           ssl => 1,
46             );
47             };
48              
49 0 0         if (my $err = $@) {
50 0           logger->warn("Unable to create Net::Twitter object: $err");
51             }
52              
53 0           register( $self, 'SERVER', qw(public_msg public_cmd_tweet topic_changed) );
54 0           logger->info("Registered, commands: !tweet");
55              
56 0           return PLUGIN_EAT_NONE;
57             }
58              
59             sub Cobalt_unregister {
60 0     0 0   my $self = shift;
61 0           my $core = shift;
62              
63 0           logger->info("Unregistered");
64            
65 0           return PLUGIN_EAT_NONE;
66             }
67              
68             sub Bot_topic_changed {
69 0     0 0   my $self = shift;
70 0           my $core = shift;
71 0           my $topic = ${ shift() };
  0            
72              
73 0 0         return PLUGIN_EAT_NONE if not $self->tweet_topics;
74              
75 0           my $new_topic = $topic->stripped;
76 0           my $status = substr($new_topic, 0, 139);
77              
78 0           $self->twitter->update($status);
79              
80 0           return PLUGIN_EAT_NONE;
81             }
82              
83             sub Bot_public_cmd_tweet {
84 0     0 0   my $self = shift;
85 0           my $core = shift;
86 0           my $msg = ${ shift() };
  0            
87              
88 0           my $context = $msg->context;
89 0           my $channel = $msg->target;
90 0           my $nick = $msg->src_nick;
91              
92 0           my @split = split(/ /, $msg->stripped);
93              
94 0           shift @split; # shift off the command
95              
96 0           my $status = substr( join(' ', @split), 0, 139);
97              
98 0           $self->twitter->update($status);
99              
100 0           return PLUGIN_EAT_ALL;
101             }
102              
103             sub Bot_public_msg {
104 0     0 0   my $self = shift;
105 0           my $core = shift;
106 0           my $msg = ${ shift() };
  0            
107              
108 0 0 0       return PLUGIN_EAT_NONE
      0        
109             unless $self->display_tweets or $self->tweet_links or $self->retweet_tweets;
110              
111 0           my $context = $msg->context;
112 0           my $channel = $msg->target;
113              
114 0           foreach my $uri ( list_uris($msg->message) ) {
115 0 0         next if not $uri;
116              
117 0 0         if ($uri =~ $status_rx) {
    0          
118 0           my $id = $1;
119 0 0         if ($self->retweet_tweets) {
120 0           eval { $self->twitter->retweet($id) };
  0            
121 0 0         if (my $err = $@) {
122 0           logger->warn(
123             "Failed to retweet [$id] - " . $err->twitter_error_text,
124             );
125             }
126             }
127            
128 0 0         if ($self->display_tweets) {
129 0           my $tweet = $self->twitter->show_status($id);
130 0           my $text = $tweet->{text};
131 0           my $name = $tweet->{user}->{name};
132 0           my $sname = $tweet->{user}->{screen_name};
133 0           my $user = sprintf '%s (@%s)', $name, $sname;
134            
135 0           $text = unidecode(decode_entities($text));
136 0           my @lines = split /\n/, $text;
137              
138 0 0         if (@lines == 1) {
139 0           broadcast( 'message', $context, $channel, "$user - $lines[0]" );
140             }
141             else {
142 0           broadcast( 'message', $context, $channel, $user );
143             broadcast( 'message', $context, $channel, " - $_" )
144 0           foreach @lines;
145             }
146 0           return PLUGIN_EAT_ALL;
147             }
148             }
149             elsif ($self->tweet_links) {
150 0           my $title = $self->ua->get($uri)->result->dom->at('title')->text;
151 0   0       my $uni = unidecode($title) || $title;
152 0           my $short = substr($uni, 0, 100);
153            
154 0 0         next if not $title;
155              
156             # my $title = decode_entities(
157             # $ua->get($uri)->result->dom->at('title')->text
158             # ) or next;
159            
160 0 0         if (length($short) < length($uni)) {
161 0           $short = "$short...";
162             }
163              
164 0           eval { $self->twitter->update("$short - $uri") };
  0            
165              
166 0 0         if (my $err = $@) {
167 0           logger->warn(
168             "Failed to tweet URL [$uri]: " . $err->twitter_error_text,
169             );
170             }
171             }
172             }
173 0           return PLUGIN_EAT_NONE;
174             }
175              
176             1;
177              
178             __END__
179              
180             =pod
181              
182             =encoding UTF-8
183              
184             =head1 NAME
185              
186             Bot::Cobalt::Plugin::Twitter - Bot::Cobalt plugin for automatic tweeting
187              
188             =head1 VERSION
189              
190             version 0.003
191              
192             =head1 SYNOPSIS
193              
194             ## In plugins.conf
195             Twitter:
196             Module: Bot::Cobalt::Plugin::Twitter
197             Config: plugins/twitter.conf
198             Opts:
199             display_tweets: 1
200             retweet_tweets: 0
201             tweet_links: 0
202             tweet_topics: 1
203              
204             ## In plugins/twitter.conf
205             ---
206             consumer_key: <twitter consumer key>
207             consumer_secret: <twitter consumer secret>
208             access_token: <twitter access token>
209             access_token_secret: <twitter access token secret>
210              
211             =head1 DESCRIPTION
212              
213             A L<Bot::Cobalt> plugin.
214              
215             This plugin will display the contents of a tweet that is linked in a channel.
216             Additionally, it does a handful of twitter-related functions.
217              
218             =over 4
219              
220             =item display_tweets (default: on)
221              
222             Whenever a twitter status link is said in chat, look it up and display it.
223              
224             =item tweet_links (default: off)
225              
226             Whenever a link is tweeted, tweet it (with title).
227              
228             =item retweet_tweets (default: off)
229              
230             Whenever a tweet is linked, retweet it.
231              
232             =item tweet_topics (default: on)
233              
234             Whenever a topic changes, tweet it.
235              
236             =item !tweet
237              
238             Finally a command, !tweet that will tweet the message you provide it.
239              
240             =back
241              
242             =head1 AUTHOR
243              
244             Scott Miller <scott.j.miller@gmail.com>
245              
246             =head1 COPYRIGHT AND LICENSE
247              
248             This software is copyright (c) 2017 by Scott Miller.
249              
250             This is free software; you can redistribute it and/or modify it under
251             the same terms as the Perl 5 programming language system itself.
252              
253             =cut