├── .gitignore ├── .jshintrc ├── examples ├── station.js ├── get_states.js ├── server-stats.js ├── stations_by_url.js ├── top_stations.js └── stations_by_tag.js ├── lib ├── env.js ├── dns-nativ.js ├── api-host.js ├── query-client.js ├── dns-https.js └── api-client.js ├── package.json ├── LICENSE ├── test └── test.js ├── README.md └── index.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | test.js 3 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "asi": true, 3 | "mocha": true, 4 | "node": true, 5 | "esversion": 8 6 | } -------------------------------------------------------------------------------- /examples/station.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | module.exports = function(station) 4 | { 5 | console.log(`${station.name}\nStation UUID: ${station.stationuuid}\nStream: ${station.url}\nTags : ${station.tags}\nVotes: ${station.votes}\nClicks: ${station.clickcount}\n`) 6 | } -------------------------------------------------------------------------------- /lib/env.js: -------------------------------------------------------------------------------- 1 | // got from https://github.com/flexdinesh/browser-or-node 2 | module.exports = { 3 | isNode: typeof process !== 'undefined' && process.versions != null && process.versions.node != null, 4 | isBrowser: typeof window !== 'undefined' && typeof window.document !== 'undefined' 5 | } 6 | -------------------------------------------------------------------------------- /examples/get_states.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const RadioBrowser = require('..') 4 | 5 | let filter = { 6 | searchterm: 'aus', 7 | reverse: true, 8 | order: 'stationcount' 9 | } 10 | RadioBrowser.getCategory('states', filter) 11 | .then(data => console.log(data)) 12 | .catch(err => console.error(err)) 13 | -------------------------------------------------------------------------------- /examples/server-stats.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const RadioBrowser = require('..') 4 | 5 | const start = async () => { 6 | try { 7 | let data = await RadioBrowser.getServerStats() 8 | console.log(`API Server: ${RadioBrowser.service_url}`) 9 | console.log('stats', data) 10 | } 11 | catch (e) { 12 | console.error(e) 13 | } 14 | } 15 | 16 | start() 17 | -------------------------------------------------------------------------------- /examples/stations_by_url.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const RadioBrowser = require('../') 4 | const station = require('./station') 5 | 6 | let filter = { 7 | by: 'url', // stations by url, 8 | searchterm: 'http://stream.laut.fm/ruffneck-smille?ref=radiode' 9 | } 10 | 11 | RadioBrowser.getStations(filter) 12 | .then(data => data.forEach((item) => station(item))) 13 | .catch(err => console.error(err)) 14 | -------------------------------------------------------------------------------- /examples/top_stations.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const RadioBrowser = require('../') 4 | const station = require('./station') 5 | 6 | let filter = { 7 | by: 'topvote', // stations by topvote, 8 | limit: 5 // top 5 stations 9 | } 10 | 11 | RadioBrowser.getStations(filter) 12 | .then(data => { 13 | data.forEach((item) => station(item)); 14 | }) 15 | .catch(err => console.error(err)) 16 | 17 | -------------------------------------------------------------------------------- /examples/stations_by_tag.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const RadioBrowser = require('../') 4 | const station = require('./station') 5 | 6 | let filter = { 7 | by: 'tag', // stations by tag, 8 | searchterm: 'ska', 9 | limit: 5 // max 5 stations 10 | } 11 | 12 | RadioBrowser.getStations(filter) 13 | .then(data => { 14 | data.forEach((item) => station(item)); 15 | }) 16 | .catch(err => console.error(err)) 17 | -------------------------------------------------------------------------------- /lib/dns-nativ.js: -------------------------------------------------------------------------------- 1 | /** 2 | * get random api host 3 | * 4 | * thanks to segler-alex 5 | * issue: https://github.com/nepodev/radio-browser/issues/1 6 | */ 7 | 'use strict' 8 | 9 | const dns = require('dns') 10 | const util = require('util') 11 | const resolve4 = util.promisify(dns.resolve4) 12 | const reverse = util.promisify(dns.reverse) 13 | 14 | module.exports = { 15 | resolve4, 16 | reverse, 17 | resolveSrv: util.promisify(dns.resolveSrv) 18 | } -------------------------------------------------------------------------------- /lib/api-host.js: -------------------------------------------------------------------------------- 1 | /** 2 | * get random api host 3 | */ 4 | 'use strict' 5 | 6 | const { isNode } = require('./env') 7 | const { resolveSrv } = isNode ? require('./dns-nativ') : require('./dns-https') 8 | 9 | /** 10 | * https://api.radio-browser.info/examples/serverlist_fast.js 11 | */ 12 | const BASE_HOST = '_api._tcp.radio-browser.info' 13 | 14 | module.exports = () => { 15 | return new Promise((resolve, reject) => { 16 | (async () => { 17 | try { 18 | let list = await resolveSrv(BASE_HOST) 19 | let item = list[Math.floor(Math.random() * list.length)] 20 | resolve(item.name) 21 | } 22 | catch(e) { 23 | reject(e) 24 | } 25 | })() 26 | }) 27 | } 28 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "radio-browser", 3 | "version": "2.2.3", 4 | "description": "nodejs module for radio-browser API (http://www.radio-browser.info/webservice)", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "mocha --reporter spec" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/nepodev/radio-browser.git" 12 | }, 13 | "keywords": [ 14 | "webradio", 15 | "radiobrowser", 16 | "api", 17 | "javascript" 18 | ], 19 | "author": "nepodev", 20 | "license": "MIT", 21 | "bugs": { 22 | "url": "https://github.com/nepodev/radio-browser/issues" 23 | }, 24 | "homepage": "https://github.com/nepodev/radio-browser#readme", 25 | "devDependencies": { 26 | "chai": "^4.3.7", 27 | "mocha": "^10.2.0" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 nepodev 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /lib/query-client.js: -------------------------------------------------------------------------------- 1 | 2 | const http = require('http') 3 | const https = require('https') 4 | 5 | module.exports = (options, body='') => { 6 | 7 | if (body) { 8 | options.headers['Content-Length'] = Buffer.byteLength(body) 9 | } 10 | 11 | let request = (options.protocol === 'https:' ? https : http).request 12 | 13 | return new Promise((resolve, reject) => { 14 | const req = request(options, (res) => { 15 | const { statusCode } = res 16 | let error; 17 | let rawData = '' 18 | 19 | if (statusCode < 200 || statusCode > 299) { 20 | error = new Error('Request Failed.\n' + `Status Code: ${statusCode}`) 21 | } 22 | 23 | if (error) { 24 | res.resume() 25 | reject(error) 26 | } 27 | 28 | res.setEncoding('utf8') 29 | res.on('data', (chunk) => rawData += chunk) 30 | res.on('end', () => { 31 | try { 32 | const parsedData = JSON.parse(rawData); 33 | resolve(parsedData) 34 | } 35 | catch (e) { 36 | reject(e) 37 | } 38 | }) 39 | }) 40 | 41 | if (options.headers['Content-Length']) { 42 | req.write(body) 43 | } 44 | 45 | req.on('error', (e) => reject(e)) 46 | req.end() 47 | }) 48 | 49 | } 50 | -------------------------------------------------------------------------------- /lib/dns-https.js: -------------------------------------------------------------------------------- 1 | /** 2 | * resolve dns over https 3 | * using cloudflare dns 4 | * 5 | */ 6 | 7 | const querystring = require('querystring') 8 | const queryClient = require('./query-client') 9 | 10 | const OPTIONS = { 11 | method: 'GET', 12 | host: 'cloudflare-dns.com', 13 | path: '/dns-query?', 14 | protocol: 'https:', 15 | headers: { 16 | accept: 'application/dns-json' 17 | } 18 | } 19 | 20 | /** 21 | * 22 | * @param {object} params 23 | */ 24 | const requestService = (params) => { 25 | let options = Object.assign({}, OPTIONS) 26 | options.path += querystring.stringify(params) 27 | return queryClient(options) 28 | } 29 | 30 | module.exports = { 31 | resolve4: name => { 32 | return requestService({name, type: 'A'}) 33 | .then(data => data.Answer.map(item => item.data)) 34 | }, 35 | 36 | reverse: ip => { 37 | const name = ip.split('.').reverse().join('.') + '.in-addr.arpa' 38 | return requestService({name, type: 'PTR'}) 39 | .then(data => data.Answer.map(item => item.data.slice(0, -1))) 40 | }, 41 | 42 | resolveSrv: name => { 43 | return requestService({name, type: 'SRV'}) 44 | .then(data => data.Answer.map(item => { 45 | let a = item.data.split(' ') 46 | return { 47 | priority: a[0], 48 | weight: a[1], 49 | port: a[2], 50 | name: a[3] 51 | } 52 | }) 53 | ) 54 | }, 55 | 56 | } 57 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const { expect } = require('chai'); 3 | const RadioBrowser = require('../index') 4 | 5 | var serverStats = {} 6 | 7 | describe('#RadioBrowser.getServerStats()', function() { 8 | this.timeout(10000) 9 | it('should return server stats', () => { 10 | return RadioBrowser.getServerStats().then((data) => { 11 | serverStats = data; 12 | expect(data).to.contain.keys('stations','tags','languages','countries') 13 | }) 14 | }) 15 | }) 16 | 17 | describe('#RadioBrowser lists', function() { 18 | this.timeout(10000) 19 | it('should return all languages', () => { 20 | return RadioBrowser.getCategory('languages').then(data => { 21 | expect(data.length).to.equal(parseInt(serverStats.languages)) 22 | expect(data[0]).to.contain.keys('stationcount') 23 | }) 24 | }) 25 | 26 | it('should return countries with string "de"', () => { 27 | let filter = { 28 | searchterm: 'de' 29 | } 30 | return RadioBrowser.getCategory('countries', filter).then(data => { 31 | expect(data.length).to.be.above(0) 32 | expect(data[0]).to.contain.keys('stationcount') 33 | 34 | let name = data[0].iso_3166_1.toLowerCase() 35 | expect(name).to.include(filter.searchterm) 36 | }) 37 | }) 38 | 39 | it('should return a list of 2 stations', () => { 40 | let filter = { 41 | limit: 2 42 | } 43 | return RadioBrowser.getStations(filter).then(data => { 44 | expect(data.length).to.equal(2) 45 | }) 46 | }) 47 | 48 | it('should return a list of 2 stations with tag ska', () => { 49 | let filter = { 50 | limit: 2, 51 | by: 'bytag', 52 | searchterm: 'ska' 53 | } 54 | return RadioBrowser.getStations(filter).then(data => { 55 | expect(data.length).to.equal(2) 56 | expect(data[0].tags).to.include(filter.searchterm) 57 | }) 58 | }) 59 | }) 60 | 61 | describe('#RadioBrowser.addStation()', function() { 62 | it('should return failure message', () => { 63 | let params = {url: 'http://example.com'} 64 | return RadioBrowser.addStation(params).then((data) => { 65 | expect(data).to.deep.equal({"ok":false,"message":"AddStationError 'name is empty'","uuid":""}) 66 | }) 67 | }) 68 | }) 69 | -------------------------------------------------------------------------------- /lib/api-client.js: -------------------------------------------------------------------------------- 1 | /** 2 | * api-client.js 3 | * 4 | */ 5 | 'use strict' 6 | 7 | const { isBrowser } = require('./env') 8 | const URL = isBrowser ? window.URL : require('url').URL 9 | const querystring = require('querystring') 10 | const apiHost = require('./api-host') 11 | const queryClient = require('./query-client') 12 | 13 | //var HttpRequest = null 14 | 15 | const DEFAULT_OPTIONS = { 16 | host: null, // default is null to get random api-host 17 | protocol: 'https:', 18 | path: '/', // base path. will extend on request. 19 | method: 'POST', // default is POST because GET request at radiobrowser-api dosen't work as expected. 20 | headers: { 21 | accept: 'application/json', 22 | 'Content-Type': 'application/x-www-form-urlencoded', 23 | 'x-requested-with': 'nodejs radio-browser (https://gitlab.com/nepodev/radio-browser)' 24 | } 25 | } 26 | 27 | var request_options = { 28 | host: null 29 | } 30 | 31 | /** 32 | * set api-host options. 33 | * 34 | * @param {object} options {host: , protocol: ', path: , port: , hostname: } 35 | * @returns {void} 36 | */ 37 | const setService = function(options) 38 | { 39 | request_options = Object.assign({}, DEFAULT_OPTIONS); 40 | 41 | ['host', 'hostname', 'port', 'protocol'].forEach((key) => { 42 | request_options[key] = options[key] 43 | }) 44 | request_options.path = options.pathname 45 | 46 | if (typeof request_options.path === 'string' && request_options.path.substr(-1) !== '/') { 47 | request_options.path += '/' 48 | } 49 | } 50 | 51 | const requestService = (route, param={}, option={}) => { 52 | let options = Object.assign({}, request_options, option) 53 | let query = querystring.stringify(param) 54 | 55 | options.path += 'json/' + route 56 | if (query) { 57 | options.path += '?' + query 58 | } 59 | 60 | return queryClient(options) 61 | } 62 | 63 | const ApiClient = { 64 | 65 | get service_url() 66 | { 67 | return request_options.host === null ? null : [ 68 | request_options.protocol, 69 | '//', 70 | request_options.host, 71 | request_options.path 72 | ].join('') 73 | }, 74 | 75 | set service_url(service_url) 76 | { 77 | if (service_url === null) { 78 | service_url = '' 79 | } 80 | let opt = new URL(service_url) 81 | setService(opt) 82 | }, 83 | 84 | getRandomHost: apiHost, 85 | 86 | /** 87 | * send request to radiobrowser-api. 88 | * 89 | * @param {string} route 90 | * @param {object} param 91 | * @param {object} option 92 | * @returns {promise} 93 | */ 94 | request: (route, param={}, option={}) => { 95 | if (request_options.host === null) { 96 | return apiHost() 97 | .then(host => ApiClient.service_url = 'https://' + host + '/') 98 | .then(() => requestService(route, param, option)) 99 | } 100 | else { 101 | return requestService(route, param, option) 102 | } 103 | } 104 | } 105 | 106 | module.exports = ApiClient 107 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RadioBrowser API Client 2 | 3 | Nodejs module for [Radio-browser API](https://de1.api.radio-browser.info/) 4 | 5 | ## Install 6 | 7 | ```bash 8 | npm install radio-browser 9 | ``` 10 | 11 | ## Usage 12 | 13 | Every method returns a promise so you have to use `then` and `catch` or `async` and `await`. 14 | 15 | ```js 16 | const RadioBrowser = require('radio-browser') 17 | 18 | let filter = { 19 | limit: 5, // list max 5 items 20 | by: 'tag', // search in tag 21 | searchterm: 'jazz' // term in tag 22 | } 23 | RadioBrowser.getStations(filter) 24 | .then(data => console.log(data)) 25 | .catch(error => console.error(error)) 26 | ``` 27 | 28 | ## Methods 29 | 30 | * `addStation()` [Add radio station](https://de1.api.radio-browser.info/#Add_radio_station) 31 | * `clickStation()` [Station click counter](https://de1.api.radio-browser.info/#Count_station_click) 32 | * `getCategory([, filter])` Get a list of [codecs](https://de1.api.radio-browser.info/#List_of_codecs), [countries](https://de1.api.radio-browser.info/#List_of_countries), [countrycodes](https://de1.api.radio-browser.info/#List_of_countrycodes), [languages](https://de1.api.radio-browser.info/#List_of_languages), [states](https://de1.api.radio-browser.info/#List_of_states), [tags](https://de1.api.radio-browser.info/#List_of_tags) 33 | * `getChecks([stationuuid][, seconds])` [List of station check results](https://de1.api.radio-browser.info/#List_of_station_check_results) 34 | * `getChecksteps()` [List of station check steps](https://de1.api.radio-browser.info/#List_of_station_check_steps) 35 | * `getClicks([stationuuid][, seconds])` [List of station clicks](https://de1.api.radio-browser.info/#List_of_station_clicks) 36 | * `getRandomHost()` Convenience function to get a random host without api request. 37 | * `getServerConfig()` [Server config](https://de1.api.radio-browser.info/#Server_config) 38 | * `getServerMirrors()` [Server mirrors](https://de1.api.radio-browser.info/#Server_mirrors) 39 | * `getServerStats()` [Server stats](https://de1.api.radio-browser.info/#Server_stats) 40 | * `getStations([filter])` [List of radio stations](https://de1.api.radio-browser.info/#List_of_radio_stations), Stations by [clicks](https://de1.api.radio-browser.info/#Stations_by_clicks), [Url](https://de1.api.radio-browser.info/#Search_radio_stations_by_url), [vote](https://de1.api.radio-browser.info/#Stations_by_votes), [recent click](https://de1.api.radio-browser.info/#Stations_by_recent_click), [recent changed](https://de1.api.radio-browser.info/#Stations_by_recently_changed), [deleted](https://de1.api.radio-browser.info/#Stations_that_got_deleted), [need improvements](https://de1.api.radio-browser.info/#Stations_that_need_improvements), [broken](https://de1.api.radio-browser.info/#Broken_stations) 41 | * `searchStations([params])` [Advanced station search](https://de1.api.radio-browser.info/#Advanced_station_search) 42 | * `voteStation()` [Vote for station](https://de1.api.radio-browser.info/#Vote_for_station) 43 | 44 | ## Properties 45 | 46 | * `filter_by_types` list of types using in getStations({by: {type}, ...}) 47 | * `category_types` list of categories using in getCategory({type} ...) 48 | * `service_url` get or set the api-url. Default is `null` to get a random API host at first request. 49 | 50 | ## Examples: 51 | 52 | Get Server Stats from a random API-Host by using async/await 53 | 54 | ```js 55 | // file: examples/server-stats.js 56 | 57 | const RadioBrowser = require('radio-browser') 58 | 59 | const start = async () => { 60 | try { 61 | let data = await RadioBrowser.getServerStats() 62 | console.log(`API Server: ${RadioBrowser.service_url}`) 63 | console.log('stats', data) 64 | } 65 | catch (e) { 66 | console.error(e) 67 | } 68 | } 69 | 70 | start() 71 | ``` 72 | 73 | ```bash 74 | // example output 75 | API Server: https://de1.api.radio-browser.info/ 76 | stats { supported_version: 1, 77 | software_version: '0.6.14', 78 | status: 'OK', 79 | stations: 25603, 80 | stations_broken: 767, 81 | tags: 6757, 82 | clicks_last_hour: 2707, 83 | clicks_last_day: 59547, 84 | languages: 374, 85 | countries: 246 } 86 | ``` 87 | 88 | Get the 5 top voted station 89 | 90 | ```js 91 | let filter = { 92 | by: 'topvote', // stations by topvote 93 | limit: 5 // top 5 stations 94 | } 95 | RadioBrowser.getStations(filter) 96 | .then(data => console.log(data)) 97 | .catch(err => console.error(err)) 98 | ``` 99 | 100 | `data` looks like [this](https://de1.api.radio-browser.info/json/stations/topvote/5) 101 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strice' 2 | 3 | const apiClient = require('./lib/api-client') 4 | 5 | const PARAM_TYPES = { 6 | hidebroken: 'boolean', 7 | limit: 'number', 8 | offset: 'number', 9 | order: 'string', 10 | reverse: 'boolean', 11 | seconds: 'number', 12 | url: 'string', 13 | lastchangeuuid: 'string' 14 | } 15 | 16 | /** 17 | * parts can be in route 18 | * order is importent 19 | */ 20 | const ROUTE_KEYS = [ 21 | 'country', // 1st 22 | 'by', // 1st 23 | 'stationuuid', // 1st 24 | 'searchterm', // 1st or 2nd 25 | 'rowcount' // 2nd 26 | ] 27 | 28 | const FILTER_BY = { 29 | uuid: 'by', 30 | name: 'by', 31 | nameexact: 'by', 32 | codec: 'by', 33 | codecexact: 'by', 34 | country: 'by', 35 | countryexact: 'by', 36 | countrycodeexact: 'by', 37 | state: 'by', 38 | stateexact: 'by', 39 | language: 'by', 40 | languageexact: 'by', 41 | tag: 'by', 42 | tagexact: 'by', 43 | url: 'by', 44 | topclick: '', 45 | topvote: '', 46 | lastclick: '', 47 | lastchange: '', 48 | improvable: '', 49 | broken: '' 50 | } 51 | 52 | const CATEGORY_TYPES = [ 53 | 'countries', 54 | 'countrycodes', 55 | 'codecs', 56 | 'states', 57 | 'languages', 58 | 'tags' 59 | ] 60 | 61 | /** 62 | * extract params from filter 63 | * 64 | * @param {object} filter 65 | * @returns {object} 66 | */ 67 | const extractParams = function(filter) 68 | { 69 | let params = {} 70 | Object.keys(PARAM_TYPES).forEach((name) => { 71 | if (filter[name] && typeof filter[name] === PARAM_TYPES[name]) { 72 | params[name] = filter[name] 73 | } 74 | }) 75 | return params 76 | } 77 | 78 | /** 79 | * extend route with parts from filter 80 | * 81 | * @example 82 | * let filter = { 83 | * country: 'Germany' 84 | * searchterm: 'ber' 85 | * } 86 | * let route = extractRoute('states', filter) 87 | * // route is: states/Germany/ber 88 | * 89 | * @param {string} route 90 | * @param {object} filter 91 | */ 92 | const extractRoute = function (route, filter) 93 | { 94 | ROUTE_KEYS.forEach((name) => { 95 | if (filter[name]) { 96 | route += '/' + encodeURI(filter[name]) 97 | } 98 | }) 99 | return route 100 | } 101 | 102 | /** 103 | * complete route and set params if any 104 | * 105 | * @param {string} route 106 | * @param {object} filter 107 | * @returns {object} {route:, params:} 108 | */ 109 | const parseFilter = function(route, filter={}) 110 | { 111 | return { 112 | route: extractRoute(route, filter), 113 | params: extractParams(filter) 114 | } 115 | } 116 | 117 | const RadioBrowser = module.exports = { 118 | 119 | get service_url() 120 | { 121 | return apiClient.service_url 122 | }, 123 | 124 | set service_url(url) 125 | { 126 | apiClient.service_url = url 127 | }, 128 | 129 | /** 130 | * get a radio-browser host 131 | * 132 | * @returns {string} 133 | */ 134 | getRandomHost: apiClient.getRandomHost, 135 | 136 | /** 137 | * returns a list of category. 138 | * https://de1.api.radio-browser.info/#List_of_countries 139 | * https://de1.api.radio-browser.info/#List_of_countrycodes 140 | * https://de1.api.radio-browser.info/#List_of_codecs 141 | * https://de1.api.radio-browser.info/#List_of_languages 142 | * https://de1.api.radio-browser.info/#List_of_states 143 | * https://de1.api.radio-browser.info/#List_of_tags 144 | * 145 | * @param {string} category 146 | * @param {object} filter {country: , searchterm: , order: , reverse: , hidebroken: } 147 | * @returns {promise} 148 | */ 149 | getCategory: (category, filter) => { 150 | let {route, params} = parseFilter(category, filter) 151 | return apiClient.request(route, params) 152 | }, 153 | 154 | /** 155 | * Get a list of countries 156 | * @deprecated use getCategory('countries', filter) 157 | * @param {object} filter {searchterm: , order: , reverse: , hidebroken: } 158 | * @returns {promise} 159 | */ 160 | getCountries: (filter) => RadioBrowser.getCategory('countries', filter), 161 | 162 | /** 163 | * get a list of codecs 164 | * @deprecated use getCategory('codecs', filter) 165 | * @param {object} filter {searchterm: , order: , reverse: , hidebroken: } 166 | * @returns {promise} 167 | */ 168 | getCodecs: (filter) => RadioBrowser.getCategory('codecs', filter), 169 | 170 | /** 171 | * Get a list of states 172 | * @deprecated use getCategory('states', filter) 173 | * @example 174 | * let filter = { 175 | * country: 'germany', 176 | * searchterm: 'ber' 177 | * } 178 | * @param {object} filter {country: , searchterm: , order: , reverse: , hidebroken: } 179 | * @returns {promise} 180 | */ 181 | getStates: (filter) => RadioBrowser.getCategory('states', filter), 182 | 183 | /** 184 | * get a list of languages 185 | * @deprecated use getCategory('languages', filter) 186 | * @param {object} filter {searchterm: , order: , reverse: , hidebroken: } 187 | * @returns {promise} 188 | */ 189 | getLanguages: (filter) => RadioBrowser.getCategory('languages', filter), 190 | 191 | /** 192 | * get list of tags 193 | * @deprecated use getCategory('tags', filter) 194 | * @param {object} filter {searchterm: , order: , reverse: , hidebroken: } 195 | * @returns {promise} 196 | */ 197 | getTags: (filter) => RadioBrowser.getCategory('tags', filter), 198 | 199 | /** 200 | * List of radio stations 201 | * https://de1.api.radio-browser.info/#List_of_radio_stations 202 | * https://de1.api.radio-browser.info/#Search_radio_stations_by_url 203 | * https://de1.api.radio-browser.info/#Stations_by_clicks 204 | * https://de1.api.radio-browser.info/#Stations_by_votes 205 | * https://de1.api.radio-browser.info/#Stations_by_recent_click 206 | * https://de1.api.radio-browser.info/#Stations_by_recently_changed 207 | * https://de1.api.radio-browser.info/#Stations_that_got_deleted 208 | * https://de1.api.radio-browser.info/#Old_versions_of_stations 209 | * https://de1.api.radio-browser.info/#Stations_that_need_improvement 210 | * https://de1.api.radio-browser.info/#Broken_stations 211 | * 212 | * @param {object} filter {by: , searchterm: , order: , reverse: , offset: , limit: } 213 | * @returns {promise} 214 | * @example 215 | * let filter = { 216 | * by: "tag", // will search in tags. for possible values see links above 217 | * searchterm: "ska", // searchterm. possible values see links above 218 | * order: "name", // sort list by name 219 | * limit: 5, // returns a list of max. 5 stations 220 | * offset: 0 // starting value of list 221 | * } 222 | * RadioBrowser.getStations(filter).then(...).catch(...) 223 | */ 224 | getStations: (filter={}) => { 225 | 226 | if (filter.by) { 227 | let by = filter.by 228 | if (FILTER_BY[by]) { 229 | filter.by = FILTER_BY[by] + by 230 | } 231 | 232 | if (['broken', 'improvable', 'topclick', 'topvote', 'lastclick', 'lastchange'].indexOf(filter.by) !== -1 && filter.limit) 233 | { 234 | filter.rowcount = filter.limit 235 | delete filter.limit 236 | } 237 | else if (filter.by === 'byurl' && filter.searchterm) { 238 | filter.url = filter.searchterm 239 | delete filter.searchterm 240 | } 241 | } 242 | 243 | let {route, params} = parseFilter('stations', filter) 244 | 245 | return apiClient.request(route, params) 246 | }, 247 | 248 | /** 249 | * Get a list of station check results 250 | * https://de1.api.radio-browser.info/#Get_a_list_of_station_check_results 251 | * 252 | * @param {string} stationuuid 253 | * @param {number} seconds 254 | */ 255 | getChecks: (stationuuid, seconds=0) => { 256 | let route = 'checks', 257 | params = false 258 | 259 | if (stationuuid) { 260 | route += '/' + stationuuid 261 | } 262 | if (seconds > 0) { 263 | params = {seconds: seconds} 264 | } 265 | return apiClient.request(route, params) 266 | }, 267 | 268 | /** 269 | * List of station check steps 270 | * https://de1.api.radio-browser.info/#List_of_station_check_steps 271 | * 272 | * @param {array} uuids array of station uuids 273 | */ 274 | getChecksteps: (uuids) => { 275 | let route = 'checksteps', 276 | params = {uuids: uuids.join(',')} 277 | 278 | return apiClient.request(route, params) 279 | }, 280 | 281 | /** 282 | * List of station clicks 283 | * 284 | * 285 | * @param {string} stationuuid 286 | * @param {integer} seconds 287 | */ 288 | getClicks: (stationuuid, seconds=0) => { 289 | let route = 'clicks', 290 | params = false 291 | 292 | if (stationuuid) { 293 | route += '/' + stationuuid 294 | } 295 | if (seconds > 0) { 296 | params = {seconds: seconds} 297 | } 298 | 299 | return apiClient.request(route, params) 300 | }, 301 | 302 | /** 303 | * Station click counter 304 | * 305 | * 306 | * @param {string} stationuuid 307 | */ 308 | clickStation: (stationuuid) => { 309 | return apiClient.request('url/' + stationuuid) 310 | }, 311 | 312 | /** 313 | * Advanced Search Stations 314 | * https://de1.api.radio-browser.info/#Advanced_station_search 315 | * 316 | * @param {object} params for parameters see link above 317 | * @returns {promise} 318 | */ 319 | searchStations: (params) => apiClient.request('stations/search', params), 320 | 321 | /** 322 | * Vote for station 323 | * https://de1.api.radio-browser.info/#Vote_for_station 324 | * 325 | * @param {number} stationuuid 326 | */ 327 | voteStation: (stationuuid) => apiClient.request('vote/' + stationuuid), 328 | 329 | /** 330 | * delete a station by staionuuid 331 | * https://de1.api.radio-browser.info/#Delete_a_station 332 | * 333 | * @param {string} stationuuid 334 | */ 335 | deleteStation: stationuuid => apiClient.request('delete/' + encodeURI(stationuuid)), 336 | 337 | /** 338 | * undelete a station by staionid 339 | * https://de1.api.radio-browser.info/#UnDelete_a_station 340 | * @depracted not suported by radio-browser.info 341 | * @param {number} stationuuid 342 | */ 343 | undeleteStation: (stationuuid) => apiClient.request('undelete/' + stationuuid), 344 | 345 | /** 346 | * Add radio station. 347 | * https://de1.api.radio-browser.info/#Add_radio_station 348 | * 349 | * @param {object} params See link above for parameters 350 | */ 351 | addStation: (params) => apiClient.request('add', params), 352 | 353 | /** 354 | * edit a station by stationid 355 | * https://de1.api.radio-browser.info/#Edit_a_radio_station 356 | * 357 | * @deprecated not suported by radio-browser.info 358 | * @param {number} stationuuid See link above for parameters 359 | * @param {object} params 360 | */ 361 | editStation: (stationuuid, params) => apiClient.request('edit/' + stationuuid, params), 362 | 363 | /** 364 | * Server stats 365 | * https://de1.api.radio-browser.info/#Server_stats 366 | */ 367 | getServerStats: () => apiClient.request('stats'), 368 | 369 | /** 370 | * Server mirrors 371 | * https://de1.api.radio-browser.info/#Server_mirrors 372 | */ 373 | getServerMirrors: () => apiClient.request('servers'), 374 | 375 | /** 376 | * Server config 377 | * 378 | */ 379 | getServerConfig: () => apiClient.request('config'), 380 | 381 | /** 382 | * list of types used in getStations({by: }) 383 | * 384 | * @var {array} 385 | */ 386 | get filter_by_types() { 387 | return Object.keys(FILTER_BY); 388 | }, 389 | 390 | /** 391 | * list of categories using in getCategory({category}[, filter]) 392 | * 393 | * @returns {array} 394 | */ 395 | get category_types() { 396 | return CATEGORY_TYPES.slice(0); 397 | } 398 | } 399 | --------------------------------------------------------------------------------