diff --git a/.idea/workspace.xml b/.idea/workspace.xml index e622cd65b7650db7c3543717e1ad52103ab08e5a..f725a49594ca8b8b1ec5847e2aef9a4ebe89825a 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -4,7 +4,15 @@ <option name="autoReloadType" value="SELECTIVE" /> </component> <component name="ChangeListManager"> - <list default="true" id="dc2eda89-ce72-4bfb-9c82-f9fb4ab5dde0" name="Changes" comment="Lets start over. (Not bumping version because thats stupid)" /> + <list default="true" id="dc2eda89-ce72-4bfb-9c82-f9fb4ab5dde0" name="Changes" comment="Add NPM boilerplate"> + <change afterPath="$PROJECT_DIR$/waves/examples/assets/noise.wav" afterDir="false" /> + <change afterPath="$PROJECT_DIR$/waves/examples/embed_basic.html" afterDir="false" /> + <change afterPath="$PROJECT_DIR$/waves/examples/player_basic.html" afterDir="false" /> + <change afterPath="$PROJECT_DIR$/waves/src/embed.html" afterDir="false" /> + <change afterPath="$PROJECT_DIR$/waves/src/station.js" afterDir="false" /> + <change afterPath="$PROJECT_DIR$/waves/src/waves.js" afterDir="false" /> + <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" /> + </list> <option name="SHOW_DIALOG" value="false" /> <option name="HIGHLIGHT_CONFLICTS" value="true" /> <option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" /> @@ -16,6 +24,7 @@ <option value="CSS File" /> <option value="SCSS File" /> <option value="JavaScript File" /> + <option value="HTML File" /> </list> </option> </component> @@ -27,6 +36,22 @@ </option> <option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" /> </component> + <component name="GitLabMergeRequestFiltersHistory"><![CDATA[{ + "lastFilter": { + "state": "OPENED", + "assignee": { + "type": "org.jetbrains.plugins.gitlab.mergerequest.ui.filters.GitLabMergeRequestsFiltersValue.MergeRequestsMemberFilterValue.MergeRequestsAssigneeFilterValue", + "username": "bye", + "fullname": "Bye" + } + } +}]]></component> + <component name="GitLabMergeRequestsSettings"><![CDATA[{ + "selectedUrlAndAccountId": { + "first": "https://shinonome.rocks/bye/waves.git", + "second": "348e169e-b102-4043-9c6f-b59fa6d1c8d2" + } +}]]></component> <component name="ProjectColorInfo">{ "associatedIndex": 0 }</component> @@ -38,10 +63,11 @@ <component name="PropertiesComponent">{ "keyToString": { "ASKED_SHARE_PROJECT_CONFIGURATION_FILES": "true", + "DefaultHtmlFileTemplate": "HTML File", "RunOnceActivity.ShowReadmeOnStart": "true", "RunOnceActivity.git.unshallow": "true", "git-widget-placeholder": "master", - "last_opened_file_path": "/shop/code/waves", + "last_opened_file_path": "/shop/code/waves/waves/src/assets", "list.type.of.created.stylesheet": "SCSS", "node.js.detected.package.eslint": "true", "node.js.detected.package.tslint": "true", @@ -57,9 +83,11 @@ }</component> <component name="RecentsManager"> <key name="CopyFile.RECENT_KEYS"> + <recent name="$PROJECT_DIR$/waves/src/assets" /> <recent name="$PROJECT_DIR$" /> </key> <key name="MoveFile.RECENT_KEYS"> + <recent name="$PROJECT_DIR$/waves/examples" /> <recent name="$PROJECT_DIR$/public" /> <recent name="$PROJECT_DIR$/src" /> <recent name="$PROJECT_DIR$" /> @@ -120,7 +148,8 @@ <workItem from="1740323680481" duration="8000" /> <workItem from="1741975972036" duration="5487000" /> <workItem from="1742126058949" duration="567000" /> - <workItem from="1742499282237" duration="423000" /> + <workItem from="1742499282237" duration="6271000" /> + <workItem from="1742575186970" duration="7655000" /> </task> <task id="LOCAL-00001" summary="Lets start over. (Not bumping version because thats stupid)"> <option name="closed" value="true" /> @@ -130,7 +159,15 @@ <option name="project" value="LOCAL" /> <updated>1742499316615</updated> </task> - <option name="localTasksCounter" value="2" /> + <task id="LOCAL-00002" summary="Add NPM boilerplate"> + <option name="closed" value="true" /> + <created>1742499870306</created> + <option name="number" value="00002" /> + <option name="presentableId" value="LOCAL-00002" /> + <option name="project" value="LOCAL" /> + <updated>1742499870306</updated> + </task> + <option name="localTasksCounter" value="3" /> <servers /> </component> <component name="TypeScriptGeneratedFilesManager"> @@ -149,6 +186,7 @@ </component> <component name="VcsManagerConfiguration"> <MESSAGE value="Lets start over. (Not bumping version because thats stupid)" /> - <option name="LAST_COMMIT_MESSAGE" value="Lets start over. (Not bumping version because thats stupid)" /> + <MESSAGE value="Add NPM boilerplate" /> + <option name="LAST_COMMIT_MESSAGE" value="Add NPM boilerplate" /> </component> </project> \ No newline at end of file diff --git a/waves/examples/assets/noise.wav b/waves/examples/assets/noise.wav new file mode 100644 index 0000000000000000000000000000000000000000..c185070f3462bc5bc94d66c5c286dbcc1580898f Binary files /dev/null and b/waves/examples/assets/noise.wav differ diff --git a/waves/examples/embed_basic.html b/waves/examples/embed_basic.html new file mode 100644 index 0000000000000000000000000000000000000000..2b4bb5edd039141704824a8c5c4229048f9fee30 --- /dev/null +++ b/waves/examples/embed_basic.html @@ -0,0 +1,16 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="UTF-8"> + <title>waves ~ basic embed</title> +</head> +<body> + + <script type="module"> + import Waves from "../src/waves.js"; + + const waves = new Waves(); + + </script> +</body> +</html> \ No newline at end of file diff --git a/waves/examples/player_basic.html b/waves/examples/player_basic.html new file mode 100644 index 0000000000000000000000000000000000000000..4361383c1418cb6f232f5177d2a32858f020d2eb --- /dev/null +++ b/waves/examples/player_basic.html @@ -0,0 +1,23 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="UTF-8"> + <title>waves ~ basic player</title> +</head> +<body> + <script type="module"> + import Waves from "../src/waves.js"; + import {URLStation} from "../src/station.js"; + + const waves = new Waves(); + waves.loadingSoundElem.src = "./assets/noise.wav"; + waves.loadingSoundElem.load(); + + const testStation = new URLStation("tilde", "https://tilde.radikan.byecorps.net/listen/tilde/radio.mp3"); + waves.addStation(testStation); + + waves.setStation("tilde"); + waves.play(); + </script> +</body> +</html> \ No newline at end of file diff --git a/waves/src/embed.html b/waves/src/embed.html new file mode 100644 index 0000000000000000000000000000000000000000..30f86f29be8cfa59e506462ac87ff3b224ebcbe8 --- /dev/null +++ b/waves/src/embed.html @@ -0,0 +1,10 @@ +<!-- + + waves + (c) 2025 bye + + Code for quickly embedding waves on another website. + +--> + + diff --git a/waves/src/station.js b/waves/src/station.js new file mode 100644 index 0000000000000000000000000000000000000000..183c78aad6c03a522a843e625b28ce96ee72c065 --- /dev/null +++ b/waves/src/station.js @@ -0,0 +1,61 @@ + +class Station { + constructor(name) { + this.name = name; + this.player = new Audio(); + + this.player.addEventListener("seeking", _ => { + console.log(`${this.name}: Started seeking... (${this.player.duration}, ${this.player.currentTime})`); + }); + + this.player.addEventListener("seeked", _ => { + console.log(`${this.name}: Seeked... (${this.player.duration}, ${this.player.currentTime})`); + }); + + this.metadataSource = undefined; + } + + play() { + this.player.load(); + + this.player.addEventListener("canplay", _=>{ + this.player.play(); + + console.log(`${this.name}: Started playing... (${this.player.duration}, ${this.player.currentTime}, ${this.player.src})`); + }, {once: true}); + + } + + stop() { + this.player.pause(); + } +} + +class URLStation extends Station { + /** + * Defines a Station that plays from a streamed file. + * + * @param props + * @param url + */ + + constructor(props, url) { + super(props); + this.url = url; + this.doCaching = false; // Append a random number to the filename to avoid caching issues. + + this.player.src = this.url; + this.player.crossOrigin = "crossorigin"; + } + + play() { + const url = new URL(this.url) + url.search = Math.floor(Math.random() * 10000) + this.player.src = url.toString() + + super.play() + } +} + +export default Station; +export {URLStation}; diff --git a/waves/src/waves.js b/waves/src/waves.js new file mode 100644 index 0000000000000000000000000000000000000000..03b5791f0626b71431323078a3abd5c4b522a5ff --- /dev/null +++ b/waves/src/waves.js @@ -0,0 +1,92 @@ +import Station from "./station.js"; + +class Waves { + constructor() { + this.stations = {}; + + this.audioContext = new AudioContext(); + this.gainNode = this.audioContext.createGain(); + + this.loadingSoundElem = new Audio(); // Can be set by client. + this.loadingSoundElem.loop = true; + + this.currentPlayer = new Audio(); + this.currentStation = new Station(); + this.currentTrack = this.audioContext.createMediaElementSource(this.currentPlayer); + this.currentTrack.connect(this.gainNode).connect(this.audioContext.destination); + + const loadingTrack = this.audioContext.createMediaElementSource(this.loadingSoundElem); + loadingTrack.connect(this.gainNode).connect(this.audioContext.destination); + } + + setStation(station) { + this.currentStation.stop(); + + if (!this.stations[station]) { + throw ReferenceError("Station not found."); + } + + this.currentStation = this.stations[station]; + this.currentPlayer = this.currentStation.player; + // this.currentPlayer.controls = "controls"; + delete this.currentTrack; + this.currentTrack = this.audioContext.createMediaElementSource(this.currentPlayer); + this.currentTrack.connect(this.gainNode).connect(this.audioContext.destination); + + this.currentPlayer.addEventListener("playing", ev=>{ + console.debug(`${station}:`, ev) + this.loadingSoundElem.pause(); + }) + + this.currentPlayer.addEventListener("play", ev=>{ + console.debug(`${station}:`, ev) + this.loadingSoundElem.pause(); + }) + + this.currentPlayer.addEventListener("seeked", ev=>{ + console.debug(`${station}:`, ev) + this.loadingSoundElem.pause(); + }) + + this.currentPlayer.addEventListener("seeking", ev=>{ + console.debug(`${station}:`, ev) + this.loadingSoundElem.play(); + }) + + this.currentPlayer.addEventListener("waiting", ev=>{ + console.debug(`${station}:`, ev) + this.loadingSoundElem.play(); + }) + + this.currentPlayer.addEventListener("stalled", ev=>{ + console.debug(`${station}:`, ev) + this.loadingSoundElem.play(); + }) + + this.currentPlayer.addEventListener("ended", ev=>{ + console.debug(`${station}:`, ev) + this.loadingSoundElem.play(); + }) + + this.currentPlayer.addEventListener("error", ev=>{ + console.debug(`${station}:`, ev) + this.loadingSoundElem.play(); + }) + } + + addStation(station) { + this.stations[station.name] = station; + console.log(`Added station ${station.name}`) + } + + play() { + this.currentStation.play(); + } + + // Code that deals with embedding waves + embed() { + document.currentScript.insertAdjacentHTML("beforebegin", EMBED) + } +} + +export default Waves;