Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: reverb effect settings #177

Merged
merged 52 commits into from
Nov 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
6efe4e3
lib: add reverb audio processor + presets
cdrani Nov 8, 2023
0e75ecc
models: add Reverb class to set reverb effect
cdrani Nov 8, 2023
13fd2cf
actions: connect Reverb with App
cdrani Nov 8, 2023
ddb8896
refactor: cleanup up presets exports
cdrani Nov 8, 2023
8676652
fix: retrieval of data from stores
cdrani Nov 9, 2023
0857735
chore: move Reverb class to sub directory
cdrani Nov 9, 2023
4e90548
lib: update reverb presets to more subdued values
cdrani Nov 9, 2023
e3a77b6
fix: set video crossOrigin to anonymous
cdrani Nov 9, 2023
1be2bea
components: create effects ui components
cdrani Nov 9, 2023
c296036
ui: connect effects ui to chorus modal
cdrani Nov 9, 2023
54e6add
fix: chorus events not re-init on ext. toggling
cdrani Nov 10, 2023
5a7c735
app: connect/disconnect Reverb on ext. toggle
cdrani Nov 10, 2023
6c68a78
style: update effects ui text + container styles
cdrani Nov 10, 2023
af53d6a
style: set track-info ui font-size to 14px
cdrani Nov 10, 2023
da81a7e
fix: reverb key retrieval from storage
cdrani Nov 10, 2023
04a26de
refactor: remove content script from document after load
cdrani Nov 10, 2023
c218544
docs: include lib in manifest resources
cdrani Nov 10, 2023
e11f3c9
media: add impulse reverb sounds
cdrani Nov 11, 2023
d0c78a0
fix: seek buttons currentTime setting
cdrani Nov 11, 2023
2e761ee
lib: add convolver presets names
cdrani Nov 11, 2023
0da2713
content: store path to reverb & sounds in session
cdrani Nov 11, 2023
7be8bfa
refactor: update Reverb class to support convolver reverb
cdrani Nov 11, 2023
7ff0f12
refactor: update to include convolver reverb logic
cdrani Nov 11, 2023
b66b121
fix: remove auto hide on action listener button events
cdrani Nov 11, 2023
1da381f
manifest: include sounds folder in resources
cdrani Nov 11, 2023
2b5d40d
style: update effects selector + selection styles
cdrani Nov 13, 2023
a4f87c6
models: only call #connect for digital drink presets
cdrani Nov 13, 2023
75bd9e1
models: reset non-selected reverb preset effect
cdrani Nov 13, 2023
40de831
styles: add styles for button classes
cdrani Nov 13, 2023
bac57b7
fix: update current-snip #delete method logic
cdrani Nov 13, 2023
27e5e91
fix: speed reset button to reset speed
cdrani Nov 13, 2023
c679e63
fix: seek #reset resets seek data to defaults
cdrani Nov 13, 2023
13ad2f9
refactor: extract track-info into util
cdrani Nov 14, 2023
a5fa58c
components: update text in effects ui
cdrani Nov 14, 2023
ecceb4b
lib: update preset sounds
cdrani Nov 14, 2023
350cf41
fix: Reverb digital & impulse dis(connect) logic
cdrani Nov 14, 2023
a1b2bd2
refactor: remove unnecessary await on reverb init
cdrani Nov 14, 2023
11ef1c1
styles: clean up styles
cdrani Nov 14, 2023
886c5f7
fix: remove hide call on snip share call
cdrani Nov 14, 2023
77e61eb
fix: chorus modal hide resets speed values
cdrani Nov 15, 2023
3f2041f
refactor: rename effects to fx
cdrani Nov 15, 2023
bb0aeca
reverb: set audio ctx latencyHint to playback
cdrani Nov 15, 2023
ca29b17
refactor: toggle reverb effect on video active value
cdrani Nov 15, 2023
b1cec6c
fix: artist retrieval in tracklist view
cdrani Nov 15, 2023
31e8e0c
fix: firefox reverb toggling
cdrani Nov 15, 2023
f819b16
services: add player seek to position request
cdrani Nov 15, 2023
98beebe
refactor: content & background messaging
cdrani Nov 15, 2023
f8f4ed1
styles: remove cursor related styles
cdrani Nov 16, 2023
75f4a95
fix: #isFirefox getter
cdrani Nov 16, 2023
40a6400
styles: remove margin from hr
cdrani Nov 16, 2023
c3c5ceb
docs: update manifest min_stric_version to 112
cdrani Nov 16, 2023
e9e4eea
docs: bump to v1.17.0
cdrani Nov 15, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "chorus",
"private": true,
"type": "module",
"version": "1.16.2",
"version": "1.17.0",
"scripts": {
"build": "rollup -c",
"watch": "rollup -c -w"
Expand Down
7 changes: 4 additions & 3 deletions src/actions/init.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@ import App from '../models/app.js'

async function load() {
await store.populate()
const app = new App(spotifyVideo.element)

const app = new App({ video: spotifyVideo.element, reverb: spotifyVideo.reverb })
const enabled = JSON.parse(sessionStorage.getItem('enabled') ?? 'true')

enabled ? await app.connect() : app.disconnect()
enabled ? app.connect() : app.disconnect()
spotifyVideo.element.active = enabled

document.addEventListener('app.enabled', async e => {
Expand All @@ -19,7 +20,7 @@ async function load() {

sessionStorage.setItem('enabled', enabled.newValue)
spotifyVideo.element.active = enabled.newValue
enabled.newValue ? await app.connect() : app.disconnect()
enabled.newValue ? app.connect() : app.disconnect()
})

document.addEventListener('app.device_id', async e => {
Expand Down
43 changes: 11 additions & 32 deletions src/actions/overload.js
Original file line number Diff line number Diff line change
@@ -1,53 +1,32 @@
import Reverb from '../models/reverb/reverb.js'
import VideoElement from '../models/video/video.js'

class SpotifyVideo {
#video
#tries = 0
#originalCreateElement = document.createElement

constructor() {
this.#overloadCreateElement()
this._video
this._reverb
this._originalCreateElement = document.createElement
this.#init()
}

#overloadCreateElement() {
#init() {
const self = this

document.createElement = function (tagName) {
const element = self.#originalCreateElement.apply(this, arguments)
const element = self._originalCreateElement.apply(this, arguments)

if (tagName === 'video') {
self.#video = new VideoElement(element)

document.createElement = self.#originalCreateElement
self._reverb = new Reverb(element)
self._video = new VideoElement({ video: element, reverb: self._reverb })
document.createElement = self._originalCreateElement
}
return element
}
}

#init = () => {
try {
this.#tries++
this.#checkForMainEl()
} catch {
if (this.#tries <= 20) {
setTimeout(this.#init, 500)
return
}
}
}

#checkForMainEl() {
const mainEl = document.getElementById('main')
get element() { return this._video }

if (mainEl === null) {
throw new Error('Main container element not found')
}
}

get element() {
return this.#video
}
get reverb() { return this._reverb }
}

export const spotifyVideo = new SpotifyVideo()
30 changes: 16 additions & 14 deletions src/background.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { setState, getState } from './utils/state.js'
import { getActiveTab, sendMessage } from './utils/messaging.js'

import { playSharedTrack } from './services/player.js'
import { createArtistDiscoPlaylist } from './services/artist-disco.js'
import { playSharedTrack, seekTrackToPosition } from './services/player.js'

let ENABLED = true
let popupPort = null
Expand Down Expand Up @@ -79,20 +79,22 @@ chrome.webRequest.onBeforeSendHeaders.addListener(details => {
['requestHeaders']
)

chrome.runtime.onMessage.addListener(({ key, data }, _, sendResponse) => {
switch (key) {
case 'artist.disco':
createArtistDiscoPlaylist(data)
.then(result => sendResponse({ state: 'completed', data: result }))
.catch(error => sendResponse({ state: 'error', error: error.message }))
return true
case 'play.shared':
playSharedTrack(data)
.then(result => sendResponse({ state: 'completed', data: result }))
.catch(error => sendResponse({ state: 'error', error: error.message }))

return true
function promiseHandler(promise, sendResponse) {
promise.then(result => sendResponse({ state: 'completed', data: result }))
.catch(error => sendResponse({ state: 'error', error: error.message }))
}

chrome.runtime.onMessage.addListener(({ key, values }, _, sendResponse) => {
const messageHandler = {
'play.shared': playSharedTrack,
'play.seek': seekTrackToPosition,
'artist-disco': createArtistDiscoPlaylist,
}
const handlerFn = messageHandler[key]
if (!handlerFn) return

promiseHandler(handlerFn(values), sendResponse)
return true
})

chrome.commands.onCommand.addListener(async command => {
Expand Down
8 changes: 8 additions & 0 deletions src/components/effects/effects-button.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { createTextButton } from '../text-button.js'

export const createEffectsButtons = () => `
<div style="display:flex;margin-top:12px;justify-content:space-between;height:1.5rem;">
${createTextButton({ text: 'reset', id: 'effects-reset' })}
${createTextButton({ text: 'save', id: 'effects-save' })}
</div>
`
20 changes: 20 additions & 0 deletions src/components/effects/effects-controls.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { createEffectsButtons } from './effects-button.js'
import { createEffectsSelector } from './effects-selector.js'
import { convolverPresets, drinkPresets } from '../../lib/reverb/presets.js'

export const createEffectsControls = () => `
<div id="chorus-fx-controls" style="display: none">
<div style="display:flex;flex-direction:column;justify-content:space-evenly;height:6rem;">
${createEffectsSelector({ name: 'drink-effect', labelName: 'cup-sized reverb', optionNames: drinkPresets })}
${createEffectsSelector({ name: 'convolver-effect', labelName: 'impulse reverb', optionNames: convolverPresets })}

<hr/>
<div style="font-size:1rem;color:#b3b3b3;">
<p style="display:flex;justify-content:space-between;width:100%;padding-right:.125rem;">
effect <span id="preset-selection" style="color:#fff"></span>
</p>
</div>
</div>
${createEffectsButtons()}
</div>
`
21 changes: 21 additions & 0 deletions src/components/effects/effects-selector.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
const createOptions = optionNames => (
optionNames.map(name => `<option name="${name}" value="${name}">${name}</option>`).join('')
)

export const createEffectsSelector = ({ labelName, name, optionNames }) => `
<div style="display:flex;justify-content:space-between">
<label style="color:#b3b3b3;font-size:">${labelName}</label>

<form id="select-container" class="selector">
<select
class="select"
id="${name}-presets"
name="${name}-presets"
style="color:#fff;font-size:1rem;text-align:end"
>
<option name="none" value="none">-----</option>
${createOptions(optionNames)}
</select>
</form>
</div>
`
1 change: 1 addition & 0 deletions src/components/header.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export const createHeader = () => `
<div style="display:flex;height:25px;align-items:center;justify-content:space-around;">
${createHeaderButton({ role: 'snip', ariaLabel: 'Snip Controls', additionalStyles: 'background-color:green;' })}
${createHeaderButton({ role: 'speed', ariaLabel: 'Speed Controls', additionalStyles: 'margin-left:.5rem;' })}
${createHeaderButton({ role: 'fx', ariaLabel: 'FX Controls', additionalStyles: 'margin-left:.5rem;' })}
${createHeaderButton({ role: 'seek', ariaLabel: 'Seek Controls', additionalStyles: 'margin:0 .5rem;' })}
</div>

Expand Down
22 changes: 13 additions & 9 deletions src/components/text-button.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
export const createTextButton = ({ id, text, style }) => `
<button
id="chorus-${id}-button"
class="chorus-text-button"
style="padding:0 10px;height:100%;font-size:1rem;${style || ''}"
>
<span>${text}</span>
</button>
`
const classNames = { share: 'share', save: 'success', reset: 'danger', remove: 'danger' }

export const createTextButton = ({ id, text, style }) => {
const btnTypeClass = classNames[id?.split('-')?.at(-1)]
return `
<button
id="chorus-${id}-button"
class="chorus-text-button ${btnTypeClass ?? ''}"
style="padding:0 10px;height:100%;font-size:1rem;${style || ''}"
>
<span>${text}</span>
</button>
`
}
6 changes: 3 additions & 3 deletions src/components/track-info.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export const createTrackInfo = () => `
<div style="display:flex;flex-direction:column;margin-top:0.5rem;">
<p id="track-title" style="color:#fff;font-size:14px;"></p>
<p id="track-artists" style="font-size:11px;color:#b3b3b3;"></p>
<div style="display:flex;flex-direction:column;width:100%;justify-content:space-evenly;margin-top:.5rem">
<div class="container" style="width:282px"><div class="track-text" id="track-title"></div></div>
<div class="container" style="width:282px"><div class="track-text" id="track-artists"></div></div>
</div>
`
57 changes: 20 additions & 37 deletions src/content.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,55 +5,38 @@ const loadScript = filePath => {
const script = document.createElement('script')
script.src = chrome.runtime.getURL(filePath)
script.type = 'module'
document.body.appendChild(script)
document.head.appendChild(script)
script.onload = () => { script.remove() }
}

loadScript('actions/init.js')
sessionStorage.setItem('soundsDir', chrome.runtime.getURL('/lib/sounds/'))
sessionStorage.setItem('reverbPath', chrome.runtime.getURL('/lib/reverb/reverb.js'))

const sendEventToPage = ({ eventType, detail }) => {
window.postMessage({
type: 'FROM_CONTENT_SCRIPT',
requestType: eventType,
payload: detail
}, window.location.origin)
window.postMessage({ type: 'FROM_CONTENT_SCRIPT', requestType: eventType, payload: detail }, window.location.origin)
}

window.addEventListener('message', async (event) => {
if (event.origin !== window.location.origin) return
if (event.data.type !== 'FROM_PAGE_SCRIPT') return

const { requestType, payload } = event.data
let response

switch (requestType) {
case 'artist.disco':
response = await sendBackgroundMessage({ key: payload.key, data: payload.values })
sendEventToPage({ eventType: 'artist.disco.response', detail: response })
break
case 'play.shared':
response = await sendBackgroundMessage({ key: payload.key, data: payload.values })
sendEventToPage({ eventType: 'play.shared.response', detail: response })
break
case 'storage.set':
const { key, values } = payload
response = await setState({ key, values })
sendEventToPage({ eventType: 'storage.set.response', detail: response })
break

case 'storage.get':
response = await getState(payload?.key)
sendEventToPage({ eventType: 'storage.get.response', detail: response })
break

case 'storage.delete':
await removeState(payload.key)
break

case 'storage.populate':
response = await getState(null)
sendEventToPage({ eventType: 'storage.populate.response', detail: response })
break
}
const messageHandlers = {
'play.seek': sendBackgroundMessage,
'play.shared': sendBackgroundMessage,
'artist.disco': sendBackgroundMessage,
'storage.populate': () => getState(null),
'storage.get': ({ key }) => getState(key),
'storage.delete': ({ key }) => removeState(key),
'storage.set': ({ key, values }) => setState({ key, values }),
};

const handlerFn = messageHandlers[requestType]
if (!handlerFn) return

const response = await handlerFn(payload)
sendEventToPage({ eventType: `${requestType}.response`, detail: response })
})

chrome.runtime.onMessage.addListener(message => {
Expand Down
Loading