File Coverage

blib/lib/StreamFinder.pm
Criterion Covered Total %
statement 9 134 6.7
branch 0 112 0.0
condition 0 78 0.0
subroutine 3 4 75.0
pod 1 1 100.0
total 13 329 3.9


line stmt bran cond sub pod time code
1             =head1 NAME
2              
3             StreamFinder - Fetch actual raw streamable URLs from various radio-station, video & podcast websites.
4              
5             =head1 INSTALLATION
6              
7             To install this module, run the following commands:
8              
9             perl Makefile.PL
10              
11             make
12              
13             make test
14              
15             make install
16              
17             =head1 AUTHOR
18              
19             This module is Copyright (C) 2017-2023 by
20              
21             Jim Turner, C<< >>
22            
23             Email: turnerjw784@yahoo.com
24              
25             All rights reserved.
26              
27             You may distribute this module under the terms of either the GNU General
28             Public License or the Artistic License, as specified in the Perl README file.
29              
30             =head1 SYNOPSIS
31              
32             #!/usr/bin/perl
33              
34             use strict;
35              
36             use StreamFinder;
37              
38             die "..usage: $0 URL\n" unless ($ARGV[0]);
39              
40             my $station = new StreamFinder($ARGV[0]);
41              
42             die "Invalid URL or no streams found!\n" unless ($station);
43              
44             my $firstStream = $station->get();
45              
46             print "First Stream URL=$firstStream\n";
47              
48             my $url = $station->getURL();
49              
50             print "Stream URL=$url\n";
51              
52             my $stationTitle = $station->getTitle();
53            
54             print "Title=$stationTitle\n";
55            
56             my $stationDescription = $station->getTitle('desc');
57            
58             print "Description=$stationDescription\n";
59            
60             my $stationID = $station->getID();
61              
62             print "Station ID=$stationID\n";
63            
64             my $artist = $station->{'artist'};
65              
66             print "Artist=$artist\n" if ($artist);
67            
68             my $genre = $station->{'genre'};
69              
70             print "Genre=$genre\n" if ($genre);
71            
72             my $icon_url = $station->getIconURL();
73              
74             if ($icon_url) { #SAVE THE ICON TO A TEMP. FILE:
75              
76             print "Icon URL=$icon_url=\n";
77              
78             my ($image_ext, $icon_image) = $station->getIconData();
79              
80             if ($icon_image && open IMGOUT, ">/tmp/${stationID}.$image_ext") {
81              
82             binmode IMGOUT;
83              
84             print IMGOUT $icon_image;
85              
86             close IMGOUT;
87              
88             print "...Icon image downloaded to (/tmp/${stationID}.$image_ext)\n";
89              
90             }
91              
92             }
93              
94             my $stream_count = $station->count();
95              
96             print "--Stream count=$stream_count=\n";
97              
98             my @streams = $station->get();
99              
100             foreach my $s (@streams) {
101              
102             print "------ stream URL=$s=\n";
103              
104             }
105              
106             =head1 DESCRIPTION
107              
108             StreamFinder accepts a webpage URL for a valid radio station, video, or podcast
109             / episode URL on supported websites and returns the actual stream URL(s),
110             title, and cover art icon for that station / podcast / video. The purpose is
111             that one needs one of these URLs in order to have the option to stream the
112             station / podcast / video in one's own choice of media player software rather
113             than using their web browser and accepting flash, ads, javascript, cookies,
114             trackers, web-bugs, and other crapware associated with that method of play.
115             The author created and uses his own custom all-purpose media player called
116             "Fauxdacious Media Player" (his custom forked version of the open-source
117             "Audacious Audio Player). "Fauxdacious"
118             (L) incorporates this module via
119             a Perl helper-script to decode and play streams, along with their titles /
120             station names, and station / podcast / video icons, artists / channel names,
121             genres, and descriptions!
122              
123             Please NOTE: StreamFinder is a module, NOT a standalone application. It is
124             designed to be used by other Perl applications. To create your own very simple
125             application just to fetch stream data manually, simply grab the code in the
126             B section above, save it to an executable text file, ie.
127             I, and run it from the command line with a supported streaming
128             site URL as the argument. You can then edit it to tailor it to your needs.
129              
130             The currently-supported websites are:
131             podcasts.apple.com podcasts (L),
132             bitchute.com videos (L),
133             blogger.com videos (L),
134             brandnewtube.com and ugetube.com videos (L),
135             brighteon.com videos (L),
136             castbox.fm podcasts (L),
137             podcasts.google.com podcasts (L),
138             iheartradio.com radio stations and podcasts (L),
139             www.internetradio.com radio stations (L),
140             www.linktv.org videos (L),
141             onlineradiobox.com radio stations (L),
142             odysee.com videos (L),
143             podbean.com podcasts (L),
144             podcastaddict.com podcasts (L),
145             podchaser.com podcasts (L),
146             radio.net radio stations (L),
147             rcast.net radio stations (L),
148             rumble.com videos (L),
149             sermonaudio.com sermons: audio and video (L),
150             soundcloud.com (non-paywalled) songs (L),
151             spreaker.com podcasts (L),
152             tunein.com (non-paywalled) radio stations and podcasts
153             (L), vimeo.com videos (L),
154             youtube.com, et. al and other sites that youtube-dl supports
155             (L),
156             zeno.fm radio stations and podcasts (L),
157             and L - search any (other) webpage URL (not supported
158             by any of the other submodules) for streams.
159              
160             NOTE: StreamFinder::Podcastaddict is now considered depreciated and may be
161             removed in a later StreamFinder release as it now requires a specific valid
162             episode page to fetch streams from, as Podcastaddict.com has javascripted up
163             their podcast pages now to the point that it is no longer possible to obtain
164             a playlist or first episode from them via our scripts.
165              
166             NOTE: StreamFinder::Goodpods has been removed, as that site has redone itself
167             in javascript as to no longer be scrapable for streams.
168              
169             NOTE: For many sites, ie. Youtube, Vimeo, Apple, Spreaker, Castbox, Google,
170             etc. the "station" object actually refers to a specific video or podcast
171             episode, but functions the same way.
172              
173             Each site is supported by a separate subpackage (StreamFinder::I),
174             which is determined and selected based on the URL argument passed to it when
175             the StreamFinder object is created. The methods are overloaded by the selected
176             subpackage's methods. An example would be B.
177              
178             Please see the POD. documentation for each subpackage for important additional
179             information on options and features specific to each site / subpackage!
180              
181             One or more playable streams can be returned for each station / video /
182             podcast, along with at least a "title" (station name / video or podcast episode
183             title) and an icon image URL ("iconurl" - if found). Additional information
184             that MAY be fetched is a (larger?) banner image ("imageurl"), a (longer?)
185             "description", an "artist" / author, a "genre", and / or a "year" (podcasts,
186             videos, etc.), an AlbumArtist / channel URL, and possibly a second
187             icon image for the channel (podcasts and videos). Some sites also provide
188             radio stations' FCC call letters ("fccid"). For icon and image URLs,
189             functions exist (getIconData() and getImageData()) to fetch the actual binary
190             data and mime type for downloading to local storage for use by your
191             application or preferred media player. NOTE: StreamFinder::Anystream is not
192             able to return much beyond the stream URLs it finds, but please see it's POD
193             documentation for details on what it is able to return.
194              
195             If you have another streaming site that is not supported, first, make sure
196             you have B installed and see if B can
197             successfully fetch any streams for it. If not, then please file a feature
198             request via email or the CPAN bug system, or (for faster service), provide a
199             Perl patch module / program source that can extract some or all of the
200             necessary information for streams on that site and I'll consider it! The
201             easiest way to do this is to take one of the existing submodules, copy it to
202             "StreamFinder::I.pm", modify it (and the POD docs) to your
203             specific site's needs, test it on several of their pages (see the "SYNOPSIS"
204             code above), and send it to me (That's what I do when I want to add a
205             new site)!
206              
207             =head1 SUBROUTINES/METHODS
208              
209             =over 4
210              
211             =item B(I [, I ])
212              
213             Accepts a URL and creates and returns a new station, video, or
214             podcast object, or I if the URL is not a valid station or
215             no streams are found.
216              
217             NOTE: Depending on the type of site being queried, the "station
218             object" can be either a streaming station, a video, or a podcast,
219             but works the same way (method calls, arguments, etc.).
220              
221             NOTE: A full URL must be specified here, but if using any of the
222             subpackage modules directly instead, then either a full URL OR just
223             the station / video / podcast's site ID may be used! Reason being
224             that this function parses the full URL to determine which subpackage
225             (site) module to use.
226              
227             I can vary depending on the type of site that is
228             being queried. One option common to all sites is I<-debug>, which
229             turns on debugging output. A numeric option can follow specifying
230             the level (0, 1, or 2). 0 is none, 1 is basic, 2 is detailed.
231             Default: B<1> (if I<-debug> is specified). Warning: 2 will dump a ton
232             of output (mostly the HTML of the web page being parsed!
233              
234             One specific option (I<-omit>, added as of v1.45) permits omitting
235             specific submodules which are currently installed from being considered.
236             For example, to NOT handle Youtube videos nor use the fallback
237             "Anystream" module, specify: I<-omit> => I<"Youtube,Anystream">, which
238             will cause StreamFinder::Anystream and StreamFinder::Youtube to not be used
239             for the stream search. Default is for all installed submodules to be
240             considered. NOTE: Omitting a module from being considered when seeking
241             to match the correct module by site URL does NOT prevent that
242             module from being invoked by a selected module for an embedded link, OR
243             in the case of StreamFinder::Youtube being omitted, will still be invoked,
244             if required or needed by a non-omitted module initially selected!
245              
246             Another global option (applicable to all submodules) is the I<-secure>
247             option who's argument can be either 0 or 1 (I or I). If 1,
248             then only secure ("https://") streams will be returned. NOTE, it's
249             possible that some sites may only contain insecure ("http://") streams,
250             which won't return any streams if this option is specified. Therefore,
251             it may be necessary, if setting this option globally, to set it to
252             zero in the config. files for those specific modules, if you determine
253             that to be the case (I have not tested all sites for that). Default:
254             I<-secure> is 0 (false) - return all streams (http and https).
255              
256             Any other options (including I<-debug>) will be passed to the submodule
257             (if any) that handles the URL you pass in, but note, submodules accept
258             different options and ignore ones they do not recognize. Valid values
259             for some options can also vary across different submodules. A better
260             way to change default options for one or more submodules is to set up
261             submodule configuration files for the ones you wish to change.
262              
263             Additional options:
264              
265             I<-hls_bandwidth> => "I"
266              
267             Limit HLS (m3u8) streams that contain a list of other HLS streams of varying
268             BANDWIDTH values (in BITS per second) by selecting the highest bitrate stream
269             at or below the specified limit when I<$stream>->I is called.
270              
271             DEFAULT I<-none-> (no limiting by bitrate).
272              
273             I<-log> => "I"
274              
275             Specify path to a log file. If a valid and writable file is specified, A line
276             will be appended to this file every time one or more streams is successfully
277             fetched for a url.
278              
279             DEFAULT I<-none-> (no logging).
280              
281             I<-logfmt> specifies a format string for lines written to the log file.
282              
283             DEFAULT "I<[time] [url] - [site]: [title] ([total])>".
284              
285             The valid field I<[variables]> are: [stream]: The url of the first/best stream
286             found. [site]: The site (submodule) name matching the webpage url.
287             [url]: The url searched for streams. [time]: Perl timestamp when the line was
288             logged. [title], [artist], [album], [description], [year], [genre], [total],
289             [albumartist]: The corresponding field data returned (or "I<-na->",
290             if no value).
291              
292             =item $station->B(['playlist'])
293              
294             Returns an array of strings representing all stream URLs found.
295             If I<"playlist"> is specified, then an extended m3u playlist is returned
296             instead of stream url(s). NOTE: For podcast sites, if an author / channel
297             page url is given, rather than an individual podcast episode's url, get()
298             returns the first (latest?) podcast episode found, and get("playlist") returns
299             an extended m3u playlist containing the urls, titles, etc. for all the podcast
300             episodes found on that page url from latest to oldest.
301              
302             =item $station->B([I])
303              
304             Similar to B() except it only returns a single stream representing
305             the first valid stream found.
306              
307             Current options are: I<"random">, I<"nopls">, and I<"noplaylists">.
308             By default, the first ("best"?) stream is returned. If I<"random"> is
309             specified, then a random one is selected from the list of streams found.
310             If I<"nopls"> is specified, and the stream to be returned is a ".pls" playlist,
311             it is first fetched and the first entry (or a random entry if I<"random"> is
312             specified) is returned. This is needed by Fauxdacious Mediaplayer.
313             If I<"noplaylists"> is specified, and the stream to be returned is a
314             "playlist" (either .pls or .m3u? extension), it is first fetched and the first
315             entry (or a random entry if I<"random"> is specified) in the playlist
316             is returned.
317              
318             =item $station->B()
319              
320             Returns the number of streams found for the station.
321              
322             =item $station->B(['fccid'])
323              
324             Returns the station's site ID (default), or station's FCC
325             call-letters ("fccid") for applicable sites and stations.
326              
327             =item $station->B(['desc'])
328              
329             Returns the station's title, (or long description, if "desc" specified).
330              
331             NOTE: Some sights do not support a separate long description field,
332             so if none found, the standard title field will always be returned.
333              
334             =item $station->B(['artist'])
335              
336             Returns the URL for the station's "cover art" icon image, if any.
337              
338             Some video and podcast sites will also provide a separate artist/channel
339             icon. If B<'artist'> is specified, this icon url is returned instead,
340             if any.
341              
342             =item $station->B(['artist'])
343              
344             Returns a two-element array consisting of the extension (ie. "png",
345             "gif", "jpeg", etc.) and the actual icon image (binary data), if any.
346             This makes it easy to download the image to local storage for use by
347             your preferred media player.
348              
349             Some video and podcast sites will also provide a separate artist/channel
350             icon. If B<'artist'> is specified, this icon's data is returned instead,
351             if any.
352              
353             =item $station->B(['artist'])
354              
355             Returns the URL for the station's "cover art" banner image, if any.
356              
357             NOTE: If no "banner image" (usually a larger image) is found,
358             the "icon image" URL will be returned.
359              
360             Some video and podcast sites will also provide a separate artist/channel
361             image (usually larger). If B<'artist'> is specified, this icon url is
362             returned instead, if any.
363              
364             =item $station->B(['artist'])
365              
366             Returns a two-element array consisting of the extension (ie. "png",
367             "gif", "jpeg", etc.) and the actual station's banner image
368             (binary data). This makes it easy to download the image to
369             local storage for use by your preferred media player.
370              
371             NOTE: If no "banner image" (usually a larger image) is found,
372             the "icon image" data, if any, will be returned.
373              
374             Some video and podcast sites will also provide a separate artist/channel
375             image (usually larger). If B<'artist'> is specified, this icon's data is
376             returned instead, if any.
377              
378             =item $station->B()
379              
380             Returns the station / podcast / video's type (I).
381             (one of: "Anystream", "Apple", "BitChute", "Blogger", "Youtube", etc. -
382             depending on the sight that matched the URL).
383              
384             Some video and podcast sites will also provide a separate artist/channel
385             image (usually larger). If B<'artist'> is specified, this icon url is
386             returned instead, if any.
387              
388             =back
389              
390             =head1 CONFIGURATION FILES
391              
392             The default root location directory for StreamFinder configuration files
393             is "~/.config/StreamFinder". To use an alternate location directory,
394             specify it in the "I" environment variable, ie.:
395             B<$ENV{STREAMFINDER} = "/etc/StreamFinder">.
396              
397             =over 4
398              
399             =item ~/.config/StreamFinder/config
400              
401             Optional text file for specifying various configuration options.
402             Each option is specified on a separate line in the formats below:
403             NOTE: Do not follow the lines with a semicolon, comma, or any other
404             separator. Non-numeric I should be surrounded with quotes, either
405             single or double. Blank lines and lines beginning with a "#" sign as
406             their first non-blank character are ignored as comments.
407              
408             'option' => 'value' [, ...]
409              
410             'option' => ['value1', 'value2', ...] [, ...]
411              
412             'option' => {'key1' => 'value1', 'key2' => 'value2', ...} [, ...]
413              
414             and the options are loaded into a hash used by all sites
415             (submodules) that support them. Valid options include
416             I<-debug> => [0|1|2] and most of the L options.
417              
418             =item ~/.config/StreamFinder/I/config
419              
420             Optional text file for specifying various configuration options
421             for a specific site (submodule, ie. "Youtube" for
422             StreamFinder::Youtube). Each option is specified on a separate
423             line in the formats below:
424              
425             'option' => 'value' [, ...]
426              
427             'option' => ['value1', 'value2', ...] [, ...]
428              
429             'option' => {'key1' => 'value1', 'key2' => 'value2', ...} [, ...]
430              
431             and the options are loaded into a hash used only by the specific
432             (submodule) specified. Valid options include
433             I<-debug> => [0|1|2] and most of the L options.
434              
435             NOTE: Options specified here override any specified in I<~/.config/StreamFinder/config>.
436              
437             =back
438              
439             NOTE: Options specified in the options parameter list of the I
440             function will override those corresponding options specified in these files.
441              
442             =head1 DEPENDENCIES
443              
444             L, L, L
445              
446             =head1 RECCOMENDS
447              
448             youtube-dl, or other compatable program such as yt-dlp, etc.
449             (for Youtube, Bitchute, Blogger, Brighteon, Odysee, Vimeo)
450             NOTE: Required for Youtube, Odysee, and SoundCloud to work.
451              
452             wget
453              
454             =head1 BUGS
455              
456             Please report any bugs or feature requests to C, or through
457             the web interface at L.
458             I will be notified, and then you'llautomatically be notified of progress on
459             your bug as I make changes.
460              
461             =head1 SUPPORT
462              
463             You can find documentation for this module with the perldoc command.
464              
465             perldoc StreamFinder
466              
467             You can also look for information at:
468              
469             =head1 SEE ALSO
470              
471             Fauxdacious media player - (L)
472              
473             =over 4
474              
475             =item * RT: CPAN's request tracker (report bugs here)
476              
477             L
478              
479             =item * CPAN Ratings
480              
481             L
482              
483             =item * Search CPAN
484              
485             L
486              
487             =back
488              
489             =head1 LICENSE AND COPYRIGHT
490              
491             Copyright 2017-2023 Jim Turner.
492              
493             This program is free software; you can redistribute it and/or modify it
494             under the terms of the the Artistic License (2.0). You may obtain a
495             copy of the full license at:
496              
497             L
498              
499             Any use, modification, and distribution of the Standard or Modified
500             Versions is governed by this Artistic License. By using, modifying or
501             distributing the Package, you accept this license. Do not use, modify,
502             or distribute the Package, if you do not accept this license.
503              
504             If your Modified Version has been derived from a Modified Version made
505             by someone other than you, you are nevertheless required to ensure that
506             your Modified Version complies with the requirements of this license.
507              
508             This license does not grant you the right to use any trademark, service
509             mark, tradename, or logo of the Copyright Holder.
510              
511             This license includes the non-exclusive, worldwide, free-of-charge
512             patent license to make, have made, use, offer to sell, sell, import and
513             otherwise transfer the Package with respect to any patent claims
514             licensable by the Copyright Holder that are necessarily infringed by the
515             Package. If you institute patent litigation (including a cross-claim or
516             counterclaim) against any party alleging that the Package constitutes
517             direct or contributory patent infringement, then this Artistic License
518             to you shall terminate on the date that such litigation is filed.
519              
520             Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER
521             AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES.
522             THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
523             PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY
524             YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR
525             CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR
526             CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE,
527             EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
528              
529             =cut
530              
531             package StreamFinder;
532              
533             require 5.001;
534              
535 1     1   68706 use strict;
  1         3  
  1         30  
536 1     1   5 use warnings;
  1         2  
  1         31  
537 1     1   6 use vars qw(@ISA @EXPORT $VERSION);
  1         2  
  1         1601  
538              
539             our $VERSION = '2.18';
540             our $DEBUG = 0;
541              
542             require Exporter;
543              
544             @ISA = qw(Exporter);
545             @EXPORT = qw();
546             my @supported_mods = (qw(Anystream Apple Bitchute Blogger BrandNewTube Brighteon Castbox
547             Google IHeartRadio InternetRadio Odysee OnlineRadiobox Podbean PodcastAddict Podchaser
548             RadioNet Rcast Rumble SermonAudio SoundCloud Spreaker Tunein Vimeo Youtube LinkTV Zeno));
549              
550             my %useit;
551              
552             foreach my $module (@supported_mods)
553             {
554             $useit{$module} = 1;
555             }
556              
557             sub new
558             {
559 0     0 1   my $class = shift;
560 0           my $url = shift;
561              
562 0           my $self = {};
563 0 0         return undef unless ($url);
564              
565 0           my $arg;
566 0           my @args = ();
567 0           while (@_) {
568 0           $arg = shift(@_);
569 0 0         if ($arg =~ /^\-?omit$/o) { #ALLOW USER TO OMIT SPECIFIC INSTALLED SUBMODULE(S):
570 0           my @omitModules = split(/\,\s*/, shift(@_));
571 0           foreach my $omit (@omitModules)
572             {
573 0           $useit{$omit} = 0;
574             }
575             } else {
576 0           push @args, $arg;
577             }
578             }
579              
580 0           my $haveit = 0;
581 0 0         push @args, ('-debug', $DEBUG) if ($DEBUG);
582 0 0 0       if ($url =~ m#\b(?:podcasts?|music)\.apple\.com\/# && $useit{'Apple'}) {
    0 0        
    0 0        
    0 0        
    0 0        
    0 0        
    0 0        
    0 0        
    0 0        
    0 0        
    0 0        
    0 0        
    0 0        
    0 0        
    0 0        
    0 0        
    0 0        
    0 0        
    0 0        
    0 0        
    0 0        
    0 0        
    0 0        
    0 0        
    0          
583 0           eval { require 'StreamFinder/Apple.pm'; $haveit = 1; };
  0            
  0            
584 0 0         return new StreamFinder::Apple($url, @args) if ($haveit);
585             } elsif ($url =~ m#\brumble\.com\/# && $useit{'Rumble'}) {
586 0           eval { require 'StreamFinder/Rumble.pm'; $haveit = 1; };
  0            
  0            
587 0 0         return new StreamFinder::Rumble($url, @args) if ($haveit);
588             } elsif ($url =~ m#\bpodcastaddict\.# && $useit{'PodcastAddict'}) {
589 0           eval { require 'StreamFinder/PodcastAddict.pm'; $haveit = 1; };
  0            
  0            
590 0 0         return new StreamFinder::PodcastAddict($url, @args) if ($haveit);
591             } elsif ($url =~ m#\b(?:brandnew|uge)tube\.# && $useit{'BrandNewTube'}) { #HANDLES brandnewtube & ugetube!
592 0           eval { require 'StreamFinder/BrandNewTube.pm'; $haveit = 1; };
  0            
  0            
593 0 0         return new StreamFinder::BrandNewTube($url, @args) if ($haveit);
594             } elsif ($url =~ m#\bbitchute\.# && $useit{'Bitchute'}) {
595 0           eval { require 'StreamFinder/Bitchute.pm'; $haveit = 1; };
  0            
  0            
596 0 0         return new StreamFinder::Bitchute($url, @args) if ($haveit);
597             } elsif ($url =~ m#\biheart(?:radio)?\.#i && $useit{'IHeartRadio'}) {
598 0           eval { require 'StreamFinder/IHeartRadio.pm'; $haveit = 1; };
  0            
  0            
599 0 0         return new StreamFinder::IHeartRadio($url, @args) if ($haveit);
600             } elsif ($url =~ m#\btunein\.# && $useit{'Tunein'}) { #NOTE:ALSO USES youtube-dl!
601 0           eval { require 'StreamFinder/Tunein.pm'; $haveit = 1; };
  0            
  0            
602 0 0         return new StreamFinder::Tunein($url, @args) if ($haveit);
603             } elsif ($url =~ m#\bbrighteon\.com\/# && $useit{'Brighteon'}) { #NOTE:ALSO USES youtube-dl!
604 0           eval { require 'StreamFinder/Brighteon.pm'; $haveit = 1; };
  0            
  0            
605 0 0         return new StreamFinder::Brighteon($url, @args) if ($haveit);
606             } elsif ($url =~ m#\bspreaker\.# && $useit{'Spreaker'}) {
607 0           eval { require 'StreamFinder/Spreaker.pm'; $haveit = 1; };
  0            
  0            
608 0 0         return new StreamFinder::Spreaker($url, @args) if ($haveit);
609             } elsif ($url =~ m#\bcastbox\.\w+\/# && $useit{'Castbox'}) {
610 0           eval { require 'StreamFinder/Castbox.pm'; $haveit = 1; };
  0            
  0            
611 0 0         return new StreamFinder::Castbox($url, @args) if ($haveit);
612             } elsif ($url =~ m#\b\.google\.\w+\/# && $useit{'Google'}) {
613 0           eval { require 'StreamFinder/Google.pm'; $haveit = 1; };
  0            
  0            
614 0 0         return new StreamFinder::Google($url, @args) if ($haveit);
615             } elsif ($url =~ m#\bradio\.net\/# && $useit{'RadioNet'}) {
616 0           eval { require 'StreamFinder/RadioNet.pm'; $haveit = 1; };
  0            
  0            
617 0 0         return new StreamFinder::RadioNet($url, @args) if ($haveit);
618             } elsif ($url =~ m#\bvimeo\.# && $useit{'Vimeo'}) { #NOTE:ALSO USES youtube-dl!
619 0           eval { require 'StreamFinder/Vimeo.pm'; $haveit = 1; };
  0            
  0            
620 0 0         return new StreamFinder::Vimeo($url, @args) if ($haveit);
621             } elsif ($url =~ m#\bblogger\.# && $useit{'Blogger'}) {
622 0           eval { require 'StreamFinder/Blogger.pm'; $haveit = 1; };
  0            
  0            
623 0 0         return new StreamFinder::Blogger($url, @args) if ($haveit);
624             } elsif ($url =~ m#\bsermonaudio\.com\/# && $useit{'SermonAudio'}) {
625 0           eval { require 'StreamFinder/SermonAudio.pm'; $haveit = 1; };
  0            
  0            
626 0 0         return new StreamFinder::SermonAudio($url, @args) if ($haveit);
627             } elsif ($url =~ m#\bodysee\.com\/# && $useit{'Odysee'}) {
628 0           eval { require 'StreamFinder/Odysee.pm'; $haveit = 1; };
  0            
  0            
629 0 0         return new StreamFinder::Odysee($url, @args) if ($haveit);
630             } elsif ($url =~ m#\bpodbean\.com\/# && $useit{'Podbean'}) {
631 0           eval { require 'StreamFinder/Podbean.pm'; $haveit = 1; };
  0            
  0            
632 0 0         return new StreamFinder::Podbean($url, @args) if ($haveit);
633             } elsif ($url =~ m#\bonlineradiobox\.# && $useit{'OnlineRadiobox'}) {
634 0           eval { require 'StreamFinder/OnlineRadiobox.pm'; $haveit = 1; };
  0            
  0            
635 0 0         return new StreamFinder::OnlineRadiobox($url, @args) if ($haveit);
636             } elsif ($url =~ m#\binternet\-radio\.# && $useit{'InternetRadio'}) {
637 0           eval { require 'StreamFinder/InternetRadio.pm'; $haveit = 1; };
  0            
  0            
638 0 0         return new StreamFinder::InternetRadio($url, @args) if ($haveit);
639             } elsif ($url =~ m#\bsoundcloud\.# && $useit{'SoundCloud'}) {
640 0           eval { require 'StreamFinder/SoundCloud.pm'; $haveit = 1; };
  0            
  0            
641 0 0         return new StreamFinder::SoundCloud($url, @args) if ($haveit);
642             } elsif ($url =~ m#\brcast\.# && $useit{'Rcast'}) {
643 0           eval { require 'StreamFinder/Rcast.pm'; $haveit = 1; };
  0            
  0            
644 0 0         return new StreamFinder::Rcast($url, @args) if ($haveit);
645             } elsif ($url =~ m#\bpodchaser\.# && $useit{'Podchaser'}) {
646 0           eval { require 'StreamFinder/Podchaser.pm'; $haveit = 1; };
  0            
  0            
647 0 0         return new StreamFinder::Podchaser($url, @args) if ($haveit);
648             } elsif ($url =~ m#\blinktv\.# && $useit{'LinkTV'}) {
649 0           eval { require 'StreamFinder/LinkTV.pm'; $haveit = 1; };
  0            
  0            
650 0 0         return new StreamFinder::LinkTV($url, @args) if ($haveit);
651             } elsif ($url =~ m#\bzeno\.# && $useit{'Zeno'}) {
652 0           eval { require 'StreamFinder/Zeno.pm'; $haveit = 1; };
  0            
  0            
653 0 0         return new StreamFinder::Zeno($url, @args) if ($haveit);
654             } elsif ($useit{'Youtube'}) { #DEFAULT TO youtube-dl SINCE SO MANY URLS ARE HANDLED THERE NOW.
655 0           eval { require 'StreamFinder/Youtube.pm'; $haveit = 1; };
  0            
  0            
656 0 0         if ($haveit) {
657 0           my $yt = new StreamFinder::Youtube($url, @args);
658 0 0 0       return $yt if (defined($yt) && $yt && $yt->count() > 0);
      0        
659             }
660             }
661 0 0         if ($useit{'Anystream'}) { #SITE NOT SUPPORTED, TRY TO FIND ANY STREAM URLS WE CAN:
662 0           $haveit = 0;
663 0           eval { require 'StreamFinder/Anystream.pm'; $haveit = 1; };
  0            
  0            
664 0 0         return new StreamFinder::Anystream($url, @args) if ($haveit);
665             }
666 0           return undef;
667             }
668              
669             1