Kaynağa Gözat

Partial Twitch downloader. I would use NightDev's TwitchDown but they are not interested in saring with other programmers.

Zachary Kotlarek 11 yıl önce
ebeveyn
işleme
c395821cec
1 değiştirilmiş dosya ile 140 ekleme ve 0 silme
  1. 140 0
      twitch.pl

+ 140 - 0
twitch.pl

@@ -0,0 +1,140 @@
+#!/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;
+}