# File: Weather.pm # # Purpose: Weather command. See Wttr.pm for a more featureful command. # SPDX-FileCopyrightText: 2007-2023 Pragmatic Software # SPDX-License-Identifier: MIT package PBot::Plugin::Weather; use parent 'PBot::Plugin::Base'; use PBot::Imports; use PBot::Core::Utils::LWPUserAgentCached; use XML::LibXML; sub initialize($self, %conf) { $self->{pbot}->{commands}->add( name => 'weather', help => 'Provides weather service via AccuWeather', subref => sub { $self->cmd_weather(@_) }, ); } sub unload($self) { $self->{pbot}->{commands}->remove('weather'); } sub cmd_weather($self, $context) { my $usage = "Usage: weather ( | -u )"; my $arguments = $context->{arguments}; my %opts; my ($opt_args, $opt_error) = $self->{pbot}->{interpreter}->getopt( $arguments, \%opts, ['bundling'], 'u=s', 'h', ); return $usage if $opts{h}; return "/say $opt_error -- $usage" if defined $opt_error; $arguments = "@$opt_args"; my $user_override = $opts{u}; if (defined $user_override) { my $userdata = $self->{pbot}->{users}->{storage}->get_data($user_override); return "No such user account $user_override." if not defined $userdata; return "User account does not have `location` set." if not exists $userdata->{location}; $arguments = $userdata->{location}; } else { if (not length $arguments) { $arguments = $self->{pbot}->{users}->get_user_metadata($context->{from}, $context->{hostmask}, 'location') // ''; } } if (not length $arguments) { return $usage; } return $self->get_weather($arguments); } sub get_weather($self, $location) { my %cache_opt = ( 'namespace' => 'accuweather', 'default_expires_in' => 3600 ); my $ua = PBot::Core::Utils::LWPUserAgentCached->new(\%cache_opt, timeout => 10); my $response = $ua->get("http://rss.accuweather.com/rss/liveweather_rss.asp?metric=0&locCode=$location"); my $xml; if ($response->is_success) { $xml = $response->decoded_content; } else { return "Failed to fetch weather data: " . $response->status_line; } my $dom = XML::LibXML->load_xml(string => $xml); my $result = ''; foreach my $channel ($dom->findnodes('//channel')) { my $title = $channel->findvalue('./title'); my $description = $channel->findvalue('./description'); if ($description eq 'Invalid Location') { return "Location $location not found. Use \", \" (e.g. \"paris, fr\") or a US Zip Code or \", , US\" (e.g., \"austin, tx, us\")."; } $title =~ s/ - AccuW.*$//; $result .= "Weather for $title: "; } foreach my $item ($dom->findnodes('//item')) { my $title = $item->findvalue('./title'); my $description = $item->findvalue('./description'); if ($title =~ m/^Currently:/) { $title = $self->fix_temps($title); $result .= "$title; "; } if ($title =~ m/Forecast$/) { $description =~ s/ fix_temps($description); $result .= "Forecast: $description"; last; } } return $result; } sub fix_temps($self, $text) { $text =~ s|(-?\d+)\s*F|my $f = $1; my $c = ($f - 32 ) * 5 / 9; $c = sprintf("%.1d", $c); "${c}C/${f}F"|eg; return $text; } 1;