diff --git a/radiomanifest.js b/radiomanifest.js index 07b57ac..3f11c06 100644 --- a/radiomanifest.js +++ b/radiomanifest.js @@ -14,12 +14,13 @@ function getAttribute(el, attr, default_value) { } class Radio { - constructor (sources, schedule, shows, feed) { + constructor (sources, schedule, showsURL, feed) { this.streaming = new RadioStreaming(sources) this.schedule = schedule - this.shows = shows + this.showsURL = showsURL this.feed = feed this.name = '' + this.shows = [] } getStreaming () { @@ -30,7 +31,11 @@ class Radio { this.name = name } + getShows() { + return this.shows + } getShowByName (showName) { + return this.shows.find(s => s.name === showName) } getSchedule () { @@ -63,9 +68,9 @@ class Radio { res = xml.evaluate('/radio-manifest/shows', xml) const showsEl = res.iterateNext() - let shows = null + let showsURL = null if (showsEl !== null) { - shows = showsEl.getAttribute('src') + showsURL = showsEl.getAttribute('src') } res = xml.evaluate('/radio-manifest/feed', xml) @@ -75,7 +80,7 @@ class Radio { feed = feedEl.getAttribute('src') } - const manifest = new Radio(sources, schedule, shows, feed) + const manifest = new Radio(sources, schedule, showsURL, feed) return manifest } } @@ -138,6 +143,12 @@ async function get (siteurl, options) { const dom = parser.parseFromString(text, 'text/xml') const manifest = Radio.fromDOM(dom) + try { + manifest.shows = await getShows(manifest) + } catch (e) { + console.error("Error while fetching shows file", e) + } + resp = null try { resp = await fetch(getStreaminfoUrl(siteurl)) @@ -163,10 +174,33 @@ async function get (siteurl, options) { } } - // XXX: in base alle options fai fetch anche di altra roba return manifest } +async function getShows(manifest) { + if (manifest.showsURL) { + let resp = null + try { + resp = await fetch(manifest.showsURL) + } catch (e) { + true + } + if (resp !== null) { + try { + text = await resp.text() + const parser = new DOMParser() + const showsDom = parser.parseFromString(text, 'text/xml') + return parseRadioShows(showsDom) + } catch (e) { + console.error('Error while parsing shows file', e) + throw e + } + } + } +} + + + function parseM3U (body) { return body.split('\n').filter((line) => { if (line.startsWith('#')) { @@ -181,6 +215,61 @@ function parseM3U (body) { }) } +class RadioShow { + constructor(name, description, website, feed, schedule, radio_calendar) { + this.name = name + this.description = description + this.website = website + this.feed = feed + this.schedule = schedule + this.radio_calendar = radio_calendar + } + + getName() { + return this.name + } + getWebsite() { + return this.website + } + getFeed() { + return this.feed + } + getSchedule() { + return this.schedule + } + +} + +function showsNamespaceResolver(prefix) { + const prefixes = { + show: 'https://radiomanifest.degenerazione.xyz/shows/', + } + return prefixes[prefix] || null +} + +function parseRadioShows(xml) { + const doc = xml.cloneNode(true) + const bookmarks = doc.evaluate('//bookmark', doc, showsNamespaceResolver, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null) + const shows = [] + for (let i = 0; i < bookmarks.snapshotLength; i++) { + const bm = bookmarks.snapshotItem(i) + + const name = doc.evaluate('./info/metadata/show:name', bm, showsNamespaceResolver, XPathResult.STRING_TYPE).stringValue + const website = doc.evaluate('./info/metadata/show:website', bm, showsNamespaceResolver, XPathResult.STRING_TYPE).stringValue + const feed = doc.evaluate('./info/metadata/show:feed', bm, showsNamespaceResolver, XPathResult.STRING_TYPE).stringValue + const schedule = doc.evaluate('./info/metadata/show:schedule', bm, showsNamespaceResolver, XPathResult.STRING_TYPE).stringValue + let description = doc.evaluate('./info/metadata/show:description', bm, showsNamespaceResolver, XPathResult.STRING_TYPE).stringValue + if(description === '') { + description = doc.evaluate('./description', bm, showsNamespaceResolver, XPathResult.STRING_TYPE).stringValue + } + + const show = new RadioShow(name || null, description, website || null, feed || null, schedule || null) + shows.push(show) + } + + return shows +} + module.exports = { get: get, objs: { @@ -189,6 +278,7 @@ module.exports = { }, parsers: { M3U: parseM3U, - radioManifest: Radio.fromDOM + radioManifest: Radio.fromDOM, + shows: parseRadioShows, } } diff --git a/test/example-full-ondarossa.test.js b/test/example-full-ondarossa.test.js new file mode 100644 index 0000000..80bc62d --- /dev/null +++ b/test/example-full-ondarossa.test.js @@ -0,0 +1,25 @@ +const radiomanifest = require('../radiomanifest.js') +const chai = require('chai') +chai.use(require('chai-as-promised')) +const assert = chai.assert + +const exampleName = 'full-ondarossa' +const expect = chai.expect +const url = 'https://radiomanifest.degenerazione.xyz/v0.2/examples/' + exampleName + '/' + +describe('examples/' + exampleName, () => { + describe('shows', () => { + it('shoud find many shows', async () => { + const rm = await radiomanifest.get(url) + assert.isAbove(rm.getShows().length, 1) + }) + it('one of which is called "Entropia Massima"', async () => { + const rm = await radiomanifest.get(url) + const show = rm.getShowByName("Entropia Massima") + assert.equal(show.getName(), "Entropia Massima") + assert.equal(show.getWebsite(), "http://www.ondarossa.info/trx/entropia-massima") + assert.equal(show.getSchedule(), null) + }) + }) +}) +