EV-Telegram-TDLib
view release on metacpan or search on metacpan
lib/EV/Telegram/TDLib/Stories.pm view on Meta::CPAN
package EV::Telegram::TDLib::Stories;
use strict;
use warnings;
use Carp qw(croak);
use overload ();
our $VERSION = '0.04';
=head1 NAME
EV::Telegram::TDLib::Stories - story methods for EV::Telegram::TDLib
=head1 DESCRIPTION
One of the mixins L<EV::Telegram::TDLib> inherits from. It has no
interface of its own and is not meant to be used directly: loading the
main module loads this one, and its methods are called on a client.
They are documented together with the rest of the API, under
L<EV::Telegram::TDLib/"Stories mixin">.
=cut
sub CLONE_SKIP { 1 }
# a story id is int32 and stays numeric; only the poster chat id is int53
our %UPDATES = (
updateStory => \&update_story,
updateStoryDeleted => \&update_story_deleted,
updateStoryPostSucceeded => \&update_post_succeeded,
updateStoryPostFailed => \&update_post_failed,
updateChatActiveStories => \&update_active_stories,
);
sub posting { $_[0]{cache}{posting} ||= {} }
sub update_story {
my ($self, $obj) = @_;
if (my $cb = $self->{on_story}) { $cb->($obj->{story}) }
}
# The schema says a canceled post yields updateStoryDeleted instead of
# updateStoryPostFailed. That comment is stale for 1.8.66: on_delete_story
# returns early unless the id is a server one (<= 1999999999), while a
# yet-unsent story is numbered from 2000000000 up, so this update never
# carries a provisional id. A cancelled post takes the 406 "Canceled" path
# into delete_pending_story, which emits updateStoryPostFailed -- already
# handled. So there is nothing to resolve here.
sub update_story_deleted {
my ($self, $obj) = @_;
if (my $cb = $self->{on_story_deleted}) {
$cb->($obj->{story_poster_chat_id}, $obj->{story_id});
}
}
# a provisional story id is unique only among one chat's stories, so two
# chats posting at once would otherwise share a key
sub posting_key {
my ($chat_id, $story_id) = @_;
return unless defined $chat_id && defined $story_id;
return (0 + $chat_id) . ':' . (0 + $story_id);
}
sub update_post_succeeded {
my ($self, $obj) = @_;
my $key = posting_key($obj->{story}{poster_chat_id}, $obj->{old_story_id})
or return;
my $cb = delete $self->posting->{$key} or return;
$cb->($obj->{story}, undef);
}
sub update_post_failed {
my ($self, $obj) = @_;
my $key = posting_key($obj->{story}{poster_chat_id}, $obj->{story}{id})
or return;
my $cb = delete $self->posting->{$key} or return;
$cb->(undef, $obj->{error} // { '@type' => 'error', code => -1,
message => 'story post failed' });
}
sub update_active_stories {
my ($self, $obj) = @_;
if (my $cb = $self->{on_active_stories}) { $cb->($obj->{active_stories}) }
}
sub on_story {
my ($self, $cb) = @_;
$self->{on_story} = $cb if @_ > 1;
return $self->{on_story};
}
sub on_story_deleted {
my ($self, $cb) = @_;
$self->{on_story_deleted} = $cb if @_ > 1;
return $self->{on_story_deleted};
}
sub on_active_stories {
my ($self, $cb) = @_;
$self->{on_active_stories} = $cb if @_ > 1;
return $self->{on_active_stories};
}
# A bare path is always a photo. Video needs duration and cover_frame_timestamp,
# which TDLib requires and nothing can infer, so it takes the explicit form.
sub story_content {
my ($content) = @_;
need('content', $content);
return $content if ref $content eq 'HASH' && $content->{'@type'};
if (ref $content eq 'HASH') {
my $video = $content->{video}
or croak 'story content must be a path or { video => ... }';
need('duration, cover_frame_timestamp',
@{$content}{qw(duration cover_frame_timestamp)});
return {
'@type' => 'inputStoryContentVideo',
video => input_file($video),
added_sticker_file_ids => num_list('sticker_file_ids',
$content->{sticker_file_ids} // []),
duration => real('duration', $content->{duration}),
cover_frame_timestamp => real('cover_frame_timestamp',
$content->{cover_frame_timestamp}),
is_animation => json_bool($content->{is_animation}),
};
}
croak 'story content must be a path or a hashref'
if ref $content && !overload::Method($content, '""');
return { '@type' => 'inputStoryContentPhoto',
photo => input_file($content),
added_sticker_file_ids => [] };
}
my %PRIVACY = (everyone => 'storyPrivacySettingsEveryone',
contacts => 'storyPrivacySettingsContacts',
close_friends => 'storyPrivacySettingsCloseFriends');
sub story_privacy {
my ($privacy, $except) = @_;
$privacy = 'everyone' unless defined $privacy;
return $privacy if ref $privacy eq 'HASH';
if (ref $privacy eq 'ARRAY') {
( run in 0.406 second using v1.01-cache-2.11-cpan-57ff5998125 )