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 |