| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140 |
- #!/usr/bin/perl
- use strict;
- use warnings;
- use LWP::UserAgent;
- # App config
- my $HTTP_TIMEOUT = 10;
- my $HTTP_UA = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.75.14 (KHTML, like Gecko) Version/7.0.3 Safari/7046A194A';
- my $HTTP_VERIFY = 0;
- # Globals
- my $LWP;
- my $QUALITY_URL;
- my $STREAM_URL;
- # Command-line parameters
- if (scalar(@ARGV) < 1) {
- die('Usage: ' . $0 . "M3U8_URL\n");
- }
- $QUALITY_URL = $ARGV[0];
- # Environmental parameters
- my $DEBUG = 0;
- if (defined($ENV{'DEBUG'}) && $ENV{'DEBUG'} =~ /(\d+)/) {
- $DEBUG = $1;
- }
- # Prototypes
- sub fetch($$);
- # Fetch and parse the quality playlist
- {
- my $playlist;
- if (fetch($QUALITY_URL, \$playlist) == 200) {
- if ($DEBUG > 1) {
- print STDERR "Quality playist:\n" . $playlist . "\n";
- }
- my $baseURL = $QUALITY_URL;
- $baseURL =~ s/\?[^\?]*$//;
- $baseURL =~ s/\/[^\/]*$//;
- if ($DEBUG > 2) {
- print STDERR 'Quality playlist base URL: ' . $baseURL . "\n";
- }
- my $lastBandwidth = 0;
- my $savedBandwidth = 0;
- foreach my $segment (split(/^/, $playlist)) {
- if ($segment =~ /^\s*$/) {
- next;
- }
- $segment =~ s/^\s+//;
- $segment =~ s/\s+$//;
- # Extract bandwidth data
- if ($segment =~ /^#/) {
- if ($segment =~ /^#EXT-X-STREAM-INF:.*\bBANDWIDTH=(\d+)\b/) {
- $lastBandwidth = $1;
- }
- next;
- }
- # Keep the best stream
- if ($DEBUG > 1) {
- print STDERR 'Considering stream URL (' . $lastBandwidth . '): ' . $segment . "\n";
- }
- if ($lastBandwidth > $savedBandwidth) {
- $savedBandwidth = $lastBandwidth;
- $STREAM_URL = $segment;
- }
- }
- }
- }
- if (!defined($STREAM_URL)) {
- die("Unable to find stream URL\n");
- }
- if ($DEBUG) {
- print STDERR 'Keeping stream URL: ' . $STREAM_URL . "\n";
- }
- # Fetch and parse the stream playlist
- my @stream_segments = ();
- {
- my $playlist;
- if (fetch($STREAM_URL, \$playlist) == 200) {
- if ($DEBUG > 1) {
- print STDERR "Stream playlist:\n" . $playlist . "\n";
- }
- my $baseURL = $STREAM_URL;
- $baseURL =~ s/\?[^\?]*$//;
- $baseURL =~ s/\/[^\/]*$//;
- if ($DEBUG > 2) {
- print STDERR 'Playlist base URL: ' . $baseURL . "\n";
- }
- foreach my $segment (split(/^/, $playlist)) {
- if ($segment =~ /^#/ || $segment =~ /^\s*$/) {
- next;
- }
- $segment =~ s/^\s+//;
- $segment =~ s/\s+$//;
- push(@stream_segments, $baseURL . '/' . $segment);
- }
- }
- }
- # DEV-ONLY DEBUG
- foreach my $segment (@stream_segments) {
- print STDERR $segment . "\n";
- }
- # Cleanup
- exit(0);
- # GET the requested URL, accepting encoded data and extracting the HTTP status code
- sub fetch($$) {
- my ($url, $data) = @_;
- # Init the global LWP as needed
- if (!defined($LWP)) {
- $LWP = new LWP::UserAgent;
- $LWP->agent($HTTP_UA);
- $LWP->timeout($HTTP_TIMEOUT);
- $LWP->ssl_opts({ 'verify_hostname' => $HTTP_VERIFY });
- }
- # Make a request
- my $request = HTTP::Request->new('GET' => $url);
- $request->header('Accept-Encoding' => HTTP::Message::decodable);
- my $response = $LWP->request($request);
- # Do something useful with the response
- my $code = 400;
- if ($response->status_line =~ /^(\d+)\s/) {
- $code = $1;
- }
- ${$data} = $response->decoded_content();
- return $code;
- }
|