-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathindex.js
101 lines (83 loc) · 2.47 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
const { extname } = require('path');
const createDebug = require('debug');
const { parse, format } = require('url');
const { parse: parseIni } = require('ini');
const fetch = require('./fetch');
const debug = createDebug('iheart');
// go through a CORS reverse proxy so that these APIs work in the web browser
const corsDefaultProxy = process.browser ? 'https://cors.now.sh/' : '';
const searchBase = 'https://api.iheart.com/api/v1/catalog/searchAll';
const streamsBase = 'https://api.iheart.com/api/v2/content/liveStations/';
function getProxyURL(options) {
return options && 'string' === typeof options.proxy
? options.proxy
: options && null === options.proxy
? ''
: corsDefaultProxy;
}
/**
* Searches for radio streams matching `keyword`.
*/
async function search(keyword, options) {
if ('string' !== typeof keyword) {
throw new TypeError('a string "keyword" is required');
}
const corsProxy = getProxyURL(options);
const formatted = parse(searchBase, true);
formatted.query.keywords = keyword;
const url = format(formatted);
const res = await fetch(`${corsProxy}${url}`);
const body = await res.json();
if (body.errors) {
// body.firstError
}
return body;
}
/**
* Searches for a station by Id
*/
async function getById(_station, options) {
const id = _station.id || _station;
if ('number' !== typeof id) {
throw new TypeError('a number station "id" is required');
}
const corsProxy = getProxyURL(options);
let url = streamsBase + id;
const res = await fetch(`${corsProxy}${url}`);
const body = await res.json();
if (body.errors) {
// body.firstError
}
return body.hits[0];
}
/**
* Gets the raw stream URL of the given Station or Station ID.
*/
async function streamURL(_station, options) {
const { streams } = await getById(_station, options);
if (!streams) {
throw new Error('No `streams` given');
}
url =
streams.secure_pls_stream ||
streams.pls_stream ||
streams.stw_stream ||
streams.secure_shoutcast_stream ||
streams.shoutcast_stream ||
streams[Object.keys(streams)[0]];
if ('.pls' === extname(url).toLowerCase()) {
debug('attempting to resolve "pls" file %o', url);
const corsProxy = getProxyURL(options);
const res = await fetch(`${corsProxy}${url}`);
const body = parseIni(await res.text());
debug('pls file: %O', body);
url = body.playlist.File1;
}
debug('stream URL: %o', url);
return url;
}
module.exports = {
search,
getById,
streamURL
};