| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
2
|
|
|
2
|
|
124019
|
use v5.37.9; |
|
|
2
|
|
|
|
|
9
|
|
|
2
|
2
|
|
|
2
|
|
14
|
use feature 'class'; |
|
|
2
|
|
|
|
|
5
|
|
|
|
2
|
|
|
|
|
364
|
|
|
3
|
2
|
|
|
2
|
|
12
|
no warnings 'experimental::class'; |
|
|
2
|
|
|
|
|
4
|
|
|
|
2
|
|
|
|
|
1470
|
|
|
4
|
2
|
|
|
2
|
|
2312
|
use utf8; |
|
|
2
|
|
|
|
|
705
|
|
|
|
2
|
|
|
|
|
16
|
|
|
5
|
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
package Video::NRK::Cache::ProgramId 3.02; # Dist::Zilla doesn't know about class yet |
|
7
|
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
class Video::NRK::Cache::ProgramId; |
|
9
|
|
|
|
|
|
|
# ABSTRACT: NRK on-demand "PRF" program ID |
|
10
|
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
|
|
12
|
2
|
|
|
2
|
|
176
|
use Carp qw( carp croak ); |
|
|
2
|
|
|
|
|
4
|
|
|
|
2
|
|
|
|
|
140
|
|
|
13
|
2
|
|
|
2
|
|
1262
|
use HTTP::Tiny (); |
|
|
2
|
|
|
|
|
77333
|
|
|
|
2
|
|
|
|
|
74
|
|
|
14
|
2
|
|
|
2
|
|
15
|
use warnings::register; |
|
|
2
|
|
|
|
|
4
|
|
|
|
2
|
|
|
|
|
2945
|
|
|
15
|
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
our $QUICK_ID = 1; # skip HTML parsing if possible, rely on hard-coded API base |
|
18
|
|
|
|
|
|
|
our $NRK_BASE = 'https://tv.nrk.no/program'; |
|
19
|
|
|
|
|
|
|
our $PSAPI_BASE = 'https://psapi.nrk.no'; |
|
20
|
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
field $program_id; |
|
23
|
|
|
|
|
|
|
field $url; |
|
24
|
|
|
|
|
|
|
field $id; |
|
25
|
|
|
|
|
|
|
field $psapi_base :param //= $PSAPI_BASE; |
|
26
|
|
|
|
|
|
|
field $parse :param = undef; |
|
27
|
|
|
|
|
|
|
field $ua :param = HTTP::Tiny->new; |
|
28
|
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
my $nrk_re = qr{//[^/]*nrk\.no(?:/|$)}; |
|
30
|
|
|
|
|
|
|
my $prfid_re = qr/[A-ZØÆÅ]{4}[0-9]{8}/; |
|
31
|
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
method id { $id } |
|
34
|
|
|
|
|
|
|
method url { $url } |
|
35
|
|
|
|
|
|
|
method psapi_base { $psapi_base } |
|
36
|
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
ADJUST { |
|
39
|
|
|
|
|
|
|
$self->parse($parse) if defined $parse; |
|
40
|
|
|
|
|
|
|
} |
|
41
|
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
method parse ($parse_) { |
|
44
|
|
|
|
|
|
|
$parse = $parse_; |
|
45
|
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
# Strategies to obtain the NRK on-demand "PRF" program ID: |
|
47
|
|
|
|
|
|
|
# 1. parse from URL |
|
48
|
|
|
|
|
|
|
# 2. get from HTTP header |
|
49
|
|
|
|
|
|
|
# 3. parse from web page meta data |
|
50
|
|
|
|
|
|
|
# 4. first string on web page that looks like an ID |
|
51
|
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
$self->_parse_as_string and return; |
|
53
|
|
|
|
|
|
|
$url = $parse; |
|
54
|
|
|
|
|
|
|
$self->_parse_from_header and return; |
|
55
|
|
|
|
|
|
|
$self->_parse_from_body and return; |
|
56
|
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
croak "Failed to discover NRK 'PRF' program ID; giving up on '$url'"; |
|
58
|
|
|
|
|
|
|
} |
|
59
|
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
method _parse_as_string () { |
|
62
|
|
|
|
|
|
|
return unless $parse =~ m/^$prfid_re$/; |
|
63
|
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
# the user supplied the program ID instead of the URL |
|
65
|
|
|
|
|
|
|
$id = $parse; |
|
66
|
|
|
|
|
|
|
$url = "$NRK_BASE/$parse"; |
|
67
|
|
|
|
|
|
|
} |
|
68
|
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
method _parse_from_header () { |
|
71
|
|
|
|
|
|
|
return unless $QUICK_ID; |
|
72
|
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
if ($url =~ m<^http.+/($prfid_re)(?:/|$)>) { |
|
74
|
|
|
|
|
|
|
return $id = $1; |
|
75
|
|
|
|
|
|
|
} |
|
76
|
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
$id = eval { $ua->head($url)->{headers}{'x-nrk-program-id'} } // ''; |
|
78
|
|
|
|
|
|
|
return $id if $id =~ m/^$prfid_re$/; |
|
79
|
|
|
|
|
|
|
} |
|
80
|
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
method _parse_from_body () { |
|
83
|
|
|
|
|
|
|
my $res = $ua->get($url, {headers => { Accept => 'text/html' }}); |
|
84
|
|
|
|
|
|
|
$url = $res->{url}; |
|
85
|
|
|
|
|
|
|
carp "Warning: This doesn't look like NRK. Check the URL '$url'" if warnings::enabled && $url !~ m/^https?:$nrk_re/i; |
|
86
|
|
|
|
|
|
|
my $error = $res->{status} eq "599" ? ": $res->{content}" : ""; |
|
87
|
|
|
|
|
|
|
croak "HTTP error $res->{status} $res->{reason} on $url$error" unless $res->{success}; |
|
88
|
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
my $html = $res->{content}; |
|
90
|
|
|
|
|
|
|
my ($base_url) = $html =~ m/\bdata-psapi-base-url="([^"]+)"/i; |
|
91
|
|
|
|
|
|
|
$psapi_base = $base_url if $base_url && $base_url =~ m/https:$nrk_re/i; |
|
92
|
|
|
|
|
|
|
$id = $res->{headers}{'x-nrk-program-id'} // ''; # this header might not have been present in the HEAD response |
|
93
|
|
|
|
|
|
|
return $id if $id =~ m/^$prfid_re$/; |
|
94
|
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
return $id if ($id) = $html =~ m/\bprogram-id(?:"\s+content)?="($prfid_re)"/i; |
|
96
|
|
|
|
|
|
|
return $id if ($id) = $html =~ m/"prf(?:Id"\s*:\s*"|:)($prfid_re)"/; |
|
97
|
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
carp "Warning: Failed to discover NRK 'PRF' program ID; trying harder" if warnings::enabled; |
|
99
|
|
|
|
|
|
|
return $id if ($id) = $html =~ m/\b($prfid_re)\b/; |
|
100
|
|
|
|
|
|
|
return $id if ($id) = $html =~ m/(?:\\u002[Ff]|\%2[Ff])($prfid_re)\b/; |
|
101
|
|
|
|
|
|
|
return $id if ($id) = $html =~ m/(?:[0-9a-z_]|\\u[0-9A-F]{4}|\%[0-9A-F]{2})($prfid_re)\b/; # last-ditch effort |
|
102
|
|
|
|
|
|
|
} |
|
103
|
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
1; |
|
106
|
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
__END__ |