aboutsummaryrefslogtreecommitdiffstats
path: root/lib/WWW/StrawViewer/Utils.pm
diff options
context:
space:
mode:
authorJesús <heckyel@hyperbola.info>2020-03-02 08:18:54 -0500
committerJesús <heckyel@hyperbola.info>2020-03-02 08:18:54 -0500
commitc67158fa409f1b1b4f98a8621a69bb2013b76451 (patch)
treebb4ca80f29cda70734a868d372e00c85e172e7d3 /lib/WWW/StrawViewer/Utils.pm
parentad7ec1785fc28799e10d10e7a679dc5bb4891ee3 (diff)
downloadfair-viewer-c67158fa409f1b1b4f98a8621a69bb2013b76451.tar.lz
fair-viewer-c67158fa409f1b1b4f98a8621a69bb2013b76451.tar.xz
fair-viewer-c67158fa409f1b1b4f98a8621a69bb2013b76451.zip
rebrand app
Diffstat (limited to 'lib/WWW/StrawViewer/Utils.pm')
-rw-r--r--lib/WWW/StrawViewer/Utils.pm801
1 files changed, 0 insertions, 801 deletions
diff --git a/lib/WWW/StrawViewer/Utils.pm b/lib/WWW/StrawViewer/Utils.pm
deleted file mode 100644
index 153aab9..0000000
--- a/lib/WWW/StrawViewer/Utils.pm
+++ /dev/null
@@ -1,801 +0,0 @@
-package WWW::StrawViewer::Utils;
-
-use utf8;
-use 5.014;
-use warnings;
-
-=head1 NAME
-
-WWW::StrawViewer::Utils - Various utils.
-
-=head1 SYNOPSIS
-
- use WWW::StrawViewer::Utils;
-
- my $yv_utils = WWW::StrawViewer::Utils->new(%opts);
-
- print $yv_utils->format_time(3600);
-
-=head1 SUBROUTINES/METHODS
-
-=head2 new(%opts)
-
-Options:
-
-=over 4
-
-=item thousand_separator => ""
-
-Character used as thousand separator.
-
-=item months => []
-
-Month names for I<format_date()>
-
-=item youtube_url_format => ""
-
-A youtube URL format for sprintf(format, videoID).
-
-=back
-
-=cut
-
-sub new {
- my ($class, %opts) = @_;
-
- my $self = bless {
- thousand_separator => q{,},
- youtube_url_format => 'https://www.youtube.com/watch?v=%s',
- }, $class;
-
- $self->{months} = [
- qw(
- Jan Feb Mar
- Apr May Jun
- Jul Aug Sep
- Oct Nov Dec
- )
- ];
-
- foreach my $key (keys %{$self}) {
- $self->{$key} = delete $opts{$key}
- if exists $opts{$key};
- }
-
- foreach my $invalid_key (keys %opts) {
- warn "Invalid key: '${invalid_key}'";
- }
-
- return $self;
-}
-
-=head2 extension($type)
-
-Returns the extension format from a given type.
-
-From a string like 'video/webm;+codecs="vp9"', it returns 'webm'.
-
-=cut
-
-sub extension {
- my ($self, $type) = @_;
- $type =~ /\bflv\b/i ? q{flv}
- : $type =~ /\bwebm\b/i ? q{webm}
- : $type =~ /\b3gpp?\b/i ? q{3gp}
- : $type =~ m{^video/(\w+)} ? $1
- : $type =~ m{^audio/(\w+)} ? $1
- : q{mp4};
-}
-
-=head2 format_time($sec)
-
-Returns time from seconds.
-
-=cut
-
-sub format_time {
- my ($self, $sec) = @_;
- $sec >= 3600
- ? join q{:}, map { sprintf '%02d', $_ } $sec / 3600 % 24, $sec / 60 % 60, $sec % 60
- : join q{:}, map { sprintf '%02d', $_ } $sec / 60 % 60, $sec % 60;
-}
-
-=head2 format_duration($duration)
-
-Return seconds from duration (PT1H20M10S).
-
-=cut
-
-# PT5M3S -> 05:03
-# PT1H20M10S -> 01:20:10
-# PT16S -> 00:16
-
-sub format_duration {
- my ($self, $duration) = @_;
-
- $duration // return 0;
- my ($hour, $min, $sec) = (0, 0, 0);
-
- $hour = $1 if ($duration =~ /(\d+)H/);
- $min = $1 if ($duration =~ /(\d+)M/);
- $sec = $1 if ($duration =~ /(\d+)S/);
-
- $hour * 60 * 60 + $min * 60 + $sec;
-}
-
-=head2 format_date($date)
-
-Return string "04 May 2010" from "2010-05-04T00:25:55.000Z"
-
-=cut
-
-sub format_date {
- my ($self, $date) = @_;
-
- # 2010-05-04T00:25:55.000Z
- # to: 04 May 2010
-
- $date =~ s{^
- (?<year>\d{4})
- -
- (?<month>\d{2})
- -
- (?<day>\d{2})
- .*
- }
- {$+{day} $self->{months}[$+{month} - 1] $+{year}}x;
-
- return $date;
-}
-
-=head2 date_to_age($date)
-
-Return the (approximated) age for a given date of the form "2010-05-04T00:25:55.000Z".
-
-=cut
-
-sub date_to_age {
- my ($self, $date) = @_;
-
- $date =~ m{^
- (?<year>\d{4})
- -
- (?<month>\d{2})
- -
- (?<day>\d{2})
- [a-zA-Z]
- (?<hour>\d{2})
- :
- (?<min>\d{2})
- :
- (?<sec>\d{2})
- }x || return undef;
-
- my ($sec, $min, $hour, $day, $month, $year) = gmtime(time);
-
- $year += 1900;
- $month += 1;
-
- my $lambda = sub {
-
- if ($year == $+{year}) {
- if ($month == $+{month}) {
- if ($day == $+{day}) {
- if ($hour == $+{hour}) {
- if ($min == $+{min}) {
- return join(' ', $sec - $+{sec}, 'seconds');
- }
- return join(' ', $min - $+{min}, 'minutes');
- }
- return join(' ', $hour - $+{hour}, 'hours');
- }
- return join(' ', $day - $+{day}, 'days');
- }
- return join(' ', $month - $+{month}, 'months');
- }
-
- if ($year - $+{year} == 1) {
- my $month_diff = $+{month} - $month;
- if ($month_diff > 0) {
- return join(' ', 12 - $month_diff, 'months');
- }
- }
-
- return join(' ', $year - $+{year}, 'years');
- };
-
- my $age = $lambda->();
-
- if ($age =~ /^1\s/) { # singular mode
- $age =~ s/s\z//;
- }
-
- return $age;
-}
-
-=head2 has_entries($result)
-
-Returns true if a given result has entries.
-
-=cut
-
-sub has_entries {
- my ($self, $result) = @_;
-
- if (ref($result->{results}) eq 'HASH') {
-
- if (exists $result->{results}{comments}) {
- return scalar @{$result->{results}{comments}} > 0;
- }
-
- my $type = $result->{results}{type}//'';
-
- if ($type eq 'playlist') {
- return $result->{results}{videoCount} > 0;
- }
- }
-
- if (ref($result->{results}) eq 'ARRAY') {
- return scalar(@{$result->{results}}) > 0;
- }
-
- return 1; # maybe?
- #ref($result) eq 'HASH' and ($result->{results}{pageInfo}{totalResults} > 0);
-}
-
-=head2 normalize_video_title($title, $fat32safe)
-
-Replace file-unsafe characters and trim spaces.
-
-=cut
-
-sub normalize_video_title {
- my ($self, $title, $fat32safe) = @_;
-
- if ($fat32safe) {
- $title =~ s/: / - /g;
- $title =~ tr{:"*/?\\|}{;'+%!%%}; # "
- $title =~ tr/<>//d;
- }
- else {
- $title =~ tr{/}{%};
- }
-
- join(q{ }, split(q{ }, $title));
-}
-
-=head2 format_text(%opt)
-
-Formats a text with information from streaming and video info.
-
-The structure of C<%opt> is:
-
- (
- streaming => HASH,
- info => HASH,
- text => STRING,
- escape => BOOL,
- fat32safe => BOOL,
- )
-
-=cut
-
-sub format_text {
- my ($self, %opt) = @_;
-
- my $streaming = $opt{streaming};
- my $info = $opt{info};
- my $text = $opt{text};
- my $escape = $opt{escape};
- my $fat32safe = $opt{fat32safe};
-
- my %special_tokens = (
- ID => sub { $self->get_video_id($info) },
- AUTHOR => sub { $self->get_channel_title($info) },
- CHANNELID => sub { $self->get_channel_id($info) },
- DEFINITION => sub { $self->get_definition($info) },
- DIMENSION => sub { $self->get_dimension($info) },
- VIEWS => sub { $self->get_views($info) },
- VIEWS_SHORT => sub { $self->get_views_approx($info) },
- LIKES => sub { $self->get_likes($info) },
- DISLIKES => sub { $self->get_dislikes($info) },
- COMMENTS => sub { $self->get_comments($info) },
- DURATION => sub { $self->get_duration($info) },
- TIME => sub { $self->get_time($info) },
- TITLE => sub { $self->get_title($info) },
- FTITLE => sub { $self->normalize_video_title($self->get_title($info), $fat32safe) },
- CAPTION => sub { $self->get_caption($info) },
- PUBLISHED => sub { $self->get_publication_date($info) },
- AGE => sub { $self->get_publication_age($info) },
- AGE_SHORT => sub { $self->get_publication_age_approx($info) },
- DESCRIPTION => sub { $self->get_description($info) },
-
- RATING => sub {
- my $likes = $self->get_likes($info) // 0;
- my $dislikes = $self->get_dislikes($info) // 0;
-
- my $rating = 0;
- if ($likes + $dislikes > 0) {
- $rating = $likes / ($likes + $dislikes) * 5;
- }
-
- sprintf('%.2f', $rating);
- },
-
- (
- defined($streaming)
- ? (
- RESOLUTION => sub {
- $streaming->{resolution} =~ /^\d+\z/
- ? $streaming->{resolution} . 'p'
- : $streaming->{resolution};
- },
-
- ITAG => sub { $streaming->{streaming}{itag} },
- SUB => sub { $streaming->{srt_file} },
- VIDEO => sub { $streaming->{streaming}{url} },
- FORMAT => sub { $self->extension($streaming->{streaming}{type}) },
-
- AUDIO => sub {
- ref($streaming->{streaming}{__AUDIO__}) eq 'HASH'
- ? $streaming->{streaming}{__AUDIO__}{url}
- : q{};
- },
-
- AOV => sub {
- ref($streaming->{streaming}{__AUDIO__}) eq 'HASH'
- ? $streaming->{streaming}{__AUDIO__}{url}
- : $streaming->{streaming}{url};
- },
- )
- : ()
- ),
-
- URL => sub { sprintf($self->{youtube_url_format}, $self->get_video_id($info)) },
- );
-
- my $tokens_re = do {
- local $" = '|';
- qr/\*(@{[keys %special_tokens]})\*/;
- };
-
- my %special_escapes = (
- a => "\a",
- b => "\b",
- e => "\e",
- f => "\f",
- n => "\n",
- r => "\r",
- t => "\t",
- );
-
- my $escapes_re = do {
- local $" = q{};
- qr/\\([@{[keys %special_escapes]}])/;
- };
-
- $text =~ s/$escapes_re/$special_escapes{$1}/g;
-
- $escape
- ? $text =~ s/$tokens_re/\Q${\$special_tokens{$1}()}\E/gr
- : $text =~ s/$tokens_re/${\$special_tokens{$1}()}/gr;
-}
-
-=head2 set_thousands($num)
-
-Return the number with thousand separators.
-
-=cut
-
-sub set_thousands { # ugly, but fast
- my ($self, $n) = @_;
-
- return 0 unless $n;
- length($n) > 3 or return $n;
-
- my $l = length($n) - 3;
- my $i = ($l - 1) % 3 + 1;
- my $x = substr($n, 0, $i) . $self->{thousand_separator};
-
- while ($i < $l) {
- $x .= substr($n, $i, 3) . $self->{thousand_separator};
- $i += 3;
- }
-
- return $x . substr($n, $i);
-}
-
-=head2 get_video_id($info)
-
-Get videoID.
-
-=cut
-
-sub get_video_id {
- my ($self, $info) = @_;
- $info->{videoId};
-
- #~ ref($info->{id}) eq 'HASH' ? $info->{id}{videoId}
- #~ : exists($info->{snippet}{resourceId}{videoId}) ? $info->{snippet}{resourceId}{videoId}
- #~ : exists($info->{contentDetails}{videoId}) ? $info->{contentDetails}{videoId}
- #~ : exists($info->{contentDetails}{playlistItem}{resourceId}{videoId})
- #~ ? $info->{contentDetails}{playlistItem}{resourceId}{videoId}
- #~ : exists($info->{contentDetails}{upload}{videoId}) ? $info->{contentDetails}{upload}{videoId}
- #~ : do {
- #~ my $id = $info->{id} // return undef;
-
- #~ if (length($id) != 11) {
- #~ return undef;
- #~ }
-
- #~ $id;
- #~ };
-}
-
-sub get_playlist_id {
- my ($self, $info) = @_;
- $info->{playlistId};
-}
-
-sub get_playlist_video_count {
- my ($self, $info) = @_;
- $info->{videoCount};
-}
-
-=head2 get_description($info)
-
-Get description.
-
-=cut
-
-sub get_description {
- my ($self, $info) = @_;
- my $desc = $info->{description};
- (defined($desc) and $desc =~ /\S/) ? $desc : 'No description available...';
-}
-
-=head2 get_title($info)
-
-Get title.
-
-=cut
-
-sub get_title {
- my ($self, $info) = @_;
- $info->{title};
-}
-
-=head2 get_thumbnail_url($info;$type='default')
-
-Get thumbnail URL.
-
-=cut
-
-sub get_thumbnail_url {
- my ($self, $info, $type) = @_;
-
- if (exists $info->{videoId}) {
- $info->{type} = 'video';
- }
-
- if ($info->{type} eq 'playlist') {
- return $info->{playlistThumbnail};
- }
-
- if ($info->{type} eq 'channel') {
- ref($info->{authorThumbnails}) eq 'ARRAY' or return '';
- return $info->{authorThumbnails}[0]{url};
- }
-
- ref($info->{videoThumbnails}) eq 'ARRAY' or return '';
-
- my @thumbs = @{$info->{videoThumbnails}};
- my @wanted = grep{$_->{quality} eq $type} @thumbs;
-
- if (@wanted) {
- return $wanted[0]{url};
- }
-
- warn "[!] Couldn't find thumbnail of type <<$type>>...";
- $thumbs[0]{url};
-}
-
-sub get_channel_title {
- my ($self, $info) = @_;
- #$info->{snippet}{channelTitle} || $self->get_channel_id($info);
- $info->{author};
-}
-
-sub get_author {
- my ($self, $info) = @_;
- $info->{author};
-}
-
-sub get_comment_id {
- my ($self, $info) = @_;
- $info->{commentId};
-}
-
-sub get_comment_content {
- my ($self, $info) = @_;
- $info->{content};
-}
-
-sub get_id {
- my ($self, $info) = @_;
- #$info->{id};
- $info->{videoId};
-}
-
-sub get_channel_id {
- my ($self, $info) = @_;
- #$info->{snippet}{resourceId}{channelId} // $info->{snippet}{channelId};
- $info->{authorId};
-}
-
-sub get_category_id {
- my ($self, $info) = @_;
- #$info->{snippet}{resourceId}{categoryId} // $info->{snippet}{categoryId};
- #"unknown";
- $info->{genre} // 'Unknown';
-}
-
-sub get_category_name {
- my ($self, $info) = @_;
-
- state $categories = {
- 1 => 'Film & Animation',
- 2 => 'Autos & Vehicles',
- 10 => 'Music',
- 15 => 'Pets & Animals',
- 17 => 'Sports',
- 19 => 'Travel & Events',
- 20 => 'Gaming',
- 22 => 'People & Blogs',
- 23 => 'Comedy',
- 24 => 'Entertainment',
- 25 => 'News & Politics',
- 26 => 'Howto & Style',
- 27 => 'Education',
- 28 => 'Science & Technology',
- 29 => 'Nonprofits & Activism',
- };
-
- #$categories->{$self->get_category_id($info) // ''} // 'Unknown';
-
- $info->{genre} // 'Unknown';
-}
-
-sub get_publication_date {
- my ($self, $info) = @_;
- #$self->format_date($info->{snippet}{publishedAt});
- #$self->format_date
- require Time::Piece;
- my $time = Time::Piece->new($info->{published});
- $time->strftime("%d %B %Y");
-}
-
-sub get_publication_age {
- my ($self, $info) = @_;
- ($info->{publishedText} // '') =~ s/\sago\z//r;;
-}
-
-sub get_publication_age_approx {
- my ($self, $info) = @_;
-
- my $age = $self->get_publication_age($info) // '';
-
- if ($age =~ /hour|min|sec/) {
- return "0d";
- }
-
- if ($age =~ /^(\d+) day/) {
- return "$1d";
- }
-
- if ($age =~ /^(\d+) week/) {
- return "$1w";
- }
-
- if ($age =~ /^(\d+) month/) {
- return "$1m";
- }
-
- if ($age =~ /^(\d+) year/) {
- return "$1y";
- }
-
- return $age;
-}
-
-sub get_duration {
- my ($self, $info) = @_;
- #$self->format_duration($info->{contentDetails}{duration});
- #$self->format_duration($info->{lengthSeconds});
- $info->{lengthSeconds};
-}
-
-sub get_time {
- my ($self, $info) = @_;
-
- if ($info->{liveNow}) {
- return 'LIVE';
- }
-
- $self->format_time($self->get_duration($info));
-
- #$self->format_time($self->get_duration($info));
-}
-
-sub get_definition {
- my ($self, $info) = @_;
- #uc($info->{contentDetails}{definition} // '-');
- #...;
- "unknown";
-}
-
-sub get_dimension {
- my ($self, $info) = @_;
- #uc($info->{contentDetails}{dimension});
- #...;
- "unknown";
-}
-
-sub get_caption {
- my ($self, $info) = @_;
- #$info->{contentDetails}{caption};
- #...;
- "unknown";
-}
-
-sub get_views {
- my ($self, $info) = @_;
- $info->{viewCount} // 0;
-}
-
-sub get_views_approx {
- my ($self, $info) = @_;
- my $views = $self->get_views($info);
-
- if ($views < 1000) {
- return $views;
- }
-
- if ($views >= 10 * 1e9) { # ten billions
- return sprintf("%dB", int($views / 1e9));
- }
-
- if ($views >= 1e9) { # billions
- return sprintf("%.2gB", $views / 1e9);
- }
-
- if ($views >= 10 * 1e6) { # ten millions
- return sprintf("%dM", int($views / 1e6));
- }
-
- if ($views >= 1e6) { # millions
- return sprintf("%.2gM", $views / 1e6);
- }
-
- if ($views >= 10 * 1e3) { # ten thousands
- return sprintf("%dK", int($views / 1e3));
- }
-
- if ($views >= 1e3) { # thousands
- return sprintf("%.2gK", $views / 1e3);
- }
-
- return $views;
-}
-
-sub get_likes {
- my ($self, $info) = @_;
- $info->{likeCount} // 0;
-}
-
-sub get_dislikes {
- my ($self, $info) = @_;
- $info->{dislikeCount} // 0;
-}
-
-sub get_comments {
- my ($self, $info) = @_;
- #$info->{statistics}{commentCount};
- 1;
-}
-
-{
- no strict 'refs';
- foreach my $pair (
- [playlist => {'playlist' => 1}],
- [channel => {'channel' => 1}],
- [video => {'video' => 1, 'playlistItem' => 1}],
- [subscription => {'subscription' => 1}],
- [activity => {'activity' => 1}],
- ) {
-
- *{__PACKAGE__ . '::' . 'is_' . $pair->[0]} = sub {
- my ($self, $item) = @_;
-
- if ($pair->[0] eq 'video') {
- return 1 if exists $item->{videoId};
- }
-
- exists $pair->[1]{$item->{type} // ''};
-
- #~ if (ref($item->{id}) eq 'HASH') {
- #~ if (exists $pair->[1]{$item->{id}{kind}}) {
- #~ return 1;
- #~ }
- #~ }
- #~ elsif (exists $item->{kind}) {
- #~ if (exists $pair->[1]{$item->{kind}}) {
- #~ return 1;
- #~ }
- #~ }
-
- #~ return;
- };
-
- }
-}
-
-sub is_channelID {
- my ($self, $id) = @_;
- $id || return;
- $id eq 'mine' or $id =~ /^UC[-a-zA-Z0-9_]{22}\z/;
-}
-
-sub is_videoID {
- my ($self, $id) = @_;
- $id || return;
- $id =~ /^[-a-zA-Z0-9_]{11}\z/;
-}
-
-sub period_to_date {
- my ($self, $amount, $period) = @_;
-
- state $day = 60 * 60 * 24;
- state $week = $day * 7;
- state $month = $day * 30.4368;
- state $year = $day * 365.242;
-
- my $time = $amount * (
- $period =~ /^d/i ? $day
- : $period =~ /^w/i ? $week
- : $period =~ /^m/i ? $month
- : $period =~ /^y/i ? $year
- : 0
- );
-
- my $now = time;
- my @time = gmtime($now - $time);
- join('-', $time[5] + 1900, sprintf('%02d', $time[4] + 1), sprintf('%02d', $time[3])) . 'T'
- . join(':', sprintf('%02d', $time[2]), sprintf('%02d', $time[1]), sprintf('%02d', $time[0])) . 'Z';
-}
-
-=head1 AUTHOR
-
-Trizen, C<< <echo dHJpemVuQHByb3Rvbm1haWwuY29tCg== | base64 -d> >>
-
-
-=head1 SUPPORT
-
-You can find documentation for this module with the perldoc command.
-
- perldoc WWW::StrawViewer::Utils
-
-
-=head1 LICENSE AND COPYRIGHT
-
-Copyright 2012-2020 Trizen.
-
-This program is free software; you can redistribute it and/or modify it
-under the terms of either: the GNU General Public License as published
-by the Free Software Foundation; or the Artistic License.
-
-See L<http://dev.perl.org/licenses/> for more information.
-
-=cut
-
-1; # End of WWW::StrawViewer::Utils