Browse Source

make it ESM ready

lesion 1 year ago
parent
commit
207f06a791
1 changed files with 287 additions and 291 deletions
  1. 287 291
      radiomanifest.js

+ 287 - 291
radiomanifest.js

@@ -1,170 +1,174 @@
-const fetch = require('isomorphic-unfetch')
-const shows = require('./shows.js')
-const calendar = require('./calendar.js')
+import fetch from 'isomorphic-unfetch'
+import shows from './shows.js'
+import calendar from './calendar.js'
 
-function getStreaminfoUrl (siteurl) {
-  return siteurl + '/streaminfo.json' // XXX: improve this logic
+function getStreaminfoUrl(siteurl) {
+    return siteurl + "/streaminfo.json" // XXX: improve this logic
 }
-function getManifestUrl (siteurl) {
-  return siteurl + '/radiomanifest.xml' // XXX: improve this logic
+function getManifestUrl(siteurl) {
+    return siteurl + "/radiomanifest.xml" // XXX: improve this logic
 }
 
 function getAttribute(el, attr, default_value) {
-  if(el.hasAttribute(attr))
-    return el.getAttribute(attr);
-  return default_value;
+    if (el.hasAttribute(attr)) return el.getAttribute(attr)
+    return default_value
 }
 
 /**
  * Represents everything we know about a radio. This includes, but is not limited to, radiomanifest.xml.
  */
 class Radio {
+    /**
+     * @param {Array}  [sources] optional
+     * @param {string} [scheduleURL]
+     * @param {string} [showsURL]
+     * @param {string} [feed]
+     */
+    constructor(sources, scheduleURL, showsURL, feed) {
+        this.streaming = new RadioStreaming(sources)
+        this.scheduleURL = scheduleURL
+        this.showsURL = showsURL
+        this.feed = feed
+        this.name = ""
+        this.description = ""
+        this.logo = null
+        this.shows = []
+        this.schedule = null
+    }
 
-  /**
-   * @param {Array}  [sources] optional
-   * @param {string} [scheduleURL]
-   * @param {string} [showsURL]
-   * @param {string} [feed]
-   */
-  constructor (sources, scheduleURL, showsURL, feed) {
-    this.streaming = new RadioStreaming(sources)
-    this.scheduleURL = scheduleURL
-    this.showsURL = showsURL
-    this.feed = feed
-    this.name = ''
-    this.description = ''
-    this.logo = null
-    this.shows = []
-    this.schedule = null
-  }
-
-  /**
-   * @returns {RadioStreaming}
-   */
-  getStreaming () {
-    return this.streaming
-  }
-
-  setName (name) {
-    this.name = name
-  }
-
-  /**
-   * The radio name, as inferred by stream-meta
-   *
-   * @returns {string}
-   */
-  getName() {
-    return this.name
-  }
-
-  setDescription(desc) {
-    this.description = desc
-  }
-
-  /**
-   * The description of the radio, as inferred by stream-meta
-   *
-   * @returns {string}
-   */
-  getDescription() {
-    return this.description
-  }
-
-  setLogo(logo) {
-    this.logo = logo
-  }
-
-  /**
-   * @returns {string} the URL of the logo, or `null` if not found
-   */
-  getLogo() {
-    return this.logo
-  }
-
-  /**
-   *
-   * @returns {Array<RadioShow>}
-   */
-  getShows() {
-    return this.shows
-  }
-
-  /**
-   * @returns {RadioShow} The lookup is exact and case-sensitive. If no such show can be found, `null`
-   * is returned.
-   */
-  getShowByName (showName) {
-    if (this.shows === undefined) return null
-    return this.shows.find(s => s.name === showName)
-  }
-
-  /**
-   * @returns {RadioSchedule} If no schedule is present, `null` is returned.
-   */
-  getSchedule () {
-    return this.schedule
-  }
-
-  /**
-   * Find if a show is running at the given moment. If there's none, `null` is returned.
-   * If possible, a complete {@link RadioShow} including full informations (from shows.xml) is returned.
-   * If, instead, we know from the `schedule` that there must be a show, but have no additional detail, a
-   * {@link RadioShow} object will be created on the fly.
-   *
-   * @param {ICAL.Time} [now] If omitted, the current time is used.
-   * @returns {RadioShow} If we don't know what's going on at the given moment, `null` is returned.
-   */
-  getShowAtTime (now) {
-    if (this.schedule === undefined || this.schedule === null) return null
-    return this.getSchedule().getNowShow(now)
-  }
-
-  /**
-   * This static method can create a Radio object from a valid radiomanifest.xml file
-   *
-   * @param xml An already parsed xml block
-   * @returns {Radio}
-   */
-  static fromDOM (xml) {
-    const doc = xml.cloneNode(true)
-    let res = doc.evaluate('/radio-manifest/streaming/source', doc, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null)
-    const sources = []
-    for (let i = 0; i < res.snapshotLength; i++) {
-      const src = res.snapshotItem(i)
-
-      if (!src.hasAttribute('priority')) {
-        src.setAttribute('priority', '0')
-      } else if (parseInt(src.getAttribute('priority'), 10) < 0) {
-        continue
-      }
-      sources.push(src)
+    /**
+     * @returns {RadioStreaming}
+     */
+    getStreaming() {
+        return this.streaming
     }
 
-    res = doc.evaluate('/radio-manifest/schedule', doc)
-    const scheduleEl = res.iterateNext()
-    let scheduleURL = null
-    if (scheduleEl !== null) {
-      scheduleURL = scheduleEl.getAttribute('src')
+    setName(name) {
+        this.name = name
     }
 
-    res = xml.evaluate('/radio-manifest/shows', xml)
-    const showsEl = res.iterateNext()
-    let showsURL = null
-    if (showsEl !== null) {
-      showsURL = showsEl.getAttribute('src')
+    /**
+     * The radio name, as inferred by stream-meta
+     *
+     * @returns {string}
+     */
+    getName() {
+        return this.name
     }
 
-    res = xml.evaluate('/radio-manifest/feed', xml)
-    const feedEl = res.iterateNext()
-    let feed = null
-    if (feedEl !== null) {
-      feed = feedEl.getAttribute('src')
+    setDescription(desc) {
+        this.description = desc
     }
 
-    const manifest = new Radio(sources, scheduleURL, showsURL, feed)
-    return manifest
-  }
+    /**
+     * The description of the radio, as inferred by stream-meta
+     *
+     * @returns {string}
+     */
+    getDescription() {
+        return this.description
+    }
+
+    setLogo(logo) {
+        this.logo = logo
+    }
+
+    /**
+     * @returns {string} the URL of the logo, or `null` if not found
+     */
+    getLogo() {
+        return this.logo
+    }
+
+    /**
+     *
+     * @returns {Array<RadioShow>}
+     */
+    getShows() {
+        return this.shows
+    }
+
+    /**
+     * @returns {RadioShow} The lookup is exact and case-sensitive. If no such show can be found, `null`
+     * is returned.
+     */
+    getShowByName(showName) {
+        if (this.shows === undefined) return null
+        return this.shows.find(s => s.name === showName)
+    }
+
+    /**
+     * @returns {RadioSchedule} If no schedule is present, `null` is returned.
+     */
+    getSchedule() {
+        return this.schedule
+    }
+
+    /**
+     * Find if a show is running at the given moment. If there's none, `null` is returned.
+     * If possible, a complete {@link RadioShow} including full informations (from shows.xml) is returned.
+     * If, instead, we know from the `schedule` that there must be a show, but have no additional detail, a
+     * {@link RadioShow} object will be created on the fly.
+     *
+     * @param {ICAL.Time} [now] If omitted, the current time is used.
+     * @returns {RadioShow} If we don't know what's going on at the given moment, `null` is returned.
+     */
+    getShowAtTime(now) {
+        if (this.schedule === undefined || this.schedule === null) return null
+        return this.getSchedule().getNowShow(now)
+    }
+
+    /**
+     * This static method can create a Radio object from a valid radiomanifest.xml file
+     *
+     * @param xml An already parsed xml block
+     * @returns {Radio}
+     */
+    static fromDOM(xml) {
+        const doc = xml.cloneNode(true)
+        let res = doc.evaluate(
+            "/radio-manifest/streaming/source",
+            doc,
+            null,
+            XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
+            null
+        )
+        const sources = []
+        for (let i = 0; i < res.snapshotLength; i++) {
+            const src = res.snapshotItem(i)
+
+            if (!src.hasAttribute("priority")) {
+                src.setAttribute("priority", "0")
+            } else if (parseInt(src.getAttribute("priority"), 10) < 0) {
+                continue
+            }
+            sources.push(src)
+        }
+
+        res = doc.evaluate("/radio-manifest/schedule", doc)
+        const scheduleEl = res.iterateNext()
+        let scheduleURL = null
+        if (scheduleEl !== null) {
+            scheduleURL = scheduleEl.getAttribute("src")
+        }
+
+        res = xml.evaluate("/radio-manifest/shows", xml)
+        const showsEl = res.iterateNext()
+        let showsURL = null
+        if (showsEl !== null) {
+            showsURL = showsEl.getAttribute("src")
+        }
+
+        res = xml.evaluate("/radio-manifest/feed", xml)
+        const feedEl = res.iterateNext()
+        let feed = null
+        if (feedEl !== null) {
+            feed = feedEl.getAttribute("src")
+        }
+
+        const manifest = new Radio(sources, scheduleURL, showsURL, feed)
+        return manifest
+    }
 }
 
 /**
@@ -172,75 +176,71 @@ class Radio {
  * This has probably been derived from the <streaming> block in radiomanifest.xml
  */
 class RadioStreaming {
-  constructor (sources) {
-    this.sources = sources.sort(
-        (a,b) => this.getPriority(a) < this.getPriority(a) 
-        )
-  }
-
-  /**
-   * Get the list of possible options that are provided to the user
-   * @returns {Array<string>}
-   */
-  getOptions() {
-    return this.sources.map(function (x) {
-        return x.getAttribute('name')
+    constructor(sources) {
+        this.sources = sources.sort((a, b) => this.getPriority(a) < this.getPriority(a))
+    }
+
+    /**
+     * Get the list of possible options that are provided to the user
+     * @returns {Array<string>}
+     */
+    getOptions() {
+        return this.sources.map(function (x) {
+            return x.getAttribute("name")
         })
-  }
-
-  /**
-   * @private
-   */
-  getPriority(element) {
-    return parseInt(getAttribute(element, 'priority', '1'))
-  }
-  /**
-   * @private
-   */
-  getTopPrioritySources() {
-    var topPriority = this.getPriority(this.sources[0])
-    return this.sources.filter(
-        (src) => parseInt(src.getAttribute('priority'), 10) === topPriority
-        )
-  }
-  /**
-   * @return {string} url of the source. Note that this is much probably a playlist, in M3U format
-   */
-  getSource(name) {
-    if (name === undefined) {
-      return this.getTopPrioritySources()[0]
     }
-    const s = this.sources.find(function (x) {
-        return x.getAttribute('name') === name
+
+    /**
+     * @private
+     */
+    getPriority(element) {
+        return parseInt(getAttribute(element, "priority", "1"))
+    }
+    /**
+     * @private
+     */
+    getTopPrioritySources() {
+        var topPriority = this.getPriority(this.sources[0])
+        return this.sources.filter(src => parseInt(src.getAttribute("priority"), 10) === topPriority)
+    }
+    /**
+     * @return {string} url of the source. Note that this is much probably a playlist, in M3U format
+     */
+    getSource(name) {
+        if (name === undefined) {
+            return this.getTopPrioritySources()[0]
+        }
+        const s = this.sources.find(function (x) {
+            return x.getAttribute("name") === name
         })
-    if (s === undefined) return s
-      return s.getAttribute('src')
-  }
-  
-  /**
-   * This is your go-to function whenever you need a list of URLs to play.
-   * They will be picked honoring priorities, and expanding the playlist source
-   * @return {Array<string>}
-   */
-  async pickURLs() {
-    var allSources = this.getTopPrioritySources()
-    var allAudios = []
-    for(let src of allSources) {
-      let url = src.getAttribute('src')
-      let resp = await fetch(url)
-      allAudios.unshift(... parseM3U(await resp.text()))
+        if (s === undefined) return s
+        return s.getAttribute("src")
+    }
+
+    /**
+     * This is your go-to function whenever you need a list of URLs to play.
+     * They will be picked honoring priorities, and expanding the playlist source
+     * @return {Array<string>}
+     */
+    async pickURLs() {
+        var allSources = this.getTopPrioritySources()
+        var allAudios = []
+        for (let src of allSources) {
+            let url = src.getAttribute("src")
+            let resp = await fetch(url)
+            allAudios.unshift(...parseM3U(await resp.text()))
+        }
+        return allAudios
+    }
+
+    /**
+     * Just like {@link RadioStreaming#pickURLs}, but get a single URL
+     * @return {string}
+     */
+    async pickURL() {
+        var allAudios = await this.pickURLs()
+        return allAudios[0]
     }
-    return allAudios
-  }
-
-  /**
-   * Just like {@link RadioStreaming#pickURLs}, but get a single URL
-   * @return {string}
-   */
-  async pickURL() {
-    var allAudios = await this.pickURLs()
-    return allAudios[0]
-  }
 }
 
 /**
@@ -250,92 +250,88 @@ class RadioStreaming {
  * @param {Object} options options. Currenly unused
  * @return {Radio}
  */
-async function get (siteurl, options) {
-  let resp = await fetch(getManifestUrl(siteurl))
-  let text = await resp.text()
-
-  const parser = new DOMParser()
-  const dom = parser.parseFromString(text, 'text/xml')
-  const manifest = Radio.fromDOM(dom)
-
-  try {
-    manifest.shows = await shows.get(manifest)
-  } catch (e) {
-    console.error("Error while fetching shows file", e)
-  }
-
-  try {
-    manifest.schedule = await calendar.get(manifest)
-    if (manifest.schedule !== undefined)
-      manifest.schedule.radio = manifest
-  } catch (e) {
-    console.error("Error while fetching shows file", e)
-  }
-
-
-  resp = null
-  try {
-    resp = await fetch(getStreaminfoUrl(siteurl))
-  } catch (e) {
-    true
-  }
-  if(resp !== null) {
+async function get(siteurl, options) {
+    let resp = await fetch(getManifestUrl(siteurl))
+    let text = await resp.text()
+
+    const parser = new DOMParser()
+    const dom = parser.parseFromString(text, "text/xml")
+    const manifest = Radio.fromDOM(dom)
+
     try {
-      text = await resp.text()
-
-      const data = JSON.parse(text)
-      const name = data['icy-name']
-      if (name !== undefined) {
-        manifest.setName(name)
-      }
-      const desc = data['icy-description']
-      if (desc !== undefined) {
-        manifest.setDescription(desc)
-      }
-
-      const logo = data['icy-logo']
-      if (desc !== undefined) {
-        manifest.setLogo(logo)
-      }
+        manifest.shows = await shows.get(manifest)
     } catch (e) {
-      if (e instanceof SyntaxError) {
-        true
-      } else {
-        console.error('Error', e)
-          throw e
-      }
+        console.error("Error while fetching shows file", e)
     }
-  }
-
-  return manifest
-}
-
 
+    try {
+        manifest.schedule = await calendar.get(manifest)
+        if (manifest.schedule !== undefined) manifest.schedule.radio = manifest
+    } catch (e) {
+        console.error("Error while fetching shows file", e)
+    }
 
-function parseM3U (body) {
-  return body.split('\n').filter((line) => {
-    if (line.startsWith('#')) {
-      return false
-    } else {
-      try {
-        new URL(line); return true
-      } catch {
-        return false
-      }
+    resp = null
+    try {
+        resp = await fetch(getStreaminfoUrl(siteurl))
+    } catch (e) {
+        true
     }
-  })
+    if (resp !== null) {
+        try {
+            text = await resp.text()
+
+            const data = JSON.parse(text)
+            const name = data["icy-name"]
+            if (name !== undefined) {
+                manifest.setName(name)
+            }
+            const desc = data["icy-description"]
+            if (desc !== undefined) {
+                manifest.setDescription(desc)
+            }
+
+            const logo = data["icy-logo"]
+            if (desc !== undefined) {
+                manifest.setLogo(logo)
+            }
+        } catch (e) {
+            if (e instanceof SyntaxError) {
+                true
+            } else {
+                console.error("Error", e)
+                throw e
+            }
+        }
+    }
+
+    return manifest
 }
 
+function parseM3U(body) {
+    return body.split("\n").filter(line => {
+        if (line.startsWith("#")) {
+            return false
+        } else {
+            try {
+                new URL(line)
+                return true
+            } catch {
+                return false
+            }
+        }
+    })
+}
 
-module.exports = {
-  get: get,
-  objs: {
-    Radio: Radio,
-    RadioStreaming: RadioStreaming
-  },
-  parsers: {
-    M3U: parseM3U,
-    radioManifest: Radio.fromDOM,
-    shows: shows.parse,
-  }
+export default {
+    get: get,
+    objs: {
+        Radio: Radio,
+        RadioStreaming: RadioStreaming
+    },
+    parsers: {
+        M3U: parseM3U,
+        radioManifest: Radio.fromDOM,
+        shows: shows.parse
+    }
 }