StreamFinder

 view release on metacpan or  search on metacpan

lib/StreamFinder/Anystream.pm  view on Meta::CPAN

	my $response = $ua->get($url2fetch);
	if ($response->is_success) {
		$html = $response->decoded_content;
	} else {
		print STDERR $response->status_line  if ($DEBUG);
	}
	unless ($html) {  #STEP 1 FAILED, INVALID URL, PUNT!
		print STDERR "-!!!- COULD NOT FETCH URL=$url2fetch=\n"  if ($DEBUG);
		return undef;
	}
	my $isHLSpage = ($html =~ /#EXTM3U/) ? 1 : 0;  #SEE AUDACIOUS ISSUE#1169 FOR EMBEDDED HLS IN HTML PAGE EXAMPLE USED FOR THIS CODE:
	my $streamExts = join('|',@okStreams);
	print STDERR "-1: HLS=$isHLSpage=\n----html=$html=\n"  if ($DEBUG > 1);
	return undef  unless ($html =~ /\<\!DOCTYPE\s+(?:html|text)/i
			|| ($isHLSpage && $streamExts =~ /(?:m3u8|any|all)/i));  #STEP 1 FAILED, INVALID STATION URL, PUNT!

	print STDERR "-1: GOT SOME(<=2048 BYTES) HTML!\n"  if ($DEBUG);
	$ua->requests_redirectable([])  if ($isHLSpage);
	unless ($isHLSpage) {
		print STDERR "-1a: NOW RE-FETCH FULL PAGE!\n"  if ($DEBUG);
		$ua->max_size(undef);  #(NOW OK TO FETCH THE WHOLE DOCUMENT)

lib/StreamFinder/Apple.pm  view on Meta::CPAN

			my $no_wget = system('wget','-V');
			unless ($no_wget) {
				print STDERR "\n..trying wget...\n"  if ($DEBUG);
				$html = `wget -t 2 -T 20 -O- -o /dev/null "$url2fetch" 2>/dev/null `;
			}
		}
		print STDERR "-1: html=$html=\n"  if ($DEBUG > 1);

		return undef  unless ($html);

		if ($url2fetch =~ s#\/\/embed.podcast#\/\/podcast#) {  #HANDLE "EMBEDDED PODCAST URLS:
			print STDERR "--2a: EMBEDDED PODCAST, take 5, then fetch podcast page ($url2fetch)...\n"  if ($DEBUG);
			sleep 5;  #AVOID HITTING 'EM TOO QUICK IN SUCCESSION (AVOID DOS SUSPICION):
			$response = $ua->get($url2fetch);
			if ($response->is_success) {  #JETCH PODCAST PAGE:
				$html = $response->decoded_content;
			} else {
				print STDERR $response->status_line  if ($DEBUG);
				my $no_wget = system('wget','-V');
				unless ($no_wget) {
					print STDERR "\n..trying wget...\n"  if ($DEBUG);
					$html = `wget -t 2 -T 20 -O- -o /dev/null "$url2fetch" 2>/dev/null `;
				}
			}

			print STDERR "-1: html=$html=\n"  if ($DEBUG > 1);
			return undef  unless ($html);

			if ($html =~ m#${url2fetch}\?i\=(\d+)#s) {
				$self->{'id'} = $1;
				$url2fetch .= '?i=' . $1;
				print STDERR "--3: EMBEDDED EPISODE FOUND (id=$1): URL=$url2fetch)!\n"  if ($DEBUG);
			} else {
				print STDERR "f:Could not find embedded episode in ($url2fetch), aborting!\n";
				return undef;
			}
		} else {
			$url2fetch = ($html =~ m#\,\"uploadDate\"\:\"[^\"]+\"\,\"url\"\:\"([^\"]+)#)
					? $1 : '';
			return undef  unless ($url2fetch);
			$self->{'id'} = ($url2fetch =~ m#\/(?:id)?(\d\d\d\d\d+)(?:\?i\=(\d+))?\/?#) ? $1 : '';
			$self->{'id'} .= '/'. $2  if (defined $2);

lib/StreamFinder/BrandNewTube.pm  view on Meta::CPAN

				$self->{'albumartist'} ||= $1;
				($self->{'artist'} = $2) =~ s#\s+$##s;
			}

			#TRY TO FETCH STREAMS:
			while ($html =~ s#\<source\s+.*?src\=\"([^\"]+)\"##s) {
				my $one = $1;
				push @{$self->{'streams'}}, $one  unless ($self->{'secure'} && $one !~ /^https/);
				$self->{'cnt'}++;
			}
			#STEP 2:  TRY FETCHING THE EMBED URL UNLESS WE FOUND STREAM(S):
#DEPRECIATED?			$url2fetch = $1  if ($self->{'cnt'} <= 0
#DEPRECIATED?					&& $html =~ m#\<iframe\s+src\=\"($baseURL\/embed\/[^\"]+)#s);
			print STDERR "*** EMBED PAGE URL($1) FOUND!\n"  if ($self->{'cnt'} <= 0
					&& $html =~ m#\<iframe\s+src\=\"($baseURL\/embed\/[^\"]+)#s);
		}
	}

	$self->{'cnt'} = scalar @{$self->{'streams'}};
	$self->{'title'} =~ s/\s+\-\s+$self->{'artist'}\s*$//;  #CONVERT "Title - Artist" => "Title"
	foreach my $field (qw(description artist title)) {
		$self->{$field} = HTML::Entities::decode_entities($self->{$field});
		$self->{$field} = uri_unescape($self->{$field});
		$self->{$field} =~ s/(?:\%|\\?u?00)([0-9A-Fa-f]{2})/chr(hex($1))/eg;

lib/StreamFinder/PodcastAddict.pm  view on Meta::CPAN

	my @epiStreams = ();
	my $ua = LWP::UserAgent->new(@{$self->{'_userAgentOps'}});		
	$ua->timeout($self->{'timeout'});
	$ua->cookie_jar({});
	$ua->env_proxy;
	my $html = '';
	my $response;
	my $isEpisode;

#NOTE:  THE ONLY "EPISODE" URLS NOW USED BY PODCASTADDICT ARE THE URI-ESCAPED ONES CONTAINING
#THE STREAM URL EMBEDDED IN THEIR PODCAST PAGES (WITH NO EPISODE-ID#) AND HAVE THE FORMAT (EXAMPLE):
#"https://podcastaddict.com/episode/https%3A%2F%2Fpscrb.fm%2Frss%2Fp%2Fpdst.fm%2Fe%2Farttrk.com%2Fp%2FABMA5%2Faudioboom.com%2Fposts%2F8280770.mp3%3Fmodified%3D1681401989%26sid%3D2399216%26source%3Drss&podcastId=1719501"
#TO PREVENT USING THE FULL STREAM-URL FOR THE UNIQUE EPISODE-ID#, WE JUST USE THE PODCAST-ID#.
#NO KNOWN WAY EXISTS FOR FETCHING EPISODES VIA JUST A PODCAST AND EPISODE-ID, THEREFORE WE CAN'T
#DETERMINE WHAT THE REAL EPISODE-ID IS, EXCEPT ON PODCAST PAGES STILL USING THE CLASSIC, UNESCAPED
#EPISODE-URLS (format:  "https://podcastaddict.com/episode/<episode-ID-number>")!
#(NOTE ALSO THAT THE "&podcastId=#####" PART OF THE URL IS *NOT* THE SEARCHABLE PODCAST-ID EITHER,
#BUT RATHER THE PODCAST ARTIST'S/CHANNEL ID#)!

TRYIT:
	if ($url2fetch =~ m#^([0-9]+)$#) {  #ASSUME PODCAST-ID, AS EPISODES NO LONGER HAVE DESCERNABLE IDs:
		$self->{'id'} = $1;
		$url2fetch = "$baseURL/podcast/".$self->{'id'};
		$isEpisode = 0;
		print STDERR "-1- PODCAST ID, ID=".$self->{'id'}."= found ($url2fetch)\n"  if ($DEBUG);
	} elsif ($url2fetch =~ m#\/episode\/https?#) { #(LONG) EPISODE URL (ON PODCAST PAGES, ESCAPED):
		$url2fetch = uri_escape($url2fetch)  unless($url2fetch =~ m#\%3A#);  #PODCASTADDICT EPISODE URLS NOW MUST BE URI-ESCAPED!
		#$self->{'id'} IS NOT EMBEDDED OR DETERMINABLE, WILL SET TO PODCAST-ID LATER!
		$isEpisode = 1;
		print STDERR "-2- EPISODE URL, ID=UNKNOWN= found ($url2fetch)\n"  if ($DEBUG);
	} elsif ($url2fetch =~ m#\/episode\/(\d+)\/?$#) {  #CLASSIC (SHORT) EPISODE URL WITH ID. (DEPRECIATED)
		$self->{'id'} = $2;  #CLASSIC EPISODE URLS HAVE A PROPER EPISODE-ID EMBEDDED!
		$isEpisode = 1;
		print STDERR "-3- CLASSIC EPISODE URL, ID=".$self->{'id'}."= found ($url2fetch)\n"  if ($DEBUG);
	} elsif ($url2fetch =~ m#\/podcast\/([^\/]+)#) {  #PODCAST URL
		$self->{'id'} = $1;  #USE UNIQUE NUMBER AS A MADE-UP "EPISODE-ID"
		$self->{'id'} = $1  if ($url2fetch =~ m#\/(\d\d\d\d+)$#);
		$isEpisode = 0;
		print STDERR "-4- PODCAST URL, ID=".$self->{'id'}."= found ($url2fetch)\n"  if ($DEBUG);
	} elsif ($url2fetch =~ m#^([^\/]+)\/(\d+)#) {  #EPISODE-ID:
		my $podcastID = $1;
		my $episodeID = $2;

lib/StreamFinder/Rumble.pm  view on Meta::CPAN

			#STEP 2:  FETCH THE STREAMS FROM THE "embedUrl":
			return $url2;
		}
		return '';
	};

	local *getEmbedPage = sub {
		my $url2fetch = shift;
		my $html = '';

		print STDERR "-FETCHING EMBED URL=$url2fetch=\n"  if ($DEBUG);
		$response = $ua->get($url2fetch);
		if ($response->is_success) {
			$html = $response->decoded_content;
		} else {
			print STDERR $response->status_line  if ($DEBUG);
			my $no_wget = system('wget','-V');
			unless ($no_wget) {
				print STDERR "\n..trying wget...\n"  if ($DEBUG);
				$html = `wget -t 2 -T 20 -O- -o /dev/null "$url2fetch" 2>/dev/null `;
			}

lib/StreamFinder/Rumble.pm  view on Meta::CPAN

			}

			if ($html =~ m#\"author\"\:\{\"name\"\:\"([^\"]+)\"\,\"url\"\:\"([^\"]+)#s) {
				$self->{'artist'} ||= $1;
				$self->{'albumartist'} ||= $2;
			}
			if ($html =~ m#\"pubDate\"\:\"([^\"]+)#s) {
				$self->{'created'} = $1;
				$self->{'year'} ||= $1  if ($self->{'created'} =~ /(\d\d\d\d)/);
			}
			if ($html =~ m#\"i\"\:\"([^\"]+)#s) {  #GRAB EMBEDDED IMAGE URL IN CASE MAIN PAGE IS "PRIVATE"(UNFETCHABLE):
				$self->{'iconurl'} ||= $1;
				$self->{'imageurl'} ||= $self->{'iconurl'};
			}
			return $url2;
		} else {
			$url2fetch =~ s#\/embed\/#\/#;
			print STDERR "---EMBED PAGE: NO HTML, TRY CHANNEL PAGE ($url2fetch)!...\n"  if ($DEBUG);
			return &getChannelPage($url2fetch);
		}
		return '';
	};

	$url = "$baseURL/embed/${url}/"  if ($url !~ m#http# && $url !~ m#\-#);
	my $tried = 0;
TRYIT:
	print STDERR "-${tried}(Rumble): URL=$url=\n"  if ($DEBUG);
	if ($url =~ m#\/embed\/#i) {

lib/StreamFinder/Spreaker.pm  view on Meta::CPAN

		$self->{'year'} = $1  if ($self->{'created'} =~ /(\d\d\d\d)/o);
		my $stream = ($html =~ m#\"download\_url\"\:\"([^\"]+)#s) ? $1 : '';
		if ($stream) {
			unless ($self->{'secure'} && $stream !~ /^https/o) {
				push @epiTitles, $self->{'title'};
				push @epiStreams, $stream;
				push @{$self->{'streams'}}, $stream;
				$self->{'cnt'}++;
			}
		}
	} else {    #EXTRACT PODCAST PAGE DATA FROM EMBEDDED, ENCODED JSON:
		$html = HTML::Entities::decode_entities($html);
		$html = uri_unescape($html);
		$html =~ s#\\\/#\/#gs;
		$self->{'album'} = ($html =~ m#\<meta\s+property\=\"(?:og|twitter)\:title\"\s+content\=\"([^\"]+)\"\s*\/\>#s) ? $1 : '';
		$self->{'articonurl'} = ($html =~ m#\<link\s+rel\=\"image\_src\"\s+href\=\"([^\"]+)#s) ? $1 : '';
		$self->{'articonurl'} ||= ($html =~ m#\<meta\s+property\=\"(?:og|twitter)\:image\"\s+content\=\"([^\"]+)\"\s*\/\>#s) ? $1 : '';
		$self->{'artist'} = ($html =~ m#\"fullname\"\:\"([^\"]+)#s) ? $1 : '';
		$self->{'genre'} = ($html =~ m#\"category\_id\"\:\d+\,\"name\"\:\"([^\"]+)#s) ? $1 : '';

		my $episodes = $1  if ($html =~ m#\"episodes\"\:\[(.+)$#s);

lib/StreamFinder/Youtube.pm  view on Meta::CPAN

		} elsif ($_[0] =~ /^\-?youtube-dl-args$/o) {
			shift;
			$self->{'youtube-dl-args'} = shift  if (defined $_[0]);
		} elsif ($_[0] =~ /^\-?youtube-dl-add-args$/o) {
			shift;
			$self->{'youtube-dl-add-args'} = shift  if (defined $_[0]);
		} else {
			shift;  #DISCARD ANY OTHERS.
		}
	}
	$self->{'youtubeonly'} = 1  if ($self->{'noiframes'});  #NO EMBEDDED RUMBLE-SEARCH IF NO IFRAMES ALLOWED!

	$self->{'youtube-dl'} = 'yt-dlp'  unless (defined $self->{'youtube-dl'});

	print STDERR "-0(Youtube): URL=$url=\n"  if ($DEBUG);
	$url =~ s/[\?\&]autoplay\=true$//;  #STRIP THIS OFF SO WE DON'T HAVE TO.
	$url =~ s/[\?\&]list\=.*$//;  #yt-dlp SEEMS TO JUST HANG ON "lists" (TRYING TO FETCH A LIST OF VIDEOS?!).
	(my $url2fetch = $url);
	$self->{'_isaYtPage'} = 1;
	#DEPRECIATED (STATION-IDS NOW INCLUDE STUFF BEFORE THE DASH: ($self->{'id'} = $url) =~ s#^.*\-([a-z]\d+)\/?$#$1#;
	if ($url2fetch =~ m#^https?\:#) {

lib/StreamFinder/Youtube.pm  view on Meta::CPAN

				$self->{'id'} =~ s/^watch\?v\=//;
				$self->{'id'} =~ s/[\?\&].*$//;
				print STDERR "---FOUND 1ST EPISODE! FETCHING=$url2fetch= ID=".$self->{'id'}."=\n"  if ($DEBUG);
				goto DO_YTDL;   #SKIP NON-YOUTUBE PAGE CHECK (NEXT PARAGRAPH):
			}
		}
		print STDERR "u:DID NOT FIND A VIDEO ON CHANNEL/USER PAGE, PUNT!"  if ($DEBUG);
		return undef;
	}

	#IF NON-YOUTUBE PAGE, LOOK FOR ANYTHING EMBEDDED IN AN IFRAME:

	unless ($self->{'_isaYtPage'} || $self->{'noiframes'}) {
		print STDERR "..1a:See if we have a StreamFinder-supported URL in 1st iframe?...\n"  if ($DEBUG);
		my $embedded_video;
		my $html = '';
		my $ua = LWP::UserAgent->new(@{$self->{'_userAgentOps'}});		
		$ua->timeout($self->{'timeout'});
		$ua->max_size(1024);  #LIMIT FETCH-SIZE TO AVOID INFINITELY DOWNLOADING A STREAM!
		$ua->cookie_jar({});
		$ua->env_proxy;

lib/StreamFinder/Youtube.pm  view on Meta::CPAN

				print STDERR "--embedded YOUTUBE JSON url=$url2fetch=\n"  if ($DEBUG);
				$self->{'_isaYtPage'} = 1;
				$self->{'id'} = $1  if ($url2fetch =~ m#\/([^\/]+)\/?$#);
				$self->{'id'} =~ s/^watch\?v\=//;
				$self->{'id'} =~ s/[\?\&].*$//;
				$self->{'id'} = $1  if (!$self->{'_isaYtPage'} && $url2fetch =~ m#id[\=\:\#]?([^\/\s\=\:\#]+)#);
				last;
			}
			unless ($self->{'youtubeonly'}) {
				if ($html =~ /\bRumble\s*\(\"play\"\,\s+\{\"video\"\:\"([a-z0-9\-\_]+)\"/si) {
					#EXTRACT CERTAIN EMBEDDED RUMBLE VIDEOS NOT NECESSARILY IN AN IFRAME:
					my $embeddedURL = 'https://rumble.com/embed/' . $1;
					my $haveRumble = 0;
					print STDERR "---FOUND AN EMBEDDED RUMBLE VIDEO ($embeddedURL), SEE IF WE CAN GO WITH THAT!\n"  if ($DEBUG);
					eval { require 'StreamFinder/Rumble.pm'; $haveRumble = 1; };
					if ($haveRumble) {
						my %globalArgs = (-debug => $DEBUG);
						foreach my $arg (qw(log logfmt)) {
							$globalArgs{$arg} = $self->{$arg}  if (defined($self->{$arg}) && $self->{$arg});
						}
						$embedded_video = new StreamFinder::Rumble($embeddedURL, %globalArgs);
						return $embedded_video  if (defined($embedded_video) && $embedded_video->count() > 0);
					}
				}

lib/StreamFinder/Youtube.pm  view on Meta::CPAN

		}
	}

	#NOW MANUALLY SCRAPE YOUTUBE PAGE TO TRY TO GET artist, description, year, ETC. DIRECTLY FROM PAGE (IF A YOUTUBE SITE):

	unless ($self->{'fast'}) {  #(FAST MEANS SKIP SCRAPING YOUTUBE PAGE FOR ADDTL. METADATA)
		$try = 0;
RETRYPAGE:
		print STDERR "----(try2=$try= FETCHURL=$url2fetch= isYT?=".$self->{'_isaYtPage'}."=\n"  if ($DEBUG);
		if ($self->{'_isaYtPage'}) {  #WE'RE A YOUTUBE PAGE, FETCH METADATA:
			#CONVERT "embedded" YT PAGES TO ACTUAL PAGE (EMBEDDED PAGES DON'T HAVE THE METADATA WE'RE SEEKING!:
			if ($url2fetch =~ m#^(.+?)\/embed\/([a-z0-9\-\_]{11})#i) {  #TRY FETCHING YOUTUBE SITE FROM THE EMBEDDED URL:
				$url2fetch = $1.'/watch?v='.$2;
			} elsif ($url2fetch =~ m#^\/embed\/([a-z0-9\-\_]{11})#i) {  #IF FAIL, TRY www.youtube.com:
				$url2fetch = $self->{'youtube-site'} . '/watch?v=' .$1;
			}
			print STDERR "-2 (TRY=$try) FETCHING SCREEN URL=$url2fetch= ID=".$self->{'id'}."=\n"  if ($DEBUG);
			my $ua = LWP::UserAgent->new(@{$self->{'_userAgentOps'}});		
			$ua->timeout($self->{'timeout'});
			$ua->cookie_jar({});
			$ua->env_proxy;
			my $html = '';



( run in 0.923 second using v1.01-cache-2.11-cpan-71847e10f99 )