App-MHFS

 view release on metacpan or  search on metacpan

lib/MHFS/Plugin/Kodi.pm  view on Meta::CPAN

package MHFS::Plugin::Kodi v0.7.0;
use 5.014;
use strict; use warnings;
use feature 'say';
use File::Basename qw(basename);
use Cwd qw(abs_path getcwd);
use URI::Escape qw(uri_escape);
use Encode qw(decode encode_utf8);
use File::Path qw(make_path);
use Data::Dumper qw(Dumper);
use Scalar::Util qw(weaken);
use MIME::Base64 qw(encode_base64url decode_base64url);
use Devel::Peek qw(Dump);
use MHFS::Kodi::TVShows;
use MHFS::Kodi::Movie;
use MHFS::Kodi::MovieEdition;
use MHFS::Kodi::MovieEditions;
use MHFS::Kodi::MoviePart;
use MHFS::Kodi::Movies;
use MHFS::Kodi::MovieSubtitle;
use MHFS::Kodi::Season;
use MHFS::Process;
use MHFS::Promise;
use MHFS::Util qw(base64url_to_str str_to_base64url uri_escape_path_utf8 read_text_file_lossy write_text_file_lossy decode_utf_8 escape_html_noquote fold_case write_file read_file);
use Feature::Compat::Try;
BEGIN {
    if( ! (eval "use JSON; 1")) {
        eval "use JSON::PP; 1" or die "No implementation of JSON available";
        warn __PACKAGE__.": Using PurePerl version of JSON (JSON::PP)";
    }
}

sub readtvdir {
    my ($self, $tvshows, $source, $b_tvdir) = @_;
    my $dh;
    if (! opendir ( $dh, $b_tvdir )) {
        warn "Error in opening dir $b_tvdir\n";
        return;
    }
    my @diritems;
    while (my $b_filename = readdir($dh)) {
        next if(($b_filename eq '.') || ($b_filename eq '..'));
        next if(!(-s "$b_tvdir/$b_filename"));
        my $filename = decode('UTF-8', $b_filename, Encode::FB_DEFAULT | Encode::LEAVE_SRC);
        next if (! -d _ && $filename !~ /\.(?:avi|mkv|mp4|m4v)$/);
        if ($filename !~ /^(.+?)(?:[\.\s]+(\d{4}))?[\.\s]+S(?:eason\s)?0*(\d+)/) {
            say "suspicious: $filename";
        }
        if ($filename =~ /S(?:eason\s)?0*(\d+)\-S(?:eason\s)?0*(\d+)/) {
            $self->readtvdir($tvshows, $source, "$b_tvdir/$b_filename");
            next;
        }
        my $showname = $1 || $filename;
        my $year = $2;
        my $season = $3 // 0;
        next if (! $showname);
        $showname =~ s/\./ /g;
        my $showid = fold_case($showname);
        if (! $tvshows->{$showid}) {
            my %show = (name => $showname, seasons => {});
            my $plot = $self->{tvmeta}."/$showid/plot.txt";
            try { $show{plot} = read_text_file_lossy($plot); }
            catch($e) {}
            $tvshows->{$showid} = \%show;
        }
        $tvshows->{$showid}{seasons}{$season} //= {};
        $tvshows->{$showid}{seasons}{$season}{"$source/$b_filename"} = {name => $filename, isdir => (-d _ // 0)+0};
    }
    closedir($dh);
}

lib/MHFS/Plugin/Kodi.pm  view on Meta::CPAN

            return;
        }
    };
    my ($mediatype, $metadatatype, $medianame, $season, $episode) = $request_path =~ m!^/kodi/metadata/(movies|tv)/(thumb|fanart|plot)/([^/]+)(?:/0*(\d+)(?:/0*(\d+))?)?$! or do {
        say "no match";
        $request->Send400;
        return;
    };
    if ($medianame =~ /^.(.)?$/ || ($mediatype eq 'movies' && defined $season)) {
        say "no match";
        $request->Send400;
        return;
    }
    if ($metadatatype eq 'fanart') {
        ($season, $episode) = (undef, undef);
    }
    $medianame = fold_case($medianame);
    say "mt $mediatype mmt $metadatatype mn $medianame". (defined $season ? " season $season". (defined $episode ? " episode $episode" : '') : '');
    my %allmediaparams  = ( 'movies' => {
        'meta' => $self->{moviemeta},
        'search' => 'movie',
    }, 'tv' => {
        'meta' => $self->{tvmeta},
        'search' => 'tv'
    });
    my $params = $allmediaparams{$mediatype};
    my $b_metadir = $params->{meta} . '/' . encode_utf8($medianame) . (defined $season ? '/'.encode_utf8($season). (defined $episode ? '/'.encode_utf8($episode) : '') : '');
    my $b_plotfile =  $params->{meta} . '/' . encode_utf8($medianame) . '/'. (defined $season ? encode_utf8($season).'/season.json' : 'plot.txt');
    # fast path, check disk
    if (defined $season && $metadatatype eq 'plot') {
        try {
            my $bytes = read_file($b_plotfile);
            my $json = decode_json($bytes);
            if (defined $episode) {
                $json = MHFS::Kodi::Season::_get_season_episode($json, $episode);
            }
            $request->SendText('text/plain; charset=utf-8', $json->{overview});
            return;
        } catch ($e){}
    } elsif (-d $b_metadir) {
        my %acceptable = ( 'thumb' => ['png', 'jpg'], 'fanart' => ['png', 'jpg'], 'plot' => ['txt']);
        if(exists $acceptable{$metadatatype}) {
            foreach my $totry (@{$acceptable{$metadatatype}}) {
                my $path = $b_metadir.'/'.$metadatatype.".$totry";
                if(-f $path) {
                    $request->SendLocalFile($path);
                    return;
                }
            }
        }
    }
    # slow path, download it
    $request->{client}{server}{settings}{TMDB} or do {
        $request->Send404;
        return;
    };
    # find the movie or tv show
    my $searchname = $medianame;
    $searchname =~ s/\s\(\d\d\d\d\)// if($mediatype eq 'movies');
    say "searchname $searchname";
    weaken($request);
    _TMDB_api_promise($request->{client}{server}, 'search/'.$params->{search}, {'query' => $searchname})->then(sub {
        my $json = $_[0]->{results}[0];
        $json or die "Failed to find item";
        $season // return $json;
        # find the season and then the episode if applicable
        my $showid = $json->{id} // die "showid not available";
        _TMDB_api_promise($request->{client}{server}, "tv/$showid/season/$season")->then(sub {
            if ($metadatatype eq 'plot' || ! -f $b_plotfile) {
                make_path($b_metadir);
                my $bytes = encode_json($_[0]);
                try { write_file($b_plotfile, $bytes) }
                catch ($e) { say "wierd, creating file failed?"; }
            }
            $episode // return $_[0];
            MHFS::Kodi::Season::_get_season_episode($_[0], $episode)
        })
    })->then(sub {
        # get the metadata
        if (! defined $season && ($metadatatype eq 'plot' || ! -f "$b_metadir/plot.txt")) {
            make_path($b_metadir);
            try { write_text_file_lossy("$b_metadir/plot.txt", $_[0]->{overview}) }
            catch ($e) { say "wierd, creating file failed?"; }
        }
        if($metadatatype eq 'plot') {
            $request->SendText('text/plain; charset=utf-8', $_[0]->{overview});
            return;
        }
        # thumb or fanart
        my $imagepartial = ($metadatatype eq 'thumb') ? (! defined $episode ? $_[0]->{poster_path} : $_[0]->{still_path}) : $_[0]->{backdrop_path};
        if (!$imagepartial || $imagepartial !~ /(\.[^\.]+)$/) {
            die 'path not matched '.$imagepartial;
        }
        my $ext = $1;
        make_path($b_metadir);
        return MHFS::Promise->new($request->{client}{server}{evp}, sub {
            my ($resolve, $reject) = @_;
            if(! defined $self->{tmdbconfig}) {
                $resolve->(_TMDB_api_promise($request->{client}{server}, 'configuration')->then( sub {
                    $self->{tmdbconfig} = $_[0];
                    return $_[0];
                }));
            } else {
                $resolve->();
            }
        })->then( sub {
            return _DownloadFile_promise($request->{client}{server}, $self->{tmdbconfig}{images}{secure_base_url}.'original'.$imagepartial, "$b_metadir/$metadatatype$ext")->then(sub {
                $request->SendLocalFile("$b_metadir/$metadatatype$ext");
                return;
            });
        });
    })->then(undef, sub {
        print $_[0];
        $request->Send404;
        return;
    });
    return;
}

sub new {
    my ($class, $settings) = @_;



( run in 2.266 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )