File Coverage

blib/lib/StreamFinder.pm
Criterion Covered Total %
statement 9 138 6.5
branch 0 116 0.0
condition 0 81 0.0
subroutine 3 4 75.0
pod 1 1 100.0
total 13 340 3.8


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