From 45877478aaea089599afa5accbde53b4cef1e022 Mon Sep 17 00:00:00 2001 From: Piotrekol <4990365+Piotrekol@users.noreply.github.com> Date: Sun, 7 Nov 2021 13:06:04 +0100 Subject: [PATCH] Misc: Remove web overlay files --- webOverlay/index.html | 125 ------ webOverlay/lib/consts.js | 103 ----- webOverlay/lib/reconnecting-websocket.js | 365 ---------------- webOverlay/lib/tokenTransformer.js | 302 -------------- webOverlay/lib/utils.js | 82 ---- webOverlay/overlays/README.txt | 7 - .../README - DON'T EDIT THIS OVERLAY.txt | 5 - .../overlays/SC_BeatOsu/components/App.js | 47 --- .../SC_BeatOsu/components/Background.js | 54 --- webOverlay/overlays/SC_BeatOsu/index.html | 74 ---- webOverlay/overlays/SC_BeatOsu/main.css | 226 ---------- webOverlay/overlays/SC_BeatOsu/main.js | 7 - .../README - DON'T EDIT THIS OVERLAY.txt | 5 - .../SC_Live Overlay/components/App.js | 104 ----- .../SC_Live Overlay/components/Background.js | 57 --- .../SC_Live Overlay/components/LineChart.js | 119 ------ .../overlays/SC_Live Overlay/index.html | 78 ---- webOverlay/overlays/SC_Live Overlay/main.css | 229 ----------- webOverlay/overlays/SC_Live Overlay/main.js | 7 - .../README - DON'T EDIT THIS OVERLAY.txt | 5 - .../overlays/SC_Map Example/components/App.js | 39 -- .../SC_Map Example/components/Background.js | 54 --- webOverlay/overlays/SC_Map Example/index.html | 57 --- webOverlay/overlays/SC_Map Example/main.css | 85 ---- webOverlay/overlays/SC_Map Example/main.js | 7 - .../README - DON'T EDIT THIS OVERLAY.txt | 5 - .../overlays/SC_Map Overlay/components/App.js | 73 ---- .../SC_Map Overlay/components/Background.js | 62 --- webOverlay/overlays/SC_Map Overlay/index.html | 45 -- webOverlay/overlays/SC_Map Overlay/main.css | 79 ---- webOverlay/overlays/SC_Map Overlay/main.js | 7 - .../SC_Map Overlay/orginal file/app.svelte | 157 ------- .../README - DON'T EDIT THIS OVERLAY.txt | 5 - .../overlays/SC_PP Counter/components/App.js | 33 -- .../SC_PP Counter/components/Background.js | 54 --- webOverlay/overlays/SC_PP Counter/index.html | 61 --- webOverlay/overlays/SC_PP Counter/main.css | 94 ----- webOverlay/overlays/SC_PP Counter/main.js | 7 - .../README - DON'T EDIT THIS OVERLAY.txt | 5 - .../overlays/SC_Template/components/App.js | 25 -- webOverlay/overlays/SC_Template/index.html | 23 -- webOverlay/overlays/SC_Template/main.css | 17 - webOverlay/overlays/SC_Template/main.js | 7 - .../README - DON'T EDIT THIS OVERLAY.txt | 5 - .../overlays/SC_Token/components/App.js | 50 --- webOverlay/overlays/SC_Token/index.html | 32 -- webOverlay/overlays/SC_Token/main.css | 17 - webOverlay/overlays/SC_Token/main.js | 7 - .../README - DON'T EDIT THIS OVERLAY.txt | 5 - .../overlays/SC_URBar/components/App.js | 27 -- .../SC_URBar/components/roundURBar.js | 389 ------------------ webOverlay/overlays/SC_URBar/index.html | 25 -- webOverlay/overlays/SC_URBar/main.css | 17 - webOverlay/overlays/SC_URBar/main.js | 7 - .../README - DON'T EDIT THIS OVERLAY.txt | 5 - webOverlay/overlays/SC_bg/components/App.js | 27 -- .../overlays/SC_bg/components/Background.js | 55 --- webOverlay/overlays/SC_bg/index.html | 24 -- webOverlay/overlays/SC_bg/main.css | 47 --- webOverlay/overlays/SC_bg/main.js | 7 - webOverlay/overlays/static/README.txt | 5 - webOverlay/overlays/static/convert.bat | 5 - webOverlay/overlays/static/fart.exe | Bin 69660 -> 0 bytes webOverlay/staticLoader.html | 63 --- 64 files changed, 3821 deletions(-) delete mode 100644 webOverlay/index.html delete mode 100644 webOverlay/lib/consts.js delete mode 100644 webOverlay/lib/reconnecting-websocket.js delete mode 100644 webOverlay/lib/tokenTransformer.js delete mode 100644 webOverlay/lib/utils.js delete mode 100644 webOverlay/overlays/README.txt delete mode 100644 webOverlay/overlays/SC_BeatOsu/README - DON'T EDIT THIS OVERLAY.txt delete mode 100644 webOverlay/overlays/SC_BeatOsu/components/App.js delete mode 100644 webOverlay/overlays/SC_BeatOsu/components/Background.js delete mode 100644 webOverlay/overlays/SC_BeatOsu/index.html delete mode 100644 webOverlay/overlays/SC_BeatOsu/main.css delete mode 100644 webOverlay/overlays/SC_BeatOsu/main.js delete mode 100644 webOverlay/overlays/SC_Live Overlay/README - DON'T EDIT THIS OVERLAY.txt delete mode 100644 webOverlay/overlays/SC_Live Overlay/components/App.js delete mode 100644 webOverlay/overlays/SC_Live Overlay/components/Background.js delete mode 100644 webOverlay/overlays/SC_Live Overlay/components/LineChart.js delete mode 100644 webOverlay/overlays/SC_Live Overlay/index.html delete mode 100644 webOverlay/overlays/SC_Live Overlay/main.css delete mode 100644 webOverlay/overlays/SC_Live Overlay/main.js delete mode 100644 webOverlay/overlays/SC_Map Example/README - DON'T EDIT THIS OVERLAY.txt delete mode 100644 webOverlay/overlays/SC_Map Example/components/App.js delete mode 100644 webOverlay/overlays/SC_Map Example/components/Background.js delete mode 100644 webOverlay/overlays/SC_Map Example/index.html delete mode 100644 webOverlay/overlays/SC_Map Example/main.css delete mode 100644 webOverlay/overlays/SC_Map Example/main.js delete mode 100644 webOverlay/overlays/SC_Map Overlay/README - DON'T EDIT THIS OVERLAY.txt delete mode 100644 webOverlay/overlays/SC_Map Overlay/components/App.js delete mode 100644 webOverlay/overlays/SC_Map Overlay/components/Background.js delete mode 100644 webOverlay/overlays/SC_Map Overlay/index.html delete mode 100644 webOverlay/overlays/SC_Map Overlay/main.css delete mode 100644 webOverlay/overlays/SC_Map Overlay/main.js delete mode 100644 webOverlay/overlays/SC_Map Overlay/orginal file/app.svelte delete mode 100644 webOverlay/overlays/SC_PP Counter/README - DON'T EDIT THIS OVERLAY.txt delete mode 100644 webOverlay/overlays/SC_PP Counter/components/App.js delete mode 100644 webOverlay/overlays/SC_PP Counter/components/Background.js delete mode 100644 webOverlay/overlays/SC_PP Counter/index.html delete mode 100644 webOverlay/overlays/SC_PP Counter/main.css delete mode 100644 webOverlay/overlays/SC_PP Counter/main.js delete mode 100644 webOverlay/overlays/SC_Template/README - DON'T EDIT THIS OVERLAY.txt delete mode 100644 webOverlay/overlays/SC_Template/components/App.js delete mode 100644 webOverlay/overlays/SC_Template/index.html delete mode 100644 webOverlay/overlays/SC_Template/main.css delete mode 100644 webOverlay/overlays/SC_Template/main.js delete mode 100644 webOverlay/overlays/SC_Token/README - DON'T EDIT THIS OVERLAY.txt delete mode 100644 webOverlay/overlays/SC_Token/components/App.js delete mode 100644 webOverlay/overlays/SC_Token/index.html delete mode 100644 webOverlay/overlays/SC_Token/main.css delete mode 100644 webOverlay/overlays/SC_Token/main.js delete mode 100644 webOverlay/overlays/SC_URBar/README - DON'T EDIT THIS OVERLAY.txt delete mode 100644 webOverlay/overlays/SC_URBar/components/App.js delete mode 100644 webOverlay/overlays/SC_URBar/components/roundURBar.js delete mode 100644 webOverlay/overlays/SC_URBar/index.html delete mode 100644 webOverlay/overlays/SC_URBar/main.css delete mode 100644 webOverlay/overlays/SC_URBar/main.js delete mode 100644 webOverlay/overlays/SC_bg/README - DON'T EDIT THIS OVERLAY.txt delete mode 100644 webOverlay/overlays/SC_bg/components/App.js delete mode 100644 webOverlay/overlays/SC_bg/components/Background.js delete mode 100644 webOverlay/overlays/SC_bg/index.html delete mode 100644 webOverlay/overlays/SC_bg/main.css delete mode 100644 webOverlay/overlays/SC_bg/main.js delete mode 100644 webOverlay/overlays/static/README.txt delete mode 100644 webOverlay/overlays/static/convert.bat delete mode 100644 webOverlay/overlays/static/fart.exe delete mode 100644 webOverlay/staticLoader.html diff --git a/webOverlay/index.html b/webOverlay/index.html deleted file mode 100644 index f6c6ae11..00000000 --- a/webOverlay/index.html +++ /dev/null @@ -1,125 +0,0 @@ - - - - - - - - - StreamCompanion web overlay - - - - - - - - - -
-
-

This is preview of all installed overlays in StreamCompanion.

-
-
Click on any name to open it in separate page.
-
To edit or create new one navigate to StreamCompanion Files/web/overlays/ folder. Make - sure - to read README inside of example overlays.
-
-
-

{{overlayName}}

-

Loading...

- -
-
-
-

Links:

-
Overlays index
-
List of functional endpoints
-
All tokens output
-
Discord
-
-
- - - - \ No newline at end of file diff --git a/webOverlay/lib/consts.js b/webOverlay/lib/consts.js deleted file mode 100644 index 20da2619..00000000 --- a/webOverlay/lib/consts.js +++ /dev/null @@ -1,103 +0,0 @@ -(()=>{let config = { - scheme: window.location.protocol.slice(0, -1), - host: window.location.hostname, - port: window.location.port, - getUrl: () => `${config.scheme}://${config.host}:${config.port}`, - getWs: () => `ws://${config.host}:${config.port}`, -}; - -let osuStatus = { - Null: 0, - Listening: 1, - Playing: 2, - Watching: 8, - Editing: 16, - ResultsScreen: 32, -}; -let osuStatusFriendly = { - Null: { text: 'Null', value: 0 }, - Listening: { text: 'Listening', value: 1 }, - Playing: { text: 'Playing', value: 2 }, - Watching: { text: 'Watching', value: 8 }, - Editing: { text: 'Editing', value: 16 }, - ResultsScreen: { text: 'ResultsScreen', value: 32 }, -}; - -let rawOsuStatus = { - Unknown: -2, - NotRunning: -1, - MainMenu: 0, - EditingMap: 1, - Playing: 2, - GameShutdownAnimation: 3, - SongSelectEdit: 4, - SongSelect: 5, - ResultsScreen: 7, - GameStartupAnimation: 10, - MultiplayerRooms: 11, - MultiplayerRoom: 12, - MultiplayerSongSelect: 13, - MultiplayerResultsscreen: 14, - OsuDirect: 15, - RankingTagCoop: 17, - RankingTeam: 18, - ProcessingBeatmaps: 19, - Tourney: 22, -}; -let rawOsuStatusFriendly = { - Unknown: { text: 'Unknown', value: -2 }, - NotRunning: { text: 'NotRunning', value: -1 }, - MainMenu: { text: 'Main Menu', value: 0 }, - EditingMap: { text: 'Editing Map', value: 1 }, - Playing: { text: 'Playing', value: 2 }, - //GameShutdownAnimation: { text: 'GameShutdownAnimation', value: 3 }, - SongSelectEdit: { text: 'Editing beatmap', value: 4 }, - SongSelect: { text: 'Selecting song', value: 5 }, - ResultsScreen: { text: 'Results screen', value: 7 }, - //GameStartupAnimation: { text: 'GameStartupAnimation', value: 10 }, - MultiplayerRooms: { text: 'Multiplayer Room selection', value: 11 }, - MultiplayerRoom: { text: 'Multiplayer lobby', value: 12 }, - MultiplayerSongSelect: { text: 'Multiplayer song selection', value: 13 }, - MultiplayerResultsscreen: { text: 'Multiplayer results screen', value: 14 }, - OsuDirect: { text: 'OsuDirect', value: 15 }, - RankingTagCoop: { text: 'Multiplayer TagCoop results screen', value: 17 }, - RankingTeam: { text: 'Multiplayer Teams results screen', value: 18 }, - ProcessingBeatmaps: { text: 'Processing beatmaps', value: 19 }, - Tourney: { text: 'Tourney manager', value: 22 }, -}; - -let osuGrade = { - 0: 'SSH', - 1: 'SH', - 2: 'SS', - 3: 'S', - 4: 'A', - 5: 'B', - 6: 'C', - 7: 'D', - 8: 'F', - 9: '', -}; - -let scoresType = { - 0: 'Local', - 1: 'Top', - 2: 'Selected mods', - 3: 'Friends', - 4: 'Country', - 10: '', //Unknown -}; - -window.overlay = { - osuStatus, - osuStatusFriendly, - rawOsuStatus, - rawOsuStatusFriendly, - osuGrade, - scoresType, - config, -}; - -})(); - - diff --git a/webOverlay/lib/reconnecting-websocket.js b/webOverlay/lib/reconnecting-websocket.js deleted file mode 100644 index a701afed..00000000 --- a/webOverlay/lib/reconnecting-websocket.js +++ /dev/null @@ -1,365 +0,0 @@ -// MIT License: -// -// Copyright (c) 2010-2012, Joe Walnes -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -/** - * This behaves like a WebSocket in every way, except if it fails to connect, - * or it gets disconnected, it will repeatedly poll until it successfully connects - * again. - * - * It is API compatible, so when you have: - * ws = new WebSocket('ws://....'); - * you can replace with: - * ws = new ReconnectingWebSocket('ws://....'); - * - * The event stream will typically look like: - * onconnecting - * onopen - * onmessage - * onmessage - * onclose // lost connection - * onconnecting - * onopen // sometime later... - * onmessage - * onmessage - * etc... - * - * It is API compatible with the standard WebSocket API, apart from the following members: - * - * - `bufferedAmount` - * - `extensions` - * - `binaryType` - * - * Latest version: https://github.com/joewalnes/reconnecting-websocket/ - * - Joe Walnes - * - * Syntax - * ====== - * var socket = new ReconnectingWebSocket(url, protocols, options); - * - * Parameters - * ========== - * url - The url you are connecting to. - * protocols - Optional string or array of protocols. - * options - See below - * - * Options - * ======= - * Options can either be passed upon instantiation or set after instantiation: - * - * var socket = new ReconnectingWebSocket(url, null, { debug: true, reconnectInterval: 4000 }); - * - * or - * - * var socket = new ReconnectingWebSocket(url); - * socket.debug = true; - * socket.reconnectInterval = 4000; - * - * debug - * - Whether this instance should log debug messages. Accepts true or false. Default: false. - * - * automaticOpen - * - Whether or not the websocket should attempt to connect immediately upon instantiation. The socket can be manually opened or closed at any time using ws.open() and ws.close(). - * - * reconnectInterval - * - The number of milliseconds to delay before attempting to reconnect. Accepts integer. Default: 1000. - * - * maxReconnectInterval - * - The maximum number of milliseconds to delay a reconnection attempt. Accepts integer. Default: 30000. - * - * reconnectDecay - * - The rate of increase of the reconnect delay. Allows reconnect attempts to back off when problems persist. Accepts integer or float. Default: 1.5. - * - * timeoutInterval - * - The maximum time in milliseconds to wait for a connection to succeed before closing and retrying. Accepts integer. Default: 2000. - * - */ -(function (global, factory) { - if (typeof define === 'function' && define.amd) { - define([], factory); - } else if (typeof module !== 'undefined' && module.exports){ - module.exports = factory(); - } else { - global.ReconnectingWebSocket = factory(); - } -})(this, function () { - - if (!('WebSocket' in window)) { - return; - } - - function ReconnectingWebSocket(url, protocols, options) { - - // Default settings - var settings = { - - /** Whether this instance should log debug messages. */ - debug: false, - - /** Whether or not the websocket should attempt to connect immediately upon instantiation. */ - automaticOpen: true, - - /** The number of milliseconds to delay before attempting to reconnect. */ - reconnectInterval: 1000, - /** The maximum number of milliseconds to delay a reconnection attempt. */ - maxReconnectInterval: 30000, - /** The rate of increase of the reconnect delay. Allows reconnect attempts to back off when problems persist. */ - reconnectDecay: 1.5, - - /** The maximum time in milliseconds to wait for a connection to succeed before closing and retrying. */ - timeoutInterval: 2000, - - /** The maximum number of reconnection attempts to make. Unlimited if null. */ - maxReconnectAttempts: null, - - /** The binary type, possible values 'blob' or 'arraybuffer', default 'blob'. */ - binaryType: 'blob' - } - if (!options) { options = {}; } - - // Overwrite and define settings with options if they exist. - for (var key in settings) { - if (typeof options[key] !== 'undefined') { - this[key] = options[key]; - } else { - this[key] = settings[key]; - } - } - - // These should be treated as read-only properties - - /** The URL as resolved by the constructor. This is always an absolute URL. Read only. */ - this.url = url; - - /** The number of attempted reconnects since starting, or the last successful connection. Read only. */ - this.reconnectAttempts = 0; - - /** - * The current state of the connection. - * Can be one of: WebSocket.CONNECTING, WebSocket.OPEN, WebSocket.CLOSING, WebSocket.CLOSED - * Read only. - */ - this.readyState = WebSocket.CONNECTING; - - /** - * A string indicating the name of the sub-protocol the server selected; this will be one of - * the strings specified in the protocols parameter when creating the WebSocket object. - * Read only. - */ - this.protocol = null; - - // Private state variables - - var self = this; - var ws; - var forcedClose = false; - var timedOut = false; - var eventTarget = document.createElement('div'); - - // Wire up "on*" properties as event handlers - - eventTarget.addEventListener('open', function(event) { self.onopen(event); }); - eventTarget.addEventListener('close', function(event) { self.onclose(event); }); - eventTarget.addEventListener('connecting', function(event) { self.onconnecting(event); }); - eventTarget.addEventListener('message', function(event) { self.onmessage(event); }); - eventTarget.addEventListener('error', function(event) { self.onerror(event); }); - - // Expose the API required by EventTarget - - this.addEventListener = eventTarget.addEventListener.bind(eventTarget); - this.removeEventListener = eventTarget.removeEventListener.bind(eventTarget); - this.dispatchEvent = eventTarget.dispatchEvent.bind(eventTarget); - - /** - * This function generates an event that is compatible with standard - * compliant browsers and IE9 - IE11 - * - * This will prevent the error: - * Object doesn't support this action - * - * http://stackoverflow.com/questions/19345392/why-arent-my-parameters-getting-passed-through-to-a-dispatched-event/19345563#19345563 - * @param s String The name that the event should use - * @param args Object an optional object that the event will use - */ - function generateEvent(s, args) { - var evt = document.createEvent("CustomEvent"); - evt.initCustomEvent(s, false, false, args); - return evt; - }; - - this.open = function (reconnectAttempt) { - ws = new WebSocket(self.url, protocols || []); - ws.binaryType = this.binaryType; - - if (reconnectAttempt) { - if (this.maxReconnectAttempts && this.reconnectAttempts > this.maxReconnectAttempts) { - return; - } - } else { - eventTarget.dispatchEvent(generateEvent('connecting')); - this.reconnectAttempts = 0; - } - - if (self.debug || ReconnectingWebSocket.debugAll) { - console.debug('ReconnectingWebSocket', 'attempt-connect', self.url); - } - - var localWs = ws; - var timeout = setTimeout(function() { - if (self.debug || ReconnectingWebSocket.debugAll) { - console.debug('ReconnectingWebSocket', 'connection-timeout', self.url); - } - timedOut = true; - localWs.close(); - timedOut = false; - }, self.timeoutInterval); - - ws.onopen = function(event) { - clearTimeout(timeout); - if (self.debug || ReconnectingWebSocket.debugAll) { - console.debug('ReconnectingWebSocket', 'onopen', self.url); - } - self.protocol = ws.protocol; - self.readyState = WebSocket.OPEN; - self.reconnectAttempts = 0; - var e = generateEvent('open'); - e.isReconnect = reconnectAttempt; - reconnectAttempt = false; - eventTarget.dispatchEvent(e); - }; - - ws.onclose = function(event) { - clearTimeout(timeout); - ws = null; - if (forcedClose) { - self.readyState = WebSocket.CLOSED; - eventTarget.dispatchEvent(generateEvent('close')); - } else { - self.readyState = WebSocket.CONNECTING; - var e = generateEvent('connecting'); - e.code = event.code; - e.reason = event.reason; - e.wasClean = event.wasClean; - eventTarget.dispatchEvent(e); - if (!reconnectAttempt && !timedOut) { - if (self.debug || ReconnectingWebSocket.debugAll) { - console.debug('ReconnectingWebSocket', 'onclose', self.url); - } - eventTarget.dispatchEvent(generateEvent('close')); - } - - var timeout = self.reconnectInterval * Math.pow(self.reconnectDecay, self.reconnectAttempts); - setTimeout(function() { - self.reconnectAttempts++; - self.open(true); - }, timeout > self.maxReconnectInterval ? self.maxReconnectInterval : timeout); - } - }; - ws.onmessage = function(event) { - if (self.debug || ReconnectingWebSocket.debugAll) { - console.debug('ReconnectingWebSocket', 'onmessage', self.url, event.data); - } - var e = generateEvent('message'); - e.data = event.data; - eventTarget.dispatchEvent(e); - }; - ws.onerror = function(event) { - if (self.debug || ReconnectingWebSocket.debugAll) { - console.debug('ReconnectingWebSocket', 'onerror', self.url, event); - } - eventTarget.dispatchEvent(generateEvent('error')); - }; - } - - // Whether or not to create a websocket upon instantiation - if (this.automaticOpen == true) { - this.open(false); - } - - /** - * Transmits data to the server over the WebSocket connection. - * - * @param data a text string, ArrayBuffer or Blob to send to the server. - */ - this.send = function(data) { - if (ws) { - if (self.debug || ReconnectingWebSocket.debugAll) { - console.debug('ReconnectingWebSocket', 'send', self.url, data); - } - return ws.send(data); - } else { - throw 'INVALID_STATE_ERR : Pausing to reconnect websocket'; - } - }; - - /** - * Closes the WebSocket connection or connection attempt, if any. - * If the connection is already CLOSED, this method does nothing. - */ - this.close = function(code, reason) { - // Default CLOSE_NORMAL code - if (typeof code == 'undefined') { - code = 1000; - } - forcedClose = true; - if (ws) { - ws.close(code, reason); - } - }; - - /** - * Additional public API method to refresh the connection if still open (close, re-open). - * For example, if the app suspects bad data / missed heart beats, it can try to refresh. - */ - this.refresh = function() { - if (ws) { - ws.close(); - } - }; - } - - /** - * An event listener to be called when the WebSocket connection's readyState changes to OPEN; - * this indicates that the connection is ready to send and receive data. - */ - ReconnectingWebSocket.prototype.onopen = function(event) {}; - /** An event listener to be called when the WebSocket connection's readyState changes to CLOSED. */ - ReconnectingWebSocket.prototype.onclose = function(event) {}; - /** An event listener to be called when a connection begins being attempted. */ - ReconnectingWebSocket.prototype.onconnecting = function(event) {}; - /** An event listener to be called when a message is received from the server. */ - ReconnectingWebSocket.prototype.onmessage = function(event) {}; - /** An event listener to be called when an error occurs. */ - ReconnectingWebSocket.prototype.onerror = function(event) {}; - - /** - * Whether all instances of ReconnectingWebSocket should log debug messages. - * Setting this to true is the equivalent of setting all instances of ReconnectingWebSocket.debug to true. - */ - ReconnectingWebSocket.debugAll = false; - - ReconnectingWebSocket.CONNECTING = WebSocket.CONNECTING; - ReconnectingWebSocket.OPEN = WebSocket.OPEN; - ReconnectingWebSocket.CLOSING = WebSocket.CLOSING; - ReconnectingWebSocket.CLOSED = WebSocket.CLOSED; - - return ReconnectingWebSocket; -}); \ No newline at end of file diff --git a/webOverlay/lib/tokenTransformer.js b/webOverlay/lib/tokenTransformer.js deleted file mode 100644 index fa6ece3c..00000000 --- a/webOverlay/lib/tokenTransformer.js +++ /dev/null @@ -1,302 +0,0 @@ -function transformTokens(tokens) { - const t = tokens; - return { - settings: { - showInterface: t['ingameInterfaceIsEnabled'] || 0, - }, - menu: { - state: t['rawStatus'], - skinFolder: t['skin'], - gameMode: t['gameMode'], - isChatEnabled: t['chatIsEnabled'], - bm: { - time: { - firstObj: t['firstHitObjectTime'], - current: t['time'] * 1000, - full: t['totaltime'], - mp3: t['totaltime'], - }, - id: t['mapid'], - set: t['mapsetid'], - md5: t['md5'], - rankedStatus: t['rankedStatus'], - metadata: { - artist: t['artistRoman'], - title: t['titleRoman'], - mapper: t['creator'], - difficulty: t['diffName'], - }, - stats: { - AR: t['mAR'], - CS: t['mCS'], - OD: t['mOD'], - HP: t['mHP'], - SR: t['liveStarRating'], - BPM: { - min: t['minBpm'], - max: t['maxBpm'], - }, - fullSR: t['mStars'], - memoryAR: t['AR'], - memoryCS: t['CS'], - memoryOD: t['OD'], - memoryHP: t['HP'], - }, - path: { - full: `${t['dir']}\\${t['backgroundImageFileName']}`, - folder: t['dir'], - file: t['osuFileName'], - bg: t['backgroundImageFileName'], - audio: t['mp3Name'], - }, - }, - mods: { - num: t['modsEnum'], - str: t['mods'].replace(/,/g, ''), - }, - pp: { - 100: t['osu_mSSPP'], - 99: t['osu_m99PP'], - 98: t['osu_m98PP'], - 97: t['osu_m97PP'], - 96: t['osu_m96PP'], - 95: t['osu_m95PP'], - strains: t['mapStrains'], - }, - }, - gameplay: { - gameMode: t['gameMode'], - name: t['username'], - score: t['score'], - accuracy: t['acc'], - combo: { - current: t['combo'], - max: t['currentMaxCombo'], - }, - hp: { - normal: t['playerHP'], - smooth: t['playerHP'], - }, - hits: { - 300: t['c300'], - geki: t['geki'], - 100: t['c100'], - katu: t['katsu'], - 50: t['c50'], - 0: t['miss'], - sliderBreaks: t['sliderBreaks'], - grade: { - current: window.overlay.osuGrade[t['grade']], - maxThisPlay: 'A', //TODO: ? - }, - unstableRate: t['unstableRate'], - hitErrorArray: t['hitErrors'], - }, - pp: { - current: t['ppIfMapEndsNow'], - fc: t['noChokePp'], - maxThisPlay: t['ppIfRestFced'], - }, - rawKeyOverlay: t['keyOverlay'], - cachedKeyOverlay: null, - get keyOverlay() { - return this.cachedKeyOverlay !== null ? this.cachedKeyOverlay : (this.cachedKeyOverlay = convertSCKeyOverlay(this.rawKeyOverlay)); - }, - rawLeaderboard: t['leaderBoardPlayers'], - rawLeaderboardMainPlayer: t['leaderBoardMainPlayer'], - cachedLeaderboard: null, - get leaderboard() { - return this.cachedLeaderboard !== null - ? this.cachedLeaderboard - : (this.cachedLeaderboard = convertSCLeaderBoard(this.rawLeaderboard, this.rawLeaderboardMainPlayer)); - }, - resultsScreen: { - 300: t['c300'], - 100: t['c100'], - 50: t['c50'], - 0: t['miss'], - geki: t['geki'], - katu: t['katsu'], - name: t['username'], - score: t['score'], - maxCombo: t['combo'], - mods: { - num: t['modsEnum'], - str: t['mods'].replace(/,/g, ''), - }, - }, - //TODO: tourney will have to be done at some other time - tourney: { - manager: { - ipcState: 0, - bestOF: 0, - teamName: { - left: '', - right: '', - }, - stars: { - left: 0, - right: 0, - }, - bools: { - scoreVisible: false, - starsVisible: false, - }, - chat: null, - gameplay: { - score: { - left: 0, - right: 0, - }, - }, - }, - ipcClients: null, - }, - }, - }; -} - -function convertSCKeyOverlay(rawKeyOverlay) { - let keys = JSON.parse(rawKeyOverlay || '{}'); - - return { - k1: { - isPressed: keys.K1Pressed, - count: keys.K1Count, - }, - k2: { - isPressed: keys.K2Pressed, - count: keys.K2Count, - }, - m1: { - isPressed: keys.M1Pressed, - count: keys.M1Count, - }, - m2: { - isPressed: keys.M2Pressed, - count: keys.M2Count, - }, - }; -} - -function convertSCLeaderBoard(rawPlayers, rawMainPlayer) { - let players = JSON.parse(rawPlayers || '[]'); - let mainPlayer = JSON.parse(rawMainPlayer || '{}'); - - return { - hasLeaderboard: players.length > 0, - isVisible: mainPlayer.IsLeaderboardVisible || false, - ourplayer: convertSCPlayerSlot(mainPlayer), - slots: players.map((p) => convertSCPlayerSlot(p)), - }; -} - -function convertSCPlayerSlot(player) { - return { - name: player.Username, - score: player.Score, - combo: player.Combo, - maxCombo: player.MaxCombo, - mods: player.Mods ? player.Mods.Value : 0, //TODO: this should be returning mod string instead of enum - h300: player.Hit300, - h100: player.Hit100, - h50: player.Hit50, - h0: player.HitMiss, - team: player.Team, - position: player.Position, - isPassing: player.IsPassing, - }; -} - -function CreateProxiedReconnectingWebSocket(url) { - const tokensCache = {}; - - let proxy = { - //onopen, - //onclose, - //onerror, - //onmessage, - }; - const tokenNames = [ - 'acc', - 'AR', - 'artistRoman', - 'backgroundImageFileName', - 'c100', - 'c300', - 'c50', - 'chatIsEnabled', - 'combo', - 'creator', - 'CS', - 'currentMaxCombo', - 'diffName', - 'dir', - 'firstHitObjectTime', - 'gameMode', - 'geki', - 'grade', - 'hitErrors', - 'HP', - 'ingameInterfaceIsEnabled', - 'katsu', - 'keyOverlay', - 'leaderBoardMainPlayer', - 'leaderBoardPlayers', - 'liveStarRating', - 'mapid', - 'mapsetid', - 'mapStrains', - 'mAR', - 'maxBpm', - 'mCS', - 'md5', - 'mHP', - 'minBpm', - 'miss', - 'mOD', - 'mods', - 'modsEnum', - 'mp3Name', - 'mStars', - 'noChokePp', - 'OD', - 'osu_m95PP', - 'osu_m96PP', - 'osu_m97PP', - 'osu_m98PP', - 'osu_m99PP', - 'osu_mSSPP', - 'osuFileName', - 'playerHP', - 'ppIfMapEndsNow', - 'ppIfRestFced', - 'rankedStatus', - 'rawStatus', - 'score', - 'skin', - 'sliderBreaks', - 'time', - 'titleRoman', - 'totaltime', - 'unstableRate', - 'username', - ]; - - let rws = watchTokens(tokenNames, (values) => { - Object.assign(tokensCache, values); - proxy.onmessage({ data: transformTokens(tokensCache) }); - }); - - let origOnOpen = rws.onopen; - - rws.onopen = (ev) => { - origOnOpen(ev); - proxy.onopen(ev); - }; - rws.onclose = (ev) => proxy.onclose(ev); - rws.onerror = (ev) => proxy.onerror(ev); - //rws.onmessage = (ev) => proxy.onmessage(ev); - - return proxy; -} diff --git a/webOverlay/lib/utils.js b/webOverlay/lib/utils.js deleted file mode 100644 index 38e21242..00000000 --- a/webOverlay/lib/utils.js +++ /dev/null @@ -1,82 +0,0 @@ -Number.prototype.pad = function (size) { - var s = String(this); - while (s.length < (size || 2)) { s = "0" + s; } - return s; -} -Number.prototype.clamp = function(min, max) { - return Math.min(Math.max(this, min), max); - }; - -function mergeObjects(vueThis, target, source) { - for (const [key, value] of Object.entries(source)) { - if (target.hasOwnProperty(key)) - target[key] = value; - else - vueThis.$set(target, key, value); - } -} -function preloadImage(url, id, cb) { - let img = new Image(); - img.onload = () => cb(url, id); - img.src = url; -} - -function watchTokens(tokenList, onTokensUpdated) { - let rws = new ReconnectingWebSocket(`${window.overlay.config.getWs()}/tokens`, null, { - automaticOpen: false, - reconnectInterval: 3000 - }); - rws.watchedTokens = tokenList; - - rws.onopen = () => { - rws.send(JSON.stringify(rws.watchedTokens)) - }; - rws.onmessage = (eventData) => { - onTokensUpdated(JSON.parse(eventData.data)); - }; - - rws.AddTokens = (tokens) => { - rws.watchedTokens = [...new Set([...rws.watchedTokens, ...tokens])]; - if (rws.readyState === 1) - rws.send(JSON.stringify(rws.watchedTokens)) - } - rws.open(); - return rws; -} - -function watchTokensVue(tokenList, vueThis) { - return watchTokens(tokenList, (tokens) => { - mergeObjects(vueThis, vueThis.tokens, tokens); - }); -} -function _GetToken(rws, tokens, tokenName, decimalPlaces) { - tokens[tokenName];//hack to inform vue3 that we are dependant on tokens object values - if (tokens.hasOwnProperty(tokenName)) { - if (decimalPlaces !== undefined && decimalPlaces !== null) - return Number(tokens[tokenName]).toFixed(decimalPlaces); - return tokens[tokenName]; - } - if (rws.watchedTokens.indexOf(tokenName) === -1) - rws.AddTokens([tokenName]); - return ''; -} - -function _GetWebOverlaySettings() { - return fetch(`${window.overlay.config.getUrl()}/settings`) - .then((response) => response.json()) - .then((responseData) => JSON.parse(responseData.WebOverlay_Config)); -} - -function _IsInStatus(rws, tokens, osuStatuses) { - if (Array.isArray(osuStatuses)) - return osuStatuses.indexOf(_GetToken(rws, tokens, 'status')) > -1; - - return _GetToken(rws, tokens, 'status') == osuStatuses -} - -function _IsPlaying(rws, tokens) { - return _IsInStatus(rws, tokens, [window.overlay.osuStatus.Playing, window.overlay.osuStatus.ResultsScreen]); -} -function _IsWatching(rws, tokens) { - return _IsInStatus(rws, tokens, window.overlay.osuStatus.Watching); -} \ No newline at end of file diff --git a/webOverlay/overlays/README.txt b/webOverlay/overlays/README.txt deleted file mode 100644 index 164cc8af..00000000 --- a/webOverlay/overlays/README.txt +++ /dev/null @@ -1,7 +0,0 @@ -================= -Any edits to files in example overlays(folders starting with SC_) -provided with StreamCompanion WILL BE OVERWRITTEN or even removed in future StreamCompanion update. -================= - -The overlays itself can be modified as you want, just not in original folders. -Copy everything to a separate folder, remove SC_ from the name, and work from there. \ No newline at end of file diff --git a/webOverlay/overlays/SC_BeatOsu/README - DON'T EDIT THIS OVERLAY.txt b/webOverlay/overlays/SC_BeatOsu/README - DON'T EDIT THIS OVERLAY.txt deleted file mode 100644 index 0db05a7d..00000000 --- a/webOverlay/overlays/SC_BeatOsu/README - DON'T EDIT THIS OVERLAY.txt +++ /dev/null @@ -1,5 +0,0 @@ -================= -Any edits to files in Example overlays provided with StreamCompanion WILL BE OVERWRITTEN or even removed in future StreamCompanion update. -================= - -The overlay itself can be modified as you want, just not in this folder. Copy everything to a separate folder one directory up, and work from there. \ No newline at end of file diff --git a/webOverlay/overlays/SC_BeatOsu/components/App.js b/webOverlay/overlays/SC_BeatOsu/components/App.js deleted file mode 100644 index d6f07685..00000000 --- a/webOverlay/overlays/SC_BeatOsu/components/App.js +++ /dev/null @@ -1,47 +0,0 @@ -import background from './Background.js'; - -const app = { - name: 'App', - components: { - Background: background, - }, - setup(props, context) { - const data = Vue.reactive({ - tokens: {}, - rws: {}, - }); - - const getToken = (tokenName, decimalPlaces) => _GetToken(data.rws, data.tokens, tokenName, decimalPlaces); - let isMania = Vue.computed(() => getToken('gameMode') === 'OsuMania'); - let isPlayingOrWatching = Vue.computed(() => - _IsInStatus(data.rws, data.tokens, [window.overlay.osuStatus.Playing, window.overlay.osuStatus.ResultsScreen, window.overlay.osuStatus.Watching]) - ); - - data.rws = watchTokens([], (values) => { - Object.assign(data.tokens, values); - }); - - let mapTime = Vue.computed(() => { - let time = getToken('time') * 1000; - return Math.floor(time / 1000 / 60).pad() + ':' + Math.floor((time / 1000) % 60).pad(); - }); - - let mapTimePercent = Vue.computed(() => ((getToken('time') / (getToken('totaltime') / 1000)) * 100).clamp(0, 100)); - - const radius = 30; - const circumference = radius * Math.PI * 2; - let progressStyle = Vue.computed(() => `stroke-dashoffset: ${(1 - mapTimePercent.value / 100) * circumference}px`); - - return { - getToken, - isPlayingOrWatching, - isMania, - mapTime, - mapTimePercent, - progressStyle, - osuGrade: window.overlay.osuGrade, - }; - }, -}; - -export default app; diff --git a/webOverlay/overlays/SC_BeatOsu/components/Background.js b/webOverlay/overlays/SC_BeatOsu/components/Background.js deleted file mode 100644 index 18517b41..00000000 --- a/webOverlay/overlays/SC_BeatOsu/components/Background.js +++ /dev/null @@ -1,54 +0,0 @@ -const background = { - name: 'backgroundContainer', - template: ` -
- -
- `, - setup(props, context) { - const data = Vue.reactive({ - tokens: { backgroundImageLocation: '', md5: '', mapsetid: '' }, - backgroundUrl: '', - backgroundId: Number.MIN_SAFE_INTEGER, - rws: {}, - }); - const backgroundDiv = Vue.ref(null); - const boxStyle = Vue.computed(() => `background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0.1), rgba(0, 0, 0, 0.6)),url(${data.backgroundUrl});`); - - Vue.watch( - () => data.tokens.backgroundImageLocation, - () => { - let currId = (data.backgroundId += 1); - - let width = 1920, - height = 1080; - if (backgroundDiv.value) { - if (backgroundDiv.value.scrollWidth > 10) width = backgroundDiv.value.scrollWidth; - if (backgroundDiv.value.scrollHeight > 10) height = backgroundDiv.value.scrollHeight; - } - - preloadImage( - `${window.overlay.config.getUrl()}/backgroundImage?width=${width}&height=${height}&mapset=${data.tokens.mapsetid}&dummyData=${encodeURIComponent( - data.tokens.md5 - )}&crop=1`, - currId, - (url, id) => { - if (data.backgroundId !== id) return; - data.backgroundUrl = url; - } - ); - } - ); - Vue.onMounted(() => { - console.log(backgroundDiv.value); - }); - data.rws = watchTokens(['backgroundImageLocation', 'md5', 'mapsetid'], (values) => Object.assign(data.tokens, values)); - - return { - backgroundDiv, - boxStyle, - }; - }, -}; - -export default background; diff --git a/webOverlay/overlays/SC_BeatOsu/index.html b/webOverlay/overlays/SC_BeatOsu/index.html deleted file mode 100644 index 649ce3e8..00000000 --- a/webOverlay/overlays/SC_BeatOsu/index.html +++ /dev/null @@ -1,74 +0,0 @@ - - - - - - pp Display Example - - - - - - - - - - - - - - -
-
-
-
- {{osuGrade[getToken('grade')]}} {{getToken('acc',2)}}% -
- -
- {{getToken('combo')}} Combo -
-
- - {{getToken('ppIfMapEndsNow',0)}}pp/{{getToken('ppIfRestFced',0)}}pp -
-
- -
-
- - - - - - - - -
- {{mapTime}} -
-
- -
-
-
- {{getToken('titleUnicode')}} - {{getToken('creator')}} -
- - {{getToken('artistUnicode')}} -
- -
- {{getToken('diffName')}} - {{getToken('mMainBpm')}} BPM - {{getToken('mods')}} -
-
-
- -
-
- - - diff --git a/webOverlay/overlays/SC_BeatOsu/main.css b/webOverlay/overlays/SC_BeatOsu/main.css deleted file mode 100644 index f5014544..00000000 --- a/webOverlay/overlays/SC_BeatOsu/main.css +++ /dev/null @@ -1,226 +0,0 @@ -body { - font-family: "Roboto Mono","Montserrat", sans-serif; - - color: white; - /* background: black; */ - - margin: 0; - - display: flex; - flex-direction: column; -} - -.overlay { - display: flex; - flex-direction: column; - - position: absolute; - left: 40px; - bottom: 40px; -} - -/* Beatmap */ - -.beatmap { - display: flex; -} - -.cover { - overflow: hidden; - border-radius: 6px; - position: relative; -} - -.image { - width: 90px; - height: 90px; -} - -.meta { - display: flex; - flex-direction: column; - - flex-grow: 1; - padding: 0 16px; -} - -.text { - flex-grow: 1; - - /* Fix text offset */ - transform: translate(0, -5px); -} - -.titles { - display: flex; - align-items: flex-end; -} - -.title { - font-size: 24px; - font-weight: 700; -} - -.subtitle { - font-size: 14px; - font-weight: 600; - margin: 0 4px 2px 4px; -} - -.artist { - display: block; - font-size: 16px; - font-weight: 400; - margin: 2px 0 0 0; -} - -.difficulty, .bpm, .mods, .ppIfRestFced{ - display: inline-block; - - font-size: 10px; - font-weight: 800; - text-transform: uppercase; - letter-spacing: 3px; -} - -.difficulty { - padding: 4px 5px 4px 8px; - - color: black; - background: white; - border-radius: 4px; -} - -.bpm { - margin: 0 8px; -} - -.mods { - margin: 0 0px; -} - -/* Progress */ - -.cover svg { - transform: rotate(-90deg); -} -.cover{ - - width: 90px; - height: 90px; -} -.cover div { - display: flex; - align-items: center; - justify-content: center; - - width: 90px; - height: 90px; -} - -.cover svg, .cover div { - position: absolute; - top: 0; - left: 0; -} - -.darken { - fill: black; - opacity: 0.5; -} - -.remaining, .progress { - fill: transparent; - stroke: white; - stroke-width: 4px; -} - -.remaining { - opacity: 0.25; -} - -.progress { - stroke-dasharray: 188.495px, 188.495px; - stroke-dashoffset: 188.495px; -} - -.progress-text { - font-size: 16px; - font-weight: 600; -} - -/* Performance */ - -.performance { - display: flex; - flex-direction: column; - margin: 0 0 20px 0; -} - -.performance-group { - margin: 4px 0 0 0; -} - -.performance-group .text { - display: inline-block; - - font-size: 22px; - font-weight: 600; -} - -.performance-group .subtext { - display: inline-block; - - font-size: 14px; - font-weight: 600; - letter-spacing: 2px; - text-transform: uppercase; - - opacity: 0.75; -} - -.score { - display: block; - font-size: 34px; - font-weight: 700; - letter-spacing: 2px; -} - -/* Animations and state */ - -.overlay { - --show: cubic-bezier(0.19, 1, 0.22, 1) 300ms; - --hide: cubic-bezier(0.55, 0.085, 0.68, 0.53) 200ms; -} - -.beatmap, .performance > * { - transition: - opacity var(--show), - transform var(--show); -} - -.overlay.hidden .beatmap, .overlay.hidden .performance > * { - opacity: 0; - transform: translate(0, 15px); - transition: - opacity var(--hide), - transform var(--hide); -} - -.performance > *:nth-child(3) { - transition-delay: 100ms !important; -} - -.overlay .performance > *:nth-child(2) { - transition-delay: 200ms !important; -} - -.overlay .performance > *:nth-child(1) { - transition-delay: 300ms !important; -} - -[v-cloak] { display: none; } - -.hide { - display: none; -} \ No newline at end of file diff --git a/webOverlay/overlays/SC_BeatOsu/main.js b/webOverlay/overlays/SC_BeatOsu/main.js deleted file mode 100644 index f9685ccb..00000000 --- a/webOverlay/overlays/SC_BeatOsu/main.js +++ /dev/null @@ -1,7 +0,0 @@ -import App from './components/App.js'; - -let app = Vue.createApp({ - ...App, -}); - -app.mount('#overlay'); diff --git a/webOverlay/overlays/SC_Live Overlay/README - DON'T EDIT THIS OVERLAY.txt b/webOverlay/overlays/SC_Live Overlay/README - DON'T EDIT THIS OVERLAY.txt deleted file mode 100644 index 0db05a7d..00000000 --- a/webOverlay/overlays/SC_Live Overlay/README - DON'T EDIT THIS OVERLAY.txt +++ /dev/null @@ -1,5 +0,0 @@ -================= -Any edits to files in Example overlays provided with StreamCompanion WILL BE OVERWRITTEN or even removed in future StreamCompanion update. -================= - -The overlay itself can be modified as you want, just not in this folder. Copy everything to a separate folder one directory up, and work from there. \ No newline at end of file diff --git a/webOverlay/overlays/SC_Live Overlay/components/App.js b/webOverlay/overlays/SC_Live Overlay/components/App.js deleted file mode 100644 index 570d3c3d..00000000 --- a/webOverlay/overlays/SC_Live Overlay/components/App.js +++ /dev/null @@ -1,104 +0,0 @@ -import background from './Background.js'; -import lineChart from './LineChart.js'; - -const app = { - name: 'App', - components: { - Background: background, - Linechart: lineChart, - }, - - setup(props, context) { - const data = Vue.reactive({ - tokens: {}, - rws: {}, - settings: {}, - }); - - const getToken = (tokenName, decimalPlaces) => _GetToken(data.rws, data.tokens, tokenName, decimalPlaces); - //either request all tokens upfront by filling their names in array - //or request them later using helper getToken method above - data.rws = watchTokens(['mapStrains'], (values) => { - Object.assign(data.tokens, values); - }); - - const getWebOverlaySettings = () => - fetch(`${window.overlay.config.getUrl()}/settings`) - .then((response) => response.json()) - .then((responseData) => JSON.parse(responseData.WebOverlay_Config)); - - getWebOverlaySettings().then((config) => { - Object.assign(data.settings, config); - }); - let mapStrains = Vue.computed(() => Object.entries(data.tokens.mapStrains || {})); - let isMania = Vue.computed(() => getToken('gameMode') === 'OsuMania'); - let isPlayingOrWatching = Vue.computed(() => - _IsInStatus(data.rws, data.tokens, [window.overlay.osuStatus.Playing, window.overlay.osuStatus.ResultsScreen, window.overlay.osuStatus.Watching]) - ); - - let ppValue = Vue.computed(() => { - if (isPlayingOrWatching.value) return getToken('ppIfMapEndsNow', 1); - if (data.settings.SimulatePPWhenListening) return getToken('simulatedPp', 1); - return 0; - }); - let mapProgress = Vue.computed(() => getToken('time') / (getToken('totaltime') / 1000)); - - return { - getToken, - - data, - - isPlayingOrWatching, - isMania, - mapStrains, - ppValue, - mapProgress, - }; - }, - computed: { - overlaySettings() { - if (Object.keys(this.data.settings).length === 0) return {}; - let s = this.data.settings; - - return { - backgroundColor: s.ChartColor, - chartProgressColor: s.ChartProgressColor, - imageDimColor: s.ImageDimColor, - artistTextColor: s.ArtistTextColor, - titleTextColor: s.TitleTextColor, - ppBackgroundColor: s.PpBackgroundColor, - hit100BackgroundColor: s.Hit100BackgroundColor, - hit50BackgroundColor: s.Hit50BackgroundColor, - hitMissBackgroundColor: s.HitMissBackgroundColor, - yAxesFontColor: s.HideChartLegend ? 'transparent' : 'white', - - simulatePPWhenListening: s.SimulatePPWhenListening, - hideDiffText: s.HideDiffText, - hideMapStats: s.HideMapStats, - hideChartLegend: s.HideChartLegend, - - chartHeight: s.ChartHeight, - }; - }, - progressChartSettings() { - return { - backgroundColor: this.overlaySettings.chartProgressColor, - yAxesFontColor: 'transparent', - }; - }, - chartStyle() { - if (Object.keys(this.overlaySettings).length === 0) return `height:200px`; - return `height:${this.overlaySettings.chartHeight}px;`; - }, - progressChartStyle() { - return `clip-path: inset(0px ${100 - this.mapProgress * 100}% 0px 0px);`; - }, - hitsStyle() { - if (!this.overlaySettings.ppBackgroundColor) return ``; - - let { ppBackgroundColor: pp, hit100BackgroundColor: h100, hit50BackgroundColor: h50, hitMissBackgroundColor: hMiss } = this.overlaySettings; - return `background: linear-gradient(to right, ${pp},${pp},${h100},${h100},${h50},${h50},${hMiss},${hMiss});`; - }, - }, -}; -export default app; diff --git a/webOverlay/overlays/SC_Live Overlay/components/Background.js b/webOverlay/overlays/SC_Live Overlay/components/Background.js deleted file mode 100644 index 046d04e9..00000000 --- a/webOverlay/overlays/SC_Live Overlay/components/Background.js +++ /dev/null @@ -1,57 +0,0 @@ -const background = { - name: 'backgroundContainer', - template: ` -
- -
- `, - props: { - dimcolor: {}, - }, - setup(props, context) { - const data = Vue.reactive({ - tokens: { backgroundImageLocation: '', md5: '', mapsetid: '' }, - backgroundUrl: '', - backgroundId: Number.MIN_SAFE_INTEGER, - rws: {}, - }); - const backgroundDiv = Vue.ref(null); - const boxStyle = Vue.computed(() => `background-image: linear-gradient(to bottom, ${props.dimcolor}, ${props.dimcolor}),url(${data.backgroundUrl});`); - - Vue.watch( - () => data.tokens.backgroundImageLocation, - () => { - let currId = (data.backgroundId += 1); - - let width = 1920, - height = 1080; - if (backgroundDiv.value) { - if (backgroundDiv.value.scrollWidth > 10) width = backgroundDiv.value.scrollWidth; - if (backgroundDiv.value.scrollHeight > 10) height = backgroundDiv.value.scrollHeight; - } - - preloadImage( - `${window.overlay.config.getUrl()}/backgroundImage?width=${width}&height=${height}&mapset=${data.tokens.mapsetid}&dummyData=${encodeURIComponent( - data.tokens.md5 - )}&crop=1`, - currId, - (url, id) => { - if (data.backgroundId !== id) return; - data.backgroundUrl = url; - } - ); - } - ); - Vue.onMounted(() => { - console.log(backgroundDiv.value); - }); - data.rws = watchTokens(['backgroundImageLocation', 'md5', 'mapsetid'], (values) => Object.assign(data.tokens, values)); - - return { - backgroundDiv, - boxStyle, - }; - }, -}; - -export default background; diff --git a/webOverlay/overlays/SC_Live Overlay/components/LineChart.js b/webOverlay/overlays/SC_Live Overlay/components/LineChart.js deleted file mode 100644 index fc7de0ef..00000000 --- a/webOverlay/overlays/SC_Live Overlay/components/LineChart.js +++ /dev/null @@ -1,119 +0,0 @@ - -const LineChart = { - name: 'LineChart', - template: ` -
- - -
- `, - props: { - points: {}, - settings: { - default: {} - } - }, - data: () => ({ - chart: {}, - defaultSettings: { - maxTicks: 3, - backgroundColor: 'rgba(255, 99, 132,0.6)', - yAxesFontColor: 'white' - } - }), - methods: { - updateChart() { - this.chart.data.labels = []; - this.chart.data.datasets.forEach((dataset) => { - dataset.data = []; - }); - - this.chart.data.labels = this.points.map(x => x[0]); - let values = this.points.map(x => x[1]) - this.chart.data.datasets.forEach((dataset) => { - dataset.data.push(...values); - - }); - - this.chart.update(); - } - }, - computed: { - - }, - watch: { - points() { - this.updateChart() - }, - settings() { - console.log('settings updated:', JSON.stringify(this.settings)); - let settings = { ...this.defaultSettings, ...this.settings }; - - this.chart.data.datasets[0].backgroundColor = settings.backgroundColor; - this.chart.options.scales.yAxes[0].ticks.fontColor = settings.yAxesFontColor; - - this.chart.update(); - } - - }, - mounted: function () { - let settings = { ...this.settings, ...this.defaultSettings } - var ctx = this.$refs.chart.getContext('2d'); - this.chart = new Chart(ctx, { - type: 'line', - - data: { - labels: ['0', '1', '2', '3'], - datasets: [{ - backgroundColor: settings.backgroundColor, - //borderColor: this.backgroundColor, - data: [0, 10, 20, 30] - }] - }, - - // Configuration options go here - options: { - maintainAspectRatio: false, - responsive: true, - legend: { - display: false - }, - scales: { - xAxes: [{ - ticks: { - display: false - }, - gridLines: { - zeroLineColor: 'transparent', - color: "transparent" - } - }], - yAxes: [{ - ticks: { - beginAtZero: true, - padding: -25, - fontColor: settings.yAxesFontColor, - maxTicksLimit: settings.maxTicks, - - }, - gridLines: { - zeroLineColor: 'transparent', - color: "transparent" - } - }] - }, - elements: { - point: { - radius: 0 - } - }, - //animation: { - // duration: 250 - //} - } - }); - } -} - - -export default LineChart \ No newline at end of file diff --git a/webOverlay/overlays/SC_Live Overlay/index.html b/webOverlay/overlays/SC_Live Overlay/index.html deleted file mode 100644 index fa07efa5..00000000 --- a/webOverlay/overlays/SC_Live Overlay/index.html +++ /dev/null @@ -1,78 +0,0 @@ - - - - - - Live Overlay - - - - - - - - - - - -
- -
-

{{getToken('mapArtistTitle')}}

-
-

mapper {{getToken('creator')}}

-

difficulty {{getToken('diffName')}}

-
-
- -
-
-
-
SR{{getToken('mStars', 2)}}
-
CS{{getToken('mCS')}}
-
AR{{getToken('mAR')}}
-
OD{{getToken('mOD')}}
-
HP{{getToken('mHP')}}
-
- -
-
- -
-
-
-
- -
-
{{ppValue}}pp
-
{{getToken('geki')}}
-
{{getToken('c300')}}
-
{{getToken('katsu')}}
-
-

{{getToken('c100')}}

-
-
-

{{getToken('c50')}}

-
-
-

{{getToken('miss')}}

-
-
-
-
{{ppValue}}pp
-
-

{{getToken('c100')}}

-
-
-

{{getToken('c50')}}

-
-
-

{{getToken('miss')}}

-
-
-
-
-
- - - diff --git a/webOverlay/overlays/SC_Live Overlay/main.css b/webOverlay/overlays/SC_Live Overlay/main.css deleted file mode 100644 index 2a3189b7..00000000 --- a/webOverlay/overlays/SC_Live Overlay/main.css +++ /dev/null @@ -1,229 +0,0 @@ -:root { - --animation-speed: 1.7s -} -* { - padding: 0px; - margin: 0px; - font-family: comfortaa; -} -.clipPathAnimation{ - transition: clip-path .3s; -} -.box { - height: 100%; - - -webkit-box-shadow: inset 0px 0px 28px 4px #0008; - -moz-box-shadow: inset 0px 0px 28px 4px #0008; - box-shadow: inset 0px 0px 28px 4px #0008; - background-repeat: no-repeat; - background-position: center center; - -webkit-background-size: cover; - -moz-background-size: cover; - -o-background-size: cover; - background-size: cover; - transition: padding var(--animation-speed) ease; - overflow-y: hidden; - - display: flex; - flex-direction: column; - align-items: center; -} - -.inner { - display: flex; - flex-direction: column; - filter: drop-shadow(0px 0px 5px #000a); - width: 100%; - margin-top:10px; - z-index: 50; - -} -.right { - text-align: right; - margin-left: auto; -} -.app { - height: 100vh; - white-space: nowrap; - color: white; -} - -.outer { - min-width: 15%; - padding: 0px 2%; - display: flex; - justify-content: center; - flex-direction: column; - font-size: 15px; -} - -.title { - font-size: 20px; - align-items: center; - justify-content: center; - text-align: center; - overflow: hidden; - text-overflow: ellipsis; - transition: font-size var(--animation-speed) ease; - margin: 0 5px; -} - -.mapinfo { - font-size: 12px; - flex-direction: row; - display: flex; - text-align: center; - align-items: center; - justify-content: center; - transition: margin-top var(--animation-speed) ease, - padding var(--animation-speed) ease; -} - -.mapper { - padding-right: 15px; - flex: 0 1 auto; - opacity:1; - transition: flex var(--animation-speed) ease, - padding var(--animation-speed) ease, - opacity var(--animation-speed) ease; -} -.box-playing { - padding-top:2px; -} -.title-playing { - font-size: 12px; - transition: font-size var(--animation-speed) ease; -} -.mapinfo-playing { - padding-bottom: 2px; - - transition: margin var(--animation-speed) ease, - padding var(--animation-speed) ease; -} -.mapinfo-playing > .mapper { - text-align: left; - /*opacity:0;*/ - - padding-left:5px; - transition: flex var(--animation-speed) ease, - padding var(--animation-speed) ease, - opacity var(--animation-speed) ease; -} -.difficulty{ - transition: padding var(--animation-speed) ease; -} -.mapinfo-playing > .difficulty{ - padding-right:5px; - transition: padding var(--animation-speed) ease; -} - -.flexSpacer{ - flex: 1 1 auto; -} - - -.ds { - filter: drop-shadow(0px 0px 5px #0004); -} - -.hit-100 { -} - -.hit-50 { -} - -.hit-miss { -} - -.hit-text { - justify-self: center; -} - -.hit { - align-self: center; - padding: 5px 9px; - font-size: 18px; - margin-right: 10px; - border-radius: 200px; - width:25%; -} - -[v-cloak] { display: none; } - -.hide { - display: none; - z-index: -1; -} - -.bottom { - width: 100%; - display:flex; - flex-direction: row; - -} - - .bottom-content { - z-index: 9999; - } - -.hits { - display: flex; - flex: 1 1 auto; - margin:5px; - padding:5px; - text-align:center; - margin: -5px 5px 5px 5px; - font-weight: 600; -} - -.pp { - align-self: center; - width:25%; -} - -.mapStats{ - border-radius: 15px; - background: rgba(0,0,0,0.4); - padding: 10px; - background-repeat: no-repeat; - background-position: center center; - -webkit-background-size: cover; - -moz-background-size: cover; - -o-background-size: cover; - background-size: cover; - margin-left: auto; - width: 60px; - margin-right:15px; - margin-bottom:25px; - text-align: end; - position: absolute; - right:0; - z-index: 99; - overflow: hidden; -} -.flexEnd{ - display: flex; - flex-direction: column; - justify-content: flex-end; -} - -.mapStats strong{ - float: left; -} - -mapStat{ - float: right; -} - -.chart-container{ - position: relative; - margin-right: 5px; - margin-left: 1px; -} - - -@media screen and (max-height: 180px) { - .mapStats { - display:none; - } - } \ No newline at end of file diff --git a/webOverlay/overlays/SC_Live Overlay/main.js b/webOverlay/overlays/SC_Live Overlay/main.js deleted file mode 100644 index ec61c247..00000000 --- a/webOverlay/overlays/SC_Live Overlay/main.js +++ /dev/null @@ -1,7 +0,0 @@ -import App from './components/App.js'; - -let app = Vue.createApp({ - ...App, -}); - -app.mount('#app'); diff --git a/webOverlay/overlays/SC_Map Example/README - DON'T EDIT THIS OVERLAY.txt b/webOverlay/overlays/SC_Map Example/README - DON'T EDIT THIS OVERLAY.txt deleted file mode 100644 index 0db05a7d..00000000 --- a/webOverlay/overlays/SC_Map Example/README - DON'T EDIT THIS OVERLAY.txt +++ /dev/null @@ -1,5 +0,0 @@ -================= -Any edits to files in Example overlays provided with StreamCompanion WILL BE OVERWRITTEN or even removed in future StreamCompanion update. -================= - -The overlay itself can be modified as you want, just not in this folder. Copy everything to a separate folder one directory up, and work from there. \ No newline at end of file diff --git a/webOverlay/overlays/SC_Map Example/components/App.js b/webOverlay/overlays/SC_Map Example/components/App.js deleted file mode 100644 index 19c49c57..00000000 --- a/webOverlay/overlays/SC_Map Example/components/App.js +++ /dev/null @@ -1,39 +0,0 @@ -import background from './Background.js'; - -const app = { - name: 'App', - components: { - Background: background, - }, - setup(props, context) { - const data = Vue.reactive({ - tokens: {}, - rws: {}, - }); - - const getToken = (tokenName, decimalPlaces) => - _GetToken(data.rws, data.tokens, tokenName, decimalPlaces); - //either request all tokens upfront by filling their names in array - //or request them later using helper getToken method above - data.rws = watchTokens([], (values) => { - Object.assign(data.tokens, values); - }); - - const totalTime = Vue.computed(() => { - let time = getToken('totaltime'); - return ( - Math.floor(time / 1000 / 60).pad() + - ':' + - Math.floor((time / 1000) % 60).pad() - ); - }); - - return { - getToken, - - totalTime, - }; - }, -}; - -export default app; diff --git a/webOverlay/overlays/SC_Map Example/components/Background.js b/webOverlay/overlays/SC_Map Example/components/Background.js deleted file mode 100644 index 18517b41..00000000 --- a/webOverlay/overlays/SC_Map Example/components/Background.js +++ /dev/null @@ -1,54 +0,0 @@ -const background = { - name: 'backgroundContainer', - template: ` -
- -
- `, - setup(props, context) { - const data = Vue.reactive({ - tokens: { backgroundImageLocation: '', md5: '', mapsetid: '' }, - backgroundUrl: '', - backgroundId: Number.MIN_SAFE_INTEGER, - rws: {}, - }); - const backgroundDiv = Vue.ref(null); - const boxStyle = Vue.computed(() => `background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0.1), rgba(0, 0, 0, 0.6)),url(${data.backgroundUrl});`); - - Vue.watch( - () => data.tokens.backgroundImageLocation, - () => { - let currId = (data.backgroundId += 1); - - let width = 1920, - height = 1080; - if (backgroundDiv.value) { - if (backgroundDiv.value.scrollWidth > 10) width = backgroundDiv.value.scrollWidth; - if (backgroundDiv.value.scrollHeight > 10) height = backgroundDiv.value.scrollHeight; - } - - preloadImage( - `${window.overlay.config.getUrl()}/backgroundImage?width=${width}&height=${height}&mapset=${data.tokens.mapsetid}&dummyData=${encodeURIComponent( - data.tokens.md5 - )}&crop=1`, - currId, - (url, id) => { - if (data.backgroundId !== id) return; - data.backgroundUrl = url; - } - ); - } - ); - Vue.onMounted(() => { - console.log(backgroundDiv.value); - }); - data.rws = watchTokens(['backgroundImageLocation', 'md5', 'mapsetid'], (values) => Object.assign(data.tokens, values)); - - return { - backgroundDiv, - boxStyle, - }; - }, -}; - -export default background; diff --git a/webOverlay/overlays/SC_Map Example/index.html b/webOverlay/overlays/SC_Map Example/index.html deleted file mode 100644 index 2043c096..00000000 --- a/webOverlay/overlays/SC_Map Example/index.html +++ /dev/null @@ -1,57 +0,0 @@ - - - - - - - Map Display Example - - - - - - - - - - -
-
-

- length {{totalTime}} -

-

- bpm {{getToken('mBpm')}} -

-
- -
-
-

- {{getToken('mapArtistTitle')}} -

-
-
-

- mapper {{getToken('creator')}} -

-

- difficulty {{getToken('diffName')}} -

-
-
-
-
-

- CS {{getToken('mCS')}} / AR {{getToken('mAR')}} / OD - {{getToken('mOD')}} -

-

- Star Rating {{getToken('mStars', 2)}} -

-
-
- - - - \ No newline at end of file diff --git a/webOverlay/overlays/SC_Map Example/main.css b/webOverlay/overlays/SC_Map Example/main.css deleted file mode 100644 index 619475a1..00000000 --- a/webOverlay/overlays/SC_Map Example/main.css +++ /dev/null @@ -1,85 +0,0 @@ -* { - padding: 0px; - margin: 0px; - font-family: comfortaa; -} - -.app { - min-width: 995px; - white-space: nowrap; -} - -.box { - border-radius: 200px; - -webkit-box-shadow: inset 0px 0px 28px 4px #0008; - -moz-box-shadow: inset 0px 0px 28px 4px #0008; - box-shadow: inset 0px 0px 28px 4px #0008; - padding: 25px; - padding-left: 27px; - background-repeat: no-repeat; - background-position: center center; - -webkit-background-size: cover; - -moz-background-size: cover; - -o-background-size: cover; - background-size: cover; - width: 55%; -} - -.inner { - display: flex; -} - -.app { - display: flex; - border-radius: 200px; - background-color: #eee; -} - -.outer { - min-width: 15%; - padding: 0px 2%; - color: #444; - display: flex; - justify-content: center; - flex-direction: column; - font-size: 15px; -} - -.right { - text-align: right; - margin-left: auto; -} - -.title { - font-size: 20px; - align-items: center; - justify-content: center; - text-align: center; - overflow: hidden; - text-overflow: ellipsis; -} - -.inner { - flex-direction: column; - color: white; - filter: drop-shadow(0px 0px 5px #000a); -} - -.mapinfo { - font-size: 12px; - flex-direction: row; - display: flex; - text-align: center; - align-items: center; - justify-content: center; -} - -.mapper { - padding-right: 15px; -} - -[v-cloak] { display: none; } - -.hide { - display: none; -} \ No newline at end of file diff --git a/webOverlay/overlays/SC_Map Example/main.js b/webOverlay/overlays/SC_Map Example/main.js deleted file mode 100644 index 26e969c4..00000000 --- a/webOverlay/overlays/SC_Map Example/main.js +++ /dev/null @@ -1,7 +0,0 @@ -import App from './components/App.js'; - -let app = Vue.createApp({ - ...App -}); - -app.mount('#app'); \ No newline at end of file diff --git a/webOverlay/overlays/SC_Map Overlay/README - DON'T EDIT THIS OVERLAY.txt b/webOverlay/overlays/SC_Map Overlay/README - DON'T EDIT THIS OVERLAY.txt deleted file mode 100644 index 0db05a7d..00000000 --- a/webOverlay/overlays/SC_Map Overlay/README - DON'T EDIT THIS OVERLAY.txt +++ /dev/null @@ -1,5 +0,0 @@ -================= -Any edits to files in Example overlays provided with StreamCompanion WILL BE OVERWRITTEN or even removed in future StreamCompanion update. -================= - -The overlay itself can be modified as you want, just not in this folder. Copy everything to a separate folder one directory up, and work from there. \ No newline at end of file diff --git a/webOverlay/overlays/SC_Map Overlay/components/App.js b/webOverlay/overlays/SC_Map Overlay/components/App.js deleted file mode 100644 index 14b4e4d6..00000000 --- a/webOverlay/overlays/SC_Map Overlay/components/App.js +++ /dev/null @@ -1,73 +0,0 @@ -import background from './Background.js'; - -const app = { - name: 'App', - components: { - Background: background, - }, - // https://v3.vuejs.org/guide/composition-api-introduction.html#basics-of-composition-api - setup(props, context) { - const data = Vue.reactive({ - tokens: {}, - rws: {}, - settings: { - progressColor: 'yellow', - }, - }); - //map global _GetToken helper method - const getToken = (tokenName, decimalPlaces) => _GetToken(data.rws, data.tokens, tokenName, decimalPlaces); - - //use helper _IsInStatus method to update isPlayingOrWatching value as necessary - let isPlayingOrWatching = Vue.computed(() => - _IsInStatus(data.rws, data.tokens, [window.overlay.osuStatus.Playing, window.overlay.osuStatus.ResultsScreen, window.overlay.osuStatus.Watching]) - ); - - //map pass percentage - let mapProgress = Vue.computed(() => ((getToken('time') / (getToken('totaltime') / 1000)) * 100).clamp(0, 100)); - - _GetWebOverlaySettings().then((config) => { - if (config.ChartProgressColor) data.settings.progressColor = config.ChartProgressColor; - }); - - //start websocket connection to SC with some predefined tokens - data.rws = watchTokens( - [ - 'mapStrains', - 'mapArtistTitle', - 'creator', - 'diffName', - 'mStars', - 'mCS', - 'mAR', - 'mOD', - 'mHP', - 'mBpm', - 'mods', - 'time', - 'totaltime', - 'status', - 'c100', - 'c50', - 'miss', - 'mapsetid', - 'status', - 'md5', - ], - (values) => { - Object.assign(data.tokens, values); - } - ); - - //return all data & computed vars & methods that we want to use elsewhere in this component - return { - data: data.tokens, - getToken, - isPlayingOrWatching, - mapProgress, - progressColor: Vue.computed(() => data.settings.progressColor), - - }; - }, -}; - -export default app; diff --git a/webOverlay/overlays/SC_Map Overlay/components/Background.js b/webOverlay/overlays/SC_Map Overlay/components/Background.js deleted file mode 100644 index 928e33ea..00000000 --- a/webOverlay/overlays/SC_Map Overlay/components/Background.js +++ /dev/null @@ -1,62 +0,0 @@ -const background = { - //unique name for this component - name: 'backgroundContainer', - //"html" to render instead of original tag ( in this case). - //Normally this would be in separate template tag(vue SFC) but because we use no build tools we have to use inline string. - template: ` -
- -
- `, - // https://v3.vuejs.org/guide/composition-api-introduction.html#basics-of-composition-api - setup(props, context) { - const data = Vue.reactive({ - tokens: { backgroundImageLocation: '', md5: '', mapsetid: '' }, - backgroundUrl: '', - backgroundId: Number.MIN_SAFE_INTEGER, - rws: {}, - }); - const backgroundDiv = Vue.ref(null); - - //function with will automatically monitor all dependant variables for changes and update its value whenever they change - //note that these variables have to be reactive(Vue.reactive)/refs(Vue.ref) - const boxStyle = Vue.computed(() => `background-image:url(${data.backgroundUrl});`); - - //we want to watch and trigger a function whenever data.tokens.backgroundImageLocation changes - Vue.watch( - //function returning value with should be watched for changes - () => data.tokens.backgroundImageLocation, - //method to execute when value defined above changes - () => { - var currId = (data.backgroundId += 1); - - let width = 1920, - height = 1080; - if (backgroundDiv.value) { - if (backgroundDiv.value.scrollWidth > 10) width = backgroundDiv.value.scrollWidth; - if (backgroundDiv.value.scrollHeight > 10) height = backgroundDiv.value.scrollHeight; - } - - preloadImage( - `${window.overlay.config.getUrl()}/backgroundImage?width=${width}&height=${height}&mapset=${data.tokens.mapsetid}&dummyData=${encodeURIComponent(data.tokens.md5)}&crop=true`, - currId, - (url, id) => { - if (data.backgroundId !== id) return; - data.backgroundUrl = url; - } - ); - } - ); - - //start websocket connection to SC with some predefined tokens - data.rws = watchTokens(['backgroundImageLocation', 'md5', 'mapsetid'], (values) => Object.assign(data.tokens, values)); - - //return all data & computed vars & methods that we want to use elsewhere in this file or in html template - return { - backgroundDiv, - boxStyle, - }; - }, -}; - -export default background; diff --git a/webOverlay/overlays/SC_Map Overlay/index.html b/webOverlay/overlays/SC_Map Overlay/index.html deleted file mode 100644 index c882a055..00000000 --- a/webOverlay/overlays/SC_Map Overlay/index.html +++ /dev/null @@ -1,45 +0,0 @@ - - - - - - - Map Overlay - - - - - - - - - - - -
-
- - -
-
-
{{data.mapArtistTitle}}
-
{{data.diffName}} -
{{data.mods.split(",").join("")}}
-
-
-
-
-
AR
{{getToken('mAR',1)}}
-
CS
{{getToken('mCS',1)}}
-
OD
{{getToken('mOD',1)}}
-
HP
{{getToken('mHP',1)}}
-
BPM
{{getToken('mainBpm',0)}}
-
SR
{{getToken('mStars',2)}}
-
-
-
-
- - - - \ No newline at end of file diff --git a/webOverlay/overlays/SC_Map Overlay/main.css b/webOverlay/overlays/SC_Map Overlay/main.css deleted file mode 100644 index 0c76140d..00000000 --- a/webOverlay/overlays/SC_Map Overlay/main.css +++ /dev/null @@ -1,79 +0,0 @@ -.progress { - /*background-color: yellow;*/ - height: 15px; - transition: none; - margin-bottom: 40px; - border-radius: 10px; - opacity: 0; -} -.pg-enabled { - opacity: 1; -} -.attr { - margin-top: 30px; -} -.attritem { - display: inline-block; - background: rgba(0, 0, 0, 0.25); - margin: 10px; - padding: 10px; - border-radius: 0.8rem; -} -.attrtitle { - display: inline-block; - margin-right: 5px; - font-weight: bold; -} -.box { - border-radius: 2rem; - overflow: hidden; - width: 1000px; -} -body { margin: 0 } -* { - transition: all 1s; - transition-timing-function: ease; - color: white; - text-align: center; - text-shadow: 0px 0px 10px rgba(255, 255, 255, 1), 0px 0px 46px rgba(255, 255, 255, 1), 0px 0px 80px rgba(255, 255, 255, 1); - font-family: 'Comfortaa'; -} -.title { - font-size: 35px; -} -.diffname { - margin-top: 7.5px; - font-size: 25px; -} -.modcolor { - color: #dbdbdb; - display: inline-block; - text-shadow: 0px 0px 10px #dbdbdb, 0px 0px 46px #dbdbdb, 0px 0px 80px #dbdbdb; -} -.background { - transition: all .2s; - filter: brightness(50%); - width: 1000px; - height: 300px; - background-position: center; - background-repeat: no-repeat; - background-size: cover; -} -.move { - position: absolute; - top: 0px; - width: 1000px; - border-radius: 2rem; overflow: hidden; - height: 300px; -} -.move2 { - position: absolute; - top: 200px; - width: 1000px; -} - -[v-cloak] { display: none; } - -.hide { - display: none; -} \ No newline at end of file diff --git a/webOverlay/overlays/SC_Map Overlay/main.js b/webOverlay/overlays/SC_Map Overlay/main.js deleted file mode 100644 index ec61c247..00000000 --- a/webOverlay/overlays/SC_Map Overlay/main.js +++ /dev/null @@ -1,7 +0,0 @@ -import App from './components/App.js'; - -let app = Vue.createApp({ - ...App, -}); - -app.mount('#app'); diff --git a/webOverlay/overlays/SC_Map Overlay/orginal file/app.svelte b/webOverlay/overlays/SC_Map Overlay/orginal file/app.svelte deleted file mode 100644 index 76b03940..00000000 --- a/webOverlay/overlays/SC_Map Overlay/orginal file/app.svelte +++ /dev/null @@ -1,157 +0,0 @@ - - - - -
- {#if data?.mAR != null && data?.mAR != "null"} - -
- -
-
-
-
-
{data?.mapArtistTitle}
-
{data?.diffName} - {#if data?.mods != "" && data?.mods != null && data?.mods != "None"} -
{`+${data.mods.split(",").join("")}`}
- {/if} -
-
-
-
-
AR
{data.mAR.toFixed(1)}
-
CS
{data.mCS.toFixed(1)}
-
OD
{data.mOD.toFixed(1)}
-
HP
{data.mHP.toFixed(1)}
-
BPM
{data.mBpm}
-
SR
{data.mStars.toFixed(2)}
-
-
-
- {/if} -
- - \ No newline at end of file diff --git a/webOverlay/overlays/SC_PP Counter/README - DON'T EDIT THIS OVERLAY.txt b/webOverlay/overlays/SC_PP Counter/README - DON'T EDIT THIS OVERLAY.txt deleted file mode 100644 index 0db05a7d..00000000 --- a/webOverlay/overlays/SC_PP Counter/README - DON'T EDIT THIS OVERLAY.txt +++ /dev/null @@ -1,5 +0,0 @@ -================= -Any edits to files in Example overlays provided with StreamCompanion WILL BE OVERWRITTEN or even removed in future StreamCompanion update. -================= - -The overlay itself can be modified as you want, just not in this folder. Copy everything to a separate folder one directory up, and work from there. \ No newline at end of file diff --git a/webOverlay/overlays/SC_PP Counter/components/App.js b/webOverlay/overlays/SC_PP Counter/components/App.js deleted file mode 100644 index 1014176a..00000000 --- a/webOverlay/overlays/SC_PP Counter/components/App.js +++ /dev/null @@ -1,33 +0,0 @@ -import background from './Background.js'; - -const app = { - name: 'App', - components: { - Background: background, - }, - setup(props, context) { - const data = Vue.reactive({ - tokens: {}, - rws: {}, - }); - - const getToken = (tokenName, decimalPlaces) => _GetToken(data.rws, data.tokens, tokenName, decimalPlaces); - let isMania = Vue.computed(() => getToken('gameMode') === 'OsuMania'); - let isPlayingOrWatching = Vue.computed(() => - _IsInStatus(data.rws, data.tokens, [window.overlay.osuStatus.Playing, window.overlay.osuStatus.ResultsScreen, window.overlay.osuStatus.Watching]) - ); - //either request all tokens upfront by filling their names in array - //or request them later using helper getToken method above - data.rws = watchTokens([], (values) => { - Object.assign(data.tokens, values); - }); - - return { - getToken, - isPlayingOrWatching, - isMania, - }; - }, -}; - -export default app; diff --git a/webOverlay/overlays/SC_PP Counter/components/Background.js b/webOverlay/overlays/SC_PP Counter/components/Background.js deleted file mode 100644 index 18517b41..00000000 --- a/webOverlay/overlays/SC_PP Counter/components/Background.js +++ /dev/null @@ -1,54 +0,0 @@ -const background = { - name: 'backgroundContainer', - template: ` -
- -
- `, - setup(props, context) { - const data = Vue.reactive({ - tokens: { backgroundImageLocation: '', md5: '', mapsetid: '' }, - backgroundUrl: '', - backgroundId: Number.MIN_SAFE_INTEGER, - rws: {}, - }); - const backgroundDiv = Vue.ref(null); - const boxStyle = Vue.computed(() => `background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0.1), rgba(0, 0, 0, 0.6)),url(${data.backgroundUrl});`); - - Vue.watch( - () => data.tokens.backgroundImageLocation, - () => { - let currId = (data.backgroundId += 1); - - let width = 1920, - height = 1080; - if (backgroundDiv.value) { - if (backgroundDiv.value.scrollWidth > 10) width = backgroundDiv.value.scrollWidth; - if (backgroundDiv.value.scrollHeight > 10) height = backgroundDiv.value.scrollHeight; - } - - preloadImage( - `${window.overlay.config.getUrl()}/backgroundImage?width=${width}&height=${height}&mapset=${data.tokens.mapsetid}&dummyData=${encodeURIComponent( - data.tokens.md5 - )}&crop=1`, - currId, - (url, id) => { - if (data.backgroundId !== id) return; - data.backgroundUrl = url; - } - ); - } - ); - Vue.onMounted(() => { - console.log(backgroundDiv.value); - }); - data.rws = watchTokens(['backgroundImageLocation', 'md5', 'mapsetid'], (values) => Object.assign(data.tokens, values)); - - return { - backgroundDiv, - boxStyle, - }; - }, -}; - -export default background; diff --git a/webOverlay/overlays/SC_PP Counter/index.html b/webOverlay/overlays/SC_PP Counter/index.html deleted file mode 100644 index bccdaa13..00000000 --- a/webOverlay/overlays/SC_PP Counter/index.html +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - pp Display Example - - - - - - - - - - - -
- -
-
-
-

{{getToken('c100')}}

-
-
-

{{getToken('c50')}}

-
-
-

{{getToken('miss')}}

-
-
-
-
-

{{getToken('geki')}}

-
-
-

{{getToken('c300')}}

-
-
-

{{getToken('katsu')}}

-
-
-

{{getToken('c100')}}

-
-
-

{{getToken('c50')}}

-
-
-

{{getToken('miss')}}

-
-
-
-

0

-
-

{{getToken('ppIfMapEndsNow',1)}}pp

-
-
-
- - - diff --git a/webOverlay/overlays/SC_PP Counter/main.css b/webOverlay/overlays/SC_PP Counter/main.css deleted file mode 100644 index 56cb5622..00000000 --- a/webOverlay/overlays/SC_PP Counter/main.css +++ /dev/null @@ -1,94 +0,0 @@ -* { - padding: 0px; - margin: 0px; - font-family: comfortaa; -} - -.hit-p300-mania { - background-color: rgba(50, 205, 50, 0.667); -} -.hit-300-mania { - background-color: rgba(50, 205, 50, 0.667); -} -.hit-200-mania { - background-color: rgba(138, 43, 226, 0.667); -} -.hit-100-mania { - background-color: rgba(138, 43, 226, 0.667); -} -.hit-50-mania { - background-color: rgba(255, 69, 0, 0.667); -} -.hit-miss-mania { - background-color: rgba(255, 69, 0, 0.667); -} - -.hit-100 { - background-color: rgba(50, 205, 50, 0.667); -} -.hit-50 { - background-color: rgba(138, 43, 226, 0.667); -} -.hit-miss { - background-color: rgba(255, 69, 0, 0.667); -} - -.hit-text { - color: white; - justify-self: center; - text-align: center; -} - -.hit { - padding: 7px 5px; - align-self: center; - text-align: center; - min-width: 45px; - font-size: 18px; -} - -.box { - border-radius: 200px -} - -.box { - padding: 25px; - padding-left: 27px; - background-repeat: no-repeat; - background-position: center center; - -webkit-background-size: cover; - -moz-background-size: cover; - -o-background-size: cover; - background-size: cover; -} - -.hit:first-child { - border-radius: 50px 0px 0px 50px; -} -.hit:last-child { - border-radius: 0px 50px 50px 0px; -} - -.inner { - display: flex; -} - -.hits { - display: flex; -} - -.pp { - color: white; - margin-left: auto; - align-self: center; -} - -.ds { - filter: drop-shadow(0px 0px 5px #0004); -} - -[v-cloak] { display: none; } - -.hide { - display: none; -} \ No newline at end of file diff --git a/webOverlay/overlays/SC_PP Counter/main.js b/webOverlay/overlays/SC_PP Counter/main.js deleted file mode 100644 index ec61c247..00000000 --- a/webOverlay/overlays/SC_PP Counter/main.js +++ /dev/null @@ -1,7 +0,0 @@ -import App from './components/App.js'; - -let app = Vue.createApp({ - ...App, -}); - -app.mount('#app'); diff --git a/webOverlay/overlays/SC_Template/README - DON'T EDIT THIS OVERLAY.txt b/webOverlay/overlays/SC_Template/README - DON'T EDIT THIS OVERLAY.txt deleted file mode 100644 index 0db05a7d..00000000 --- a/webOverlay/overlays/SC_Template/README - DON'T EDIT THIS OVERLAY.txt +++ /dev/null @@ -1,5 +0,0 @@ -================= -Any edits to files in Example overlays provided with StreamCompanion WILL BE OVERWRITTEN or even removed in future StreamCompanion update. -================= - -The overlay itself can be modified as you want, just not in this folder. Copy everything to a separate folder one directory up, and work from there. \ No newline at end of file diff --git a/webOverlay/overlays/SC_Template/components/App.js b/webOverlay/overlays/SC_Template/components/App.js deleted file mode 100644 index 84f99a0b..00000000 --- a/webOverlay/overlays/SC_Template/components/App.js +++ /dev/null @@ -1,25 +0,0 @@ -const app = { - name: 'App', - components: {}, - // https://v3.vuejs.org/guide/composition-api-introduction.html#basics-of-composition-api - setup(props, context) { - const data = Vue.reactive({ - tokens: {}, - rws: {}, - }); - //map global _GetToken helper method - const getToken = (tokenName, decimalPlaces) => _GetToken(data.rws, data.tokens, tokenName, decimalPlaces); - - //start websocket connection to SC - data.rws = watchTokens([], (values) => { - Object.assign(data.tokens, values); - }); - - //return all data & computed vars & methods that we want to use elsewhere in this component - return { - getToken, - }; - }, -}; - -export default app; diff --git a/webOverlay/overlays/SC_Template/index.html b/webOverlay/overlays/SC_Template/index.html deleted file mode 100644 index c55448c1..00000000 --- a/webOverlay/overlays/SC_Template/index.html +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - minimal template overlay - - - - - - - - - - - -
-
{{getToken('mapArtistTitle')}}
-
- - - diff --git a/webOverlay/overlays/SC_Template/main.css b/webOverlay/overlays/SC_Template/main.css deleted file mode 100644 index 7c4521e1..00000000 --- a/webOverlay/overlays/SC_Template/main.css +++ /dev/null @@ -1,17 +0,0 @@ -body { - margin: 0; -} -* { - color: black; - font-family: 'Comfortaa'; -} -.large { - font-size: 35px; -} -.hide { - display: none; -} - -[v-cloak] { - display: none; -} diff --git a/webOverlay/overlays/SC_Template/main.js b/webOverlay/overlays/SC_Template/main.js deleted file mode 100644 index ec61c247..00000000 --- a/webOverlay/overlays/SC_Template/main.js +++ /dev/null @@ -1,7 +0,0 @@ -import App from './components/App.js'; - -let app = Vue.createApp({ - ...App, -}); - -app.mount('#app'); diff --git a/webOverlay/overlays/SC_Token/README - DON'T EDIT THIS OVERLAY.txt b/webOverlay/overlays/SC_Token/README - DON'T EDIT THIS OVERLAY.txt deleted file mode 100644 index 0db05a7d..00000000 --- a/webOverlay/overlays/SC_Token/README - DON'T EDIT THIS OVERLAY.txt +++ /dev/null @@ -1,5 +0,0 @@ -================= -Any edits to files in Example overlays provided with StreamCompanion WILL BE OVERWRITTEN or even removed in future StreamCompanion update. -================= - -The overlay itself can be modified as you want, just not in this folder. Copy everything to a separate folder one directory up, and work from there. \ No newline at end of file diff --git a/webOverlay/overlays/SC_Token/components/App.js b/webOverlay/overlays/SC_Token/components/App.js deleted file mode 100644 index 99d3ebba..00000000 --- a/webOverlay/overlays/SC_Token/components/App.js +++ /dev/null @@ -1,50 +0,0 @@ -const app = { - name: 'App', - components: {}, - // https://v3.vuejs.org/guide/composition-api-introduction.html#basics-of-composition-api - setup(props, context) { - const data = Vue.reactive({ - tokens: {}, - rws: {}, - }); - //map global _GetToken helper method - const getToken = (tokenName, decimalPlaces) => _GetToken(data.rws, data.tokens, tokenName, decimalPlaces); - - const urlParams = new URLSearchParams(window.location.search); - const tokenName = urlParams.get('token'); - const decimals = urlParams.get('decimals'); - - console.log(urlParams.get('token')); - //start websocket connection to SC - data.rws = watchTokens([], (values) => { - Object.assign(data.tokens, values); - }); - const baseUrl= window.location.origin+window.location.pathname+"?token="; - - const createExample = (text,token,decimals)=>{ - return { - text: text, - token: token, - decimals: decimals, - url: `${baseUrl}${token}`+(decimals ? `&decimals=${decimals}` : ``) - }; - }; - - //return all data & computed vars & methods that we want to use elsewhere in this component - return { - getToken, - tokenName, - decimals, - baseUrl, - examples:[ - createExample('text token:','mapArtistTitle'), - createExample('text token:','mapArtistTitleUnicode'), - createExample('numeric token(map AR):','mAR'), - createExample('numeric token, with defined amount of decimals(map AR):','mAR',2), - createExample('numeric token(map AR):','mAR'), - ] - }; - }, -}; - -export default app; diff --git a/webOverlay/overlays/SC_Token/index.html b/webOverlay/overlays/SC_Token/index.html deleted file mode 100644 index a0180ed6..00000000 --- a/webOverlay/overlays/SC_Token/index.html +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - Single token output - - - - - - - - - - - -
-
- {{getToken(tokenName, decimals)}} -
-
-
Set token name in overlay url!
-
examples:
-
-
{{ex.text}} {{ex.url}} - Result: {{getToken(ex.token,ex.decimals)}}
-
-
-
- - - diff --git a/webOverlay/overlays/SC_Token/main.css b/webOverlay/overlays/SC_Token/main.css deleted file mode 100644 index 7c4521e1..00000000 --- a/webOverlay/overlays/SC_Token/main.css +++ /dev/null @@ -1,17 +0,0 @@ -body { - margin: 0; -} -* { - color: black; - font-family: 'Comfortaa'; -} -.large { - font-size: 35px; -} -.hide { - display: none; -} - -[v-cloak] { - display: none; -} diff --git a/webOverlay/overlays/SC_Token/main.js b/webOverlay/overlays/SC_Token/main.js deleted file mode 100644 index ec61c247..00000000 --- a/webOverlay/overlays/SC_Token/main.js +++ /dev/null @@ -1,7 +0,0 @@ -import App from './components/App.js'; - -let app = Vue.createApp({ - ...App, -}); - -app.mount('#app'); diff --git a/webOverlay/overlays/SC_URBar/README - DON'T EDIT THIS OVERLAY.txt b/webOverlay/overlays/SC_URBar/README - DON'T EDIT THIS OVERLAY.txt deleted file mode 100644 index 0db05a7d..00000000 --- a/webOverlay/overlays/SC_URBar/README - DON'T EDIT THIS OVERLAY.txt +++ /dev/null @@ -1,5 +0,0 @@ -================= -Any edits to files in Example overlays provided with StreamCompanion WILL BE OVERWRITTEN or even removed in future StreamCompanion update. -================= - -The overlay itself can be modified as you want, just not in this folder. Copy everything to a separate folder one directory up, and work from there. \ No newline at end of file diff --git a/webOverlay/overlays/SC_URBar/components/App.js b/webOverlay/overlays/SC_URBar/components/App.js deleted file mode 100644 index a653b2ce..00000000 --- a/webOverlay/overlays/SC_URBar/components/App.js +++ /dev/null @@ -1,27 +0,0 @@ -import roundurbar from './roundURBar.js'; - -const app = { - name: 'App', - components: { roundurbar }, - // https://v3.vuejs.org/guide/composition-api-introduction.html#basics-of-composition-api - setup(props, context) { - const data = Vue.reactive({ - tokens: {}, - rws: {}, - }); - //map global _GetToken helper method - const getToken = (tokenName, decimalPlaces) => _GetToken(data.rws, data.tokens, tokenName, decimalPlaces); - - //start websocket connection to SC with some predefined tokens - data.rws = watchTokens([], (values) => { - Object.assign(data.tokens, values); - }); - - //return all data & computed vars & methods that we want to use elsewhere in this component - return { - getToken, - }; - }, -}; - -export default app; diff --git a/webOverlay/overlays/SC_URBar/components/roundURBar.js b/webOverlay/overlays/SC_URBar/components/roundURBar.js deleted file mode 100644 index ebb90e8a..00000000 --- a/webOverlay/overlays/SC_URBar/components/roundURBar.js +++ /dev/null @@ -1,389 +0,0 @@ -//=======USER CONFIGURATION -const SCRoundURBarSettings = { - //hit colors, css color value - hitColors: { - hit300: '#add8e6c9', - hit100: '#008000c9', - hit50: '#ffa500c9', - }, - //arc colors, css color value - arcColors: { - hit300: '#add8e6', - hit100: '#008000', - hit50: '#ffa500', - }, - //color of current avg hit marker - hitMarkerColor: '#00ffffc9', - canvas: { - width: 600, - height: 100, - }, - //arc settings - when changing you might need to also adjust canvas settings above - arc: { - //x-center of the arc - x: 300, - //y-center of the arc - y: 720, - //arc radius - radius: 680, - //how long should the arc be, 0.01 - 2 - length: 0.25, - //width of the arc line - width: 8, - }, - //How many hits should be displayed at the same time - amountOfHitErrors: 40, - // add #type (eg. /#circle ) at the end of overlay url to change or change it here. accepted values: 'rectangle' | 'circle' | 'ellipse' - hitElementType: getHitTypeFromUrlHash('ellipse'), - //should UR bar hide itself when not playing? true/false - hideWhenNotPlaying: false, - //per-hitType hit configuration - hitElements: { - rectangle: { - //width of hit element - width: 3, - //height of hit element - height: 30, - //how far away should the hit be drawn from arc, negative values inside, positive values outside - distanceFromArc: 0, - marker: { - //how far away should current avg hit marker arrow be drawn from arc, negative values inside, positive values outside - distanceFromArc: 5, - //size of avg hit marker arrow - size: 8, - }, - //don't touch (: - drawFn: () => canvasHelpers.arc.drawRectangleAroundArc, - }, - circle: { - width: 6, - distanceFromArc: 12, - marker: { - distanceFromArc: 22, - size: 8, - }, - drawFn: () => canvasHelpers.arc.drawCircleAroundArc, - }, - ellipse: { - width: 2.5, - height: 8, - distanceFromArc: 13, - marker: { - distanceFromArc: 22, - size: 8, - }, - drawFn: () => canvasHelpers.arc.drawEllipseAroundArc, - }, - }, -}; -//=======END OF USER CONFIGURATION - - - -const canvasHelpers = (() => { - function drawAroundArc(x, y, deg, yOffset, ctx, drawFn) { - ctx.save(); - ctx.translate(x, y); - ctx.rotate(degrees_to_radians(deg + 90)); - ctx.translate(0, yOffset); - drawFn(ctx); - ctx.restore(); - } - function drawRectangleAroundArc(x, y, w, h, deg, yOffset, fillStyle, ctx) { - drawAroundArc(x, y, deg, yOffset, ctx, () => drawRectangle(-1 * (w / 2), -1 * (h / 2), w, h, fillStyle, ctx)); - } - function drawCircleAroundArc(x, y, w, h, deg, yOffset, fillStyle, ctx) { - drawAroundArc(x, y, deg, yOffset, ctx, () => drawCircle(0, 0, w / 2, w, 0, 2 * Math.PI, fillStyle, ctx)); - } - function drawEllipseAroundArc(x, y, w, h, deg, yOffset, fillStyle, ctx) { - drawAroundArc(x, y, deg, yOffset, ctx, () => drawEllipse(0, 0, w, h, 0,0, 2 * Math.PI,0, fillStyle, ctx)); - } - function drawRectangle(x, y, w, h, fillStyle, ctx) { - ctx.fillStyle = fillStyle; - ctx.fillRect(x, y, w, h); - } - function drawCircle(x, y, radius, width, startAngle, endAngle, fillStyle, ctx) { - ctx.beginPath(); - ctx.strokeStyle = fillStyle; - ctx.lineWidth = width; - ctx.arc(x, y, radius, startAngle, endAngle, false); - ctx.stroke(); - } - function drawEllipse(x,y,radiusX,radiusY,rotation,startAngle,endAngle,lineWidth,fillStyle,ctx){ - startAngle = startAngle * Math.PI; - endAngle = endAngle * Math.PI; - ctx.beginPath(); - ctx.ellipse(x, y, radiusX, radiusY, rotation, startAngle, endAngle, false); - ctx.lineWidth = lineWidth; - ctx.fillStyle = fillStyle; - ctx.fill(); - } - function drawArc(x, y, startAngle, endAngle, radius, strokeStyle, lineWidth, ctx) { - startAngle = startAngle * Math.PI; - endAngle = endAngle * Math.PI; - ctx.beginPath(); - ctx.arc(x, y, radius, startAngle, endAngle, false); - ctx.lineWidth = lineWidth; - ctx.strokeStyle = strokeStyle; - ctx.stroke(); - } - function drawArrowAroundArc(x, y, deg, yOffset, fillStyle, p1, p2, size, ctx) { - drawAroundArc(x, y, deg, yOffset, ctx, (ctx) => { - var angle = Math.atan2(p2.y - p1.y, p2.x - p1.x); - var hyp = Math.sqrt((p2.x - p1.x) * (p2.x - p1.x) + (p2.y - p1.y) * (p2.y - p1.y)); - - ctx.save(); - ctx.translate(p1.x, p1.y); - ctx.rotate(angle); - - // // line - // ctx.beginPath(); - // ctx.moveTo(0, 0); - // ctx.lineTo(hyp - size, 0); - // ctx.stroke(); - - // triangle - ctx.fillStyle = fillStyle; - ctx.beginPath(); - ctx.lineTo(hyp - size, size); - ctx.lineTo(hyp, 0); - ctx.lineTo(hyp - size, -size); - ctx.fill(); - - ctx.restore(); - }); - } - function clearCanvas(canvas, context) { - context.save(); - context.setTransform(1, 0, 0, 1, 0, 0); - context.clearRect(0, 0, canvas.width, canvas.height); - context.restore(); - } - function degrees_to_radians(degrees) { - return (degrees * Math.PI) / 180; - } - function radians_to_degrees(radians) { - return (radians * 180) / Math.PI; - } - - return { - arc: { - drawArc, - drawAroundArc, - drawRectangleAroundArc, - drawCircleAroundArc, - drawArrowAroundArc, - drawEllipseAroundArc - }, - degrees_to_radians, - radians_to_degrees, - drawRectangle, - drawCircle, - drawEllipse, - clearCanvas, - }; -})(); - -function odToMs(od) { - return { - hit300: (159 - 12 * od) / 2, - hit100: (279 - 16 * od) / 2, - hit50: (399 - 20 * od) / 2, - }; -} - -function scaleValue(value, from, to) { - var scale = (to[1] - to[0]) / (from[1] - from[0]); - var capped = Math.min(from[1], Math.max(from[0], value)) - from[0]; - return capped * scale + to[0]; -} - -function movingAverage(windowSize, values) { - if (!(windowSize > 0)) { - throw new Error('windowSize must be positive'); - } - if (!(values != null && values.length)) { - throw new Error('invalid array of values'); - } - let sum = 0.0; - const results = []; - for (let i = 0; i < values.length; i++) { - const val = values[i]; - sum += val; - if (i >= windowSize) { - sum -= values[i - windowSize]; - } - results.push(sum / Math.min(i + 1, windowSize)); - } - return results; -} - -function getHitTypeFromUrlHash(fallbackValue){ - const hash = (window.location.hash || '').toLowerCase(); - return ['#rectangle', '#circle', '#ellipse'].indexOf(hash)>-1 ? hash.substr(1) : fallbackValue; -} - -const roundurbar = { - name: 'roundurbar', - template: ` -
- - - -
- `, - setup(props, context) { - const data = Vue.reactive({ - tokens: { hitErrors: '', unstableRate: '', mOD: '' }, - rws: {}, - }); - data.rws = watchTokens(['hitErrors', 'unstableRate', 'mOD'], (values) => Object.assign(data.tokens, values)); - const isPlayingOrWatching = Vue.computed(() => _IsInStatus(data.rws, data.tokens, [window.overlay.osuStatus.Playing, window.overlay.osuStatus.Watching])); - const settings = SCRoundURBarSettings; - - //some calc - const arcStart = 1.5 - settings.arc.length / 2; - const arcEnd = 1.5 + settings.arc.length / 2; - const arcDiff = arcEnd - arcStart; - const rectDegOffset = -canvasHelpers.radians_to_degrees(arcDiff) * 1.572 + 90; - const x = settings.arc.x; - const y = settings.arc.y; - const hitSettings = settings.hitElements[settings.hitElementType]; - let hitsContext, barContext, AvgHitsArrowContext, arrowInterval, hitMsWindows=odToMs(1); - - let arrowAvg = 0; - const drawHitsArrow = () => { - canvasHelpers.clearCanvas(canvasAvgHitsArrowRef.value, AvgHitsArrowContext); - if (!data.tokens.hitErrors || data.tokens.hitErrors.length === 0) { - return; - } - - let avgErrorHits = data.tokens.hitErrors.slice(Math.max(data.tokens.hitErrors.length - 10, 0)); - avgErrorHits = movingAverage(2, avgErrorHits); - for (var i = 0; i < avgErrorHits.length; i++) { - arrowAvg = arrowAvg * 0.95 + avgErrorHits[i] * 0.05; - } - canvasHelpers.arc.drawArrowAroundArc( - x, - y, - getDegForHit(arrowAvg), - settings.arc.radius + hitSettings.marker.distanceFromArc, - settings.hitMarkerColor, - { x: 0, y: 5 }, - { x: 0, y: 0 }, - hitSettings.marker.size, - AvgHitsArrowContext - ); - }; - - //canvas dom element refs - const canvasBarRef = Vue.ref(null); - const canvasHitsRef = Vue.ref(null); - const canvasAvgHitsArrowRef = Vue.ref(null); - - Vue.onMounted(() => { - barContext = canvasBarRef.value.getContext('2d'); - hitsContext = canvasHitsRef.value.getContext('2d'); - AvgHitsArrowContext = canvasAvgHitsArrowRef.value.getContext('2d'); - arrowInterval = setInterval(drawHitsArrow, 33); - }); - - const getColorForHit = (hit) => { - let abs = Math.abs(hit); - if (abs <= hitMsWindows.hit300) return settings.hitColors.hit300; - if (abs <= hitMsWindows.hit100) return settings.hitColors.hit100; - return settings.hitColors.hit50; - } - const getDegForHit = (hit) => { - return ( - rectDegOffset + - canvasHelpers.radians_to_degrees( - scaleValue(hit.clamp(-hitMsWindows.hit50, hitMsWindows.hit50), [-hitMsWindows.hit50, hitMsWindows.hit50], [0, arcDiff * 3.142]) - ) - ); - }; - - //draw hit elements around arc circumference - const drawShapeFn = hitSettings.drawFn() - const drawHits = (hits, height = null) => { - hits = hits || []; - height = height || hitSettings.height; - hits.forEach((hitError) => { - drawShapeFn( - x, - y, - hitSettings.width, - height, - getDegForHit(hitError), - settings.arc.radius + hitSettings.distanceFromArc, - getColorForHit(hitError), - hitsContext - ); - }); - }; - - //Update arc whenever map OD value changes - Vue.watch( - () => data.tokens.mOD, - () => { - hitMsWindows = odToMs(data.tokens.mOD); - let arcTotal = Math.abs(arcStart - arcEnd); - - //radians taken on arc by each hit - let h300p = (hitMsWindows.hit300 / hitMsWindows.hit50) * arcTotal; - let h100p = ((hitMsWindows.hit100 - hitMsWindows.hit300) / hitMsWindows.hit50) * arcTotal; - let h50p = arcTotal - h300p - h100p; - - //draw arc sections - canvasHelpers.clearCanvas(canvasBarRef.value, barContext); - const drawArc = canvasHelpers.arc.drawArc; - const radius = settings.arc.radius; - const arcColors = settings.arcColors; - const arcWidth = settings.arc.width; - - let newArcStart = arcStart + h50p / 2; - drawArc(x, y, arcStart, newArcStart, radius, arcColors.hit50, arcWidth, barContext); - - let newArcEnd = newArcStart + h100p / 2; - drawArc(x, y, newArcStart, newArcEnd, radius, arcColors.hit100, arcWidth, barContext); - newArcStart = newArcEnd; - - newArcEnd = newArcStart + h300p; - drawArc(x, y, newArcStart, newArcEnd, radius, arcColors.hit300, arcWidth, barContext); - newArcStart = newArcEnd; - - newArcEnd = newArcStart + h100p / 2; - drawArc(x, y, newArcStart, newArcEnd, radius, arcColors.hit100, arcWidth, barContext); - newArcStart = newArcEnd; - - newArcEnd = newArcStart + h50p / 2; - drawArc(x, y, newArcStart, newArcEnd, radius, arcColors.hit50, arcWidth, barContext); - newArcStart = newArcEnd; - - canvasHelpers.clearCanvas(canvasHitsRef.value, hitsContext); - drawHits([0, -hitMsWindows.hit50, hitMsWindows.hit50, -hitMsWindows.hit100, hitMsWindows.hit100, -hitMsWindows.hit300, hitMsWindows.hit300]); - } - ); - - //Update drawn hitErrors whenever these change - Vue.watch( - () => data.tokens.hitErrors, - () => { - canvasHelpers.clearCanvas(canvasHitsRef.value, hitsContext); - if (!data.tokens.hitErrors || !(x && y)) return; - drawHits(data.tokens.hitErrors.slice(Math.max(data.tokens.hitErrors.length - settings.amountOfHitErrors, 0))); - } - ); - - return { - canvasBarRef, - canvasHitsRef, - canvasAvgHitsArrowRef, - width: settings.canvas.width, - height: settings.canvas.height, - show: Vue.computed(() => (settings.hideWhenNotPlaying ? isPlayingOrWatching.value : true)), - }; - }, -}; - -export default roundurbar; diff --git a/webOverlay/overlays/SC_URBar/index.html b/webOverlay/overlays/SC_URBar/index.html deleted file mode 100644 index f64e6c6d..00000000 --- a/webOverlay/overlays/SC_URBar/index.html +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - SC UR Bar - - - - - - - - - - - -
- -
- - - diff --git a/webOverlay/overlays/SC_URBar/main.css b/webOverlay/overlays/SC_URBar/main.css deleted file mode 100644 index be6917ab..00000000 --- a/webOverlay/overlays/SC_URBar/main.css +++ /dev/null @@ -1,17 +0,0 @@ -body { - margin: 0; -} -* { - color: black; - font-family: 'Comfortaa'; -} -.large { - font-size: 35px; -} -.hide { - display: none; -} - -[v-cloak] { - display: none; - } \ No newline at end of file diff --git a/webOverlay/overlays/SC_URBar/main.js b/webOverlay/overlays/SC_URBar/main.js deleted file mode 100644 index ec61c247..00000000 --- a/webOverlay/overlays/SC_URBar/main.js +++ /dev/null @@ -1,7 +0,0 @@ -import App from './components/App.js'; - -let app = Vue.createApp({ - ...App, -}); - -app.mount('#app'); diff --git a/webOverlay/overlays/SC_bg/README - DON'T EDIT THIS OVERLAY.txt b/webOverlay/overlays/SC_bg/README - DON'T EDIT THIS OVERLAY.txt deleted file mode 100644 index 0db05a7d..00000000 --- a/webOverlay/overlays/SC_bg/README - DON'T EDIT THIS OVERLAY.txt +++ /dev/null @@ -1,5 +0,0 @@ -================= -Any edits to files in Example overlays provided with StreamCompanion WILL BE OVERWRITTEN or even removed in future StreamCompanion update. -================= - -The overlay itself can be modified as you want, just not in this folder. Copy everything to a separate folder one directory up, and work from there. \ No newline at end of file diff --git a/webOverlay/overlays/SC_bg/components/App.js b/webOverlay/overlays/SC_bg/components/App.js deleted file mode 100644 index 599fe1e9..00000000 --- a/webOverlay/overlays/SC_bg/components/App.js +++ /dev/null @@ -1,27 +0,0 @@ -import background from './Background.js'; - -const app = { - name: 'App', - components: { - Background: background, - }, - - setup(props, context) { - const data = Vue.reactive({ - tokens: {}, - rws: {}, - settings: {}, - }); - - const getToken = (tokenName, decimalPlaces) => _GetToken(data.rws, data.tokens, tokenName, decimalPlaces); - data.rws = watchTokens([], (values) => { - Object.assign(data.tokens, values); - }); - - return { - getToken, - data, - }; - } -}; -export default app; diff --git a/webOverlay/overlays/SC_bg/components/Background.js b/webOverlay/overlays/SC_bg/components/Background.js deleted file mode 100644 index df534108..00000000 --- a/webOverlay/overlays/SC_bg/components/Background.js +++ /dev/null @@ -1,55 +0,0 @@ -const background = { - name: 'backgroundContainer', - template: ` -
- -
- `, - props: { - dimcolor: { default: '#00000000' }, - }, - setup(props, context) { - const data = Vue.reactive({ - tokens: { backgroundImageLocation: '', md5: '', mapsetid: '' }, - backgroundUrl: '', - backgroundId: Number.MIN_SAFE_INTEGER, - rws: {}, - }); - const backgroundDiv = Vue.ref(null); - const boxStyle = Vue.computed(() => `background-image: linear-gradient(to bottom, ${props.dimcolor}, ${props.dimcolor}),url(${data.backgroundUrl});`); - - Vue.watch( - () => data.tokens.backgroundImageLocation, - () => { - let currId = (data.backgroundId += 1); - - let width = 1920, - height = 1080; - if (backgroundDiv.value) { - if (backgroundDiv.value.scrollWidth > 10) width = backgroundDiv.value.scrollWidth; - if (backgroundDiv.value.scrollHeight > 10) height = backgroundDiv.value.scrollHeight; - } - - preloadImage( - `${window.overlay.config.getUrl()}/backgroundImage?width=${width}&height=${height}&mapset=${data.tokens.mapsetid}&dummyData=${encodeURIComponent( - data.tokens.md5 - )}&crop=1`, - currId, - (url, id) => { - if (data.backgroundId !== id) return; - data.backgroundUrl = url; - } - ); - } - ); - - data.rws = watchTokens(['backgroundImageLocation', 'md5', 'mapsetid'], (values) => Object.assign(data.tokens, values)); - - return { - backgroundDiv, - boxStyle, - }; - }, -}; - -export default background; diff --git a/webOverlay/overlays/SC_bg/index.html b/webOverlay/overlays/SC_bg/index.html deleted file mode 100644 index 61fd7b5c..00000000 --- a/webOverlay/overlays/SC_bg/index.html +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - Background image - - - - - - - - - - - -
- - -
- - - diff --git a/webOverlay/overlays/SC_bg/main.css b/webOverlay/overlays/SC_bg/main.css deleted file mode 100644 index 36481f9c..00000000 --- a/webOverlay/overlays/SC_bg/main.css +++ /dev/null @@ -1,47 +0,0 @@ -:root { - --animation-speed: 1.7s; -} - -* { - padding: 0px; - margin: 0px; - font-family: comfortaa; -} - -.clipPathAnimation { - transition: clip-path 0.3s; -} - -.box { - height: 100%; - background-repeat: no-repeat; - background-position: center center; - -webkit-background-size: cover; - -moz-background-size: cover; - -o-background-size: cover; - background-size: cover; - transition: padding var(--animation-speed) ease; - overflow-y: hidden; -} - -.inner { - display: flex; - flex-direction: column; - filter: drop-shadow(0px 0px 5px #000a); - width: 100%; - margin-top: 10px; - z-index: 50; -} - -.app { - height: 100vh; -} - -[v-cloak] { - display: none; -} - -.hide { - display: none; - z-index: -1; -} diff --git a/webOverlay/overlays/SC_bg/main.js b/webOverlay/overlays/SC_bg/main.js deleted file mode 100644 index ec61c247..00000000 --- a/webOverlay/overlays/SC_bg/main.js +++ /dev/null @@ -1,7 +0,0 @@ -import App from './components/App.js'; - -let app = Vue.createApp({ - ...App, -}); - -app.mount('#app'); diff --git a/webOverlay/overlays/static/README.txt b/webOverlay/overlays/static/README.txt deleted file mode 100644 index 413110b3..00000000 --- a/webOverlay/overlays/static/README.txt +++ /dev/null @@ -1,5 +0,0 @@ -Instructions: -download zip of this repository: https://github.com/l3lackShark/static -unpack it in this folder -run convert.bat ONCE -navigate to http://localhost:20727/ to see additional overlays ready to use diff --git a/webOverlay/overlays/static/convert.bat b/webOverlay/overlays/static/convert.bat deleted file mode 100644 index f7e0a7cb..00000000 --- a/webOverlay/overlays/static/convert.bat +++ /dev/null @@ -1,5 +0,0 @@ -fart.exe -r -c -C -- .\*.html "reconnecting-websocket.min.js\x22>" "reconnecting-websocket.min.js\x22>\n" -fart.exe -r -c -C -- .\*.js "new ReconnectingWebSocket" "CreateProxiedReconnectingWebSocket" -fart.exe -r -c -C -- .\*.js "JSON.parse(event.data)" "event.data" -fart.exe -r -c -C -- .\*.js "24050" "${window.overlay.config.port}" -fart.exe -r -c -C -- .\*.js "127.0.0.1" "${window.overlay.config.host}" \ No newline at end of file diff --git a/webOverlay/overlays/static/fart.exe b/webOverlay/overlays/static/fart.exe deleted file mode 100644 index 075563cdc0f4909c5ab3ba2147c80ade92f49825..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 69660 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

_w>?-bDFnk8sDNC*^vjwPM99VI<0a#T?Vn8}< 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 z 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 diff --git a/webOverlay/staticLoader.html b/webOverlay/staticLoader.html deleted file mode 100644 index d1e0eb89..00000000 --- a/webOverlay/staticLoader.html +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - - - - StreamCompanion web overlay static loader - - - - - - - - - \ No newline at end of file