Skip to content

Commit

Permalink
feat: better snip + loop controls (#201)
Browse files Browse the repository at this point in the history
  • Loading branch information
cdrani authored Dec 21, 2023
1 parent 8244aa8 commit a8a7d4a
Show file tree
Hide file tree
Showing 41 changed files with 566 additions and 375 deletions.
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.20.0",
"version": "1.21.0",
"scripts": {
"build": "rollup -c",
"watch": "rollup -c -w"
Expand Down
8 changes: 3 additions & 5 deletions src/background.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,13 @@ async function getUIState({ selector, tabId }) {
}

async function getMediaControlsState(tabId) {
const requiredKeys = ['repeat', 'shuffle', 'play/pause', 'save/unsave', 'seek-rewind', 'seek-fastforward']
const requiredKeys = ['repeat', 'shuffle', 'play/pause', 'seek-rewind', 'seek-fastforward', 'loop', 'save/unsave']
const selectorKeys = { ...mediaKeys, ...chorusKeys }
const selectors = Object.keys(selectorKeys).map(key => (
requiredKeys.includes(key) ? selectorKeys[key] : undefined
)).filter(Boolean)
const selectors = requiredKeys.map(key => selectorKeys[key] ?? undefined).filter(Boolean)

const promises = selectors.map(selector => (
new Promise(resolve => {
if (!selector.includes('add-button')) return resolve(getUIState({ selector, tabId }))
if (!selector.includes('loop')) return resolve(getUIState({ selector, tabId }))
return setTimeout(() => resolve(getUIState({ selector, tabId })), 500)
})
))
Expand Down
2 changes: 1 addition & 1 deletion src/components/artist-disco.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const dispatcher = new Dispatcher()
const createArtistDiscoUI = () => `
<div
id="artist-disco"
style="display:flex;width:3.5rem;height:3.5rem;align-items:center;justify-content:center"
style="display:flex;align-items:center;"
>
<button
role="artist-disco"
Expand Down
2 changes: 1 addition & 1 deletion src/components/effects/effects-controls.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ 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;">
<div style="display:flex;flex-direction:column;justify-content:space-between;height:5.5rem;">
${createEffectsSelector({ name: 'drink-effect', labelName: 'cup-sized reverb', optionNames: drinkPresets })}
${createEffectsSelector({ name: 'convolver-effect', labelName: 'impulse reverb', optionNames: convolverPresets })}
Expand Down
2 changes: 1 addition & 1 deletion src/components/header.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export const createHeader = () => `
<div class="chorus-common">
<span class="chorus-header">chorus</span>
<div style="display:flex;justify-content:space-between;align-items:center;">
<div style="display:flex;height:25px;align-items:center;justify-content:space-around;">
<div id="header-buttons" 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;' })}
Expand Down
22 changes: 12 additions & 10 deletions src/components/snip/snip-controls.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
import { createSlider } from './snip-slider.js'
import { createRangeLabels } from './snip-labels.js'
import { createSnipToggler } from './snip-toggle.js'
import { createSnipButtons } from './snip-buttons.js'

import { playback } from '../../utils/playback.js'

export const createSnipControls = () => {
const current = playback.current()
const duration = playback.duration()

return `
<div id="chorus-snip-controls" style="display: block">
${createSlider({ current, duration })}
export const createSnipControls = () => `
<div id="chorus-snip-controls" style="display: block">
${createSlider({ current: playback.current(), duration: playback.duration(), style: "margin:6px 0" })}
<p style="font-size:.75rem;color:#fff;padding:0;margin-top:-8px;padding-bottom:.5rem">
* while editing 'end', track plays 3 secs past set 'end'
</p>
<div style="display:flex;justify-content:space-between;height:3rem;">
${createRangeLabels()}
${createSnipButtons()}
${createSnipToggler()}
</div>
`
}
${createSnipButtons()}
</div>
`
13 changes: 6 additions & 7 deletions src/components/snip/snip-labels.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
const style = "min-width:24px;font-size:0.85rem;text-align:end;margin-left:4px"

const createLabel = text => `
<div>
<label class="chorus-common" style="width:100%;align-items: end">
${text}: <span style="${style}" id="chorus-${text}"></span>
</label>
<div class="chorus-common" style="display:flex;align-items:center;height:22px;">
<span class="chorus-text chorus-pill" style="font-size:1rem;line-height:22px;height:100%;text-align:center;min-width:43px;width:56px;padding:0 4px">
${text}
</span>
<input id="chorus-${text}" class="chorus-text" style="letter-spacing:0.5px;padding:0 4px;width:100%;text-align:end;background:green;border:none;color:#fff;height:100%;">
</div>
`

export const createRangeLabels = () => `
<div style="display:flex;justify-content:space-between;height:3rem;align-items:center;">
<div style="display:flex;flex-direction:column;justify-content:space-between;width:100%">
${createLabel('start')}
${createLabel('end')}
</div>
Expand Down
6 changes: 3 additions & 3 deletions src/components/snip/snip-slider.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { secondsToTime } from '../../utils/time.js'

const createInput = ({ type, max, value }) => `
<input min="0" max="${max}" type="range" class="input" value="${value}" id="input-${type}">
<input min="0" max="${max}" step="0.01" type="range" class="input" value="${value}" id="input-${type}">
`

const createTime = ({ id, time }) => `
<p class="time${id == 'end' ? ' end' : ''}"><span id="${id}">${time}</span></p>
`

export const createSlider = ({ current, duration }) => `
<div id="snippy" class="snippy">
export const createSlider = ({ current, duration, style = '' }) => `
<div id="snippy" class="snippy" style="${style}">
${createTime({ id: 'start', time: '0:00' })}
<div class="slider-container">
${createInput({ type: 'start', max: duration, value: current })}
Expand Down
16 changes: 16 additions & 0 deletions src/components/snip/snip-toggle.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { createToggleButton } from '../toggle-button.js'

export const createSnipToggler = () => `
<div style="display:flex;justify-content:flex-end;align-items:center;width:100%;">
<div style="display:flex;justify-content:space-between;align-items:flex-end">
${createToggleButton({
labelId: 'loop-label',
labelText: 'Auto-Loop',
onPathId: 'loop-toggle-on',
offPathId: 'loop-toggle-off',
checkboxId: 'loop-checkbox',
buttonId: 'loop-toggle-button',
})}
</div>
</div>
`
10 changes: 5 additions & 5 deletions src/components/speed/speed-toggler.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { createToggleButton } from '../toggle-button.js'

const createTag = ({ tag, id, style = '' }) => `
<div style="display:flex;align-items:center;${style};">
<span class="chorus-text chorus-pill" style="text-align:left;width:46px;padding-left:4px">${tag}</span>
<input id="${id}" class="chorus-text" style="color:#fff;width:42px;height:100%;padding:0 4px">
<div style="display:flex;align-items:center;height:22px;${style};">
<span class="chorus-text chorus-pill" style="line-height:22px;height:100%;font-size:14px;text-align:center;width:56px;padding:0 4px">${tag}</span>
<input id="${id}" class="chorus-text" style="text-align:end;letter-spacing:0.5px;border:none;color:#fff;width:56px;height:100%;padding:0 4px">
</div>
`

export const createSpeedToggler = () => `
<div style="display:flex;justify-content:space-between;align-items:center;width:100%;">
<div style="display:flex;flex-direction:column;justify-content:space-between;">
<div style="display:flex;justify-content:space-between;width:100%;height:3.5rem;">
<div style="display:flex;flex-direction:column;justify-content:space-between;height:100%">
${createTag({ tag: 'Track', id: 'speed-track-value', style: 'margin-bottom:4px' })}
${createTag({ tag: 'Global', id: 'speed-global-value' })}
</div>
Expand Down
2 changes: 1 addition & 1 deletion src/components/text-button.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export const createTextButton = ({ id, text, style }) => {
<button
id="chorus-${id}-button"
class="chorus-text-button ${btnTypeClass ?? ''}"
style="padding:0 10px;height:100%;font-size:1rem;${style || ''}"
style="display:flex;justify-content:center;align-items:center;padding:0 10px;height:100%;font-size:1rem;${style || ''}"
>
<span>${text}</span>
</button>
Expand Down
2 changes: 1 addition & 1 deletion src/components/toggle-button.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export const createToggleButton = ({
style="z-index:100;padding:0;background-color:transparent;display:flex;align-items:center;user-select:none;"
>
${labelId && labelText && `
<span id="${labelId}" style="font-size:1rem;color:#fff;margin-right:1rem">${labelText}</span>
<span id="${labelId}" style="font-weight:600;font-size:1rem;color:#fff;margin-right:1rem">${labelText}</span>
`}
<input
Expand Down
2 changes: 1 addition & 1 deletion src/components/track-info.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export const createTrackInfo = () => `
<div style="display:flex;flex-direction:column;width:100%;justify-content:space-evenly;margin-top:.5rem">
<div style="display:flex;flex-direction:column;width:100%;justify-content:space-evenly;margin:.5rem 0">
<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>
Expand Down
3 changes: 2 additions & 1 deletion src/data/current.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ class CurrentData {
...currentSongInfo(),
startTime: 0,
isSnip: false,
autoLoop: false,
isSkipped: false,
endTime: playback.duration()
}
Expand Down Expand Up @@ -67,7 +68,7 @@ class CurrentData {
}

async readTrack() {
return await this._store.getTrack({ id: currentSongInfo().id, value: this.#trackDefaults })
return await this._store.getTrack({ id: currentSongInfo().id, value: { ...this.#trackDefaults, ...currentSongInfo() }})
}

async readGlobals() {
Expand Down
19 changes: 13 additions & 6 deletions src/events/listeners/header-listeners.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import Listeners from './listeners.js'
import { spotifyVideo } from '../../actions/overload.js'

export default class HeaderListeners extends Listeners {
constructor(songTracker) {
super(songTracker)

this._setup = false
this._viewInFocus = null
this._video = spotifyVideo.element
this._VIEWS = ['snip', 'speed', 'fx', 'seek']
}

Expand All @@ -18,7 +20,7 @@ export default class HeaderListeners extends Listeners {
this.#effectsViewToggle()
this.#closeModalListener()

this._currentView = 'snip'
this.currentView = 'snip'
this._setup = true
}

Expand All @@ -30,13 +32,15 @@ export default class HeaderListeners extends Listeners {
#seekViewToggle() {
const seekButton = document.getElementById('chorus-seek-button')
seekButton?.addEventListener('click', async () => {
this._currentView = 'seek'
this.currentView = 'seek'
await this._seek.init()
})
}

set _currentView(selectedView) {
set currentView(selectedView = 'snip') {
this._viewInFocus = selectedView
if (selectedView != 'snip') this._video.resetTempTimes()

this._VIEWS.forEach(view => {
const viewButton = document.getElementById(`chorus-${view}-button`)
const viewInFocusContainer = document.getElementById(`chorus-${view}-controls`)
Expand All @@ -49,21 +53,24 @@ export default class HeaderListeners extends Listeners {

#snipViewToggle() {
const snipButton = document.getElementById('chorus-snip-button')
snipButton?.addEventListener('click', () => { this._currentView = 'snip' })
snipButton?.addEventListener('click', async () => {
this.currentView = 'snip'
await this._snip.init()
})
}

#speedViewToggle() {
const speedButton = document.getElementById('chorus-speed-button')
speedButton?.addEventListener('click', async () => {
this._currentView = 'speed'
this.currentView = 'speed'
await this._speed.init()
})
}

#effectsViewToggle() {
const effectsButton = document.getElementById('chorus-fx-button')
effectsButton?.addEventListener('click', () => {
this._currentView = 'fx'
this.currentView = 'fx'
this._reverb.init()
})
}
Expand Down
2 changes: 1 addition & 1 deletion src/events/listeners/listeners.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,6 @@ export default class Listeners {
_hide() {
const mainElement = document.getElementById('chorus-main')
mainElement.style.display = 'none'
this._video.isEditing = false
this._video.resetTempTimes()
}
}
5 changes: 4 additions & 1 deletion src/manifest.chrome.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"short_name": "Chorus",
"name": "Chorus - Spotify Enhancer",
"description": "Enhance Spotify with controls to save favourite snips, auto-skip tracks, and set global and custom speed. More to come!",
"version": "1.20.0",
"version": "1.21.0",
"manifest_version": 3,
"author": "cdrani",
"action": {
Expand Down Expand Up @@ -49,6 +49,9 @@
"on/off": {
"description": "Toggle Extension On/Off"
},
"loop": {
"description": "Loop/UnLoop Snip/Track"
},
"next": {
"description": "Next Track"
},
Expand Down
5 changes: 4 additions & 1 deletion src/manifest.firefox.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"short_name": "Chorus",
"name": "Chorus - Spotify Enhancer",
"description": "Enhance Spotify with controls to save favourite snips, auto-skip tracks, and set global and custom speed. More to come!",
"version": "1.20.0",
"version": "1.21.0",
"manifest_version": 3,
"author": "cdrani",
"action": {
Expand Down Expand Up @@ -49,6 +49,9 @@
"on/off": {
"description": "Toggle Extension On/Off"
},
"loop": {
"description": "Loop/UnLoop Snip/Track"
},
"next": {
"description": "Next Track"
},
Expand Down
19 changes: 5 additions & 14 deletions src/models/chorus.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,21 +26,13 @@ export default class Chorus {
return this.mainElement.style.display == 'block'
}

get mainElement() {
return document.getElementById('chorus-main')
}
get mainElement() { return document.getElementById('chorus-main') }

get chorusControls() {
return document.getElementById('chorus-controls')
}
get chorusControls() { return document.getElementById('chorus-controls') }

toggle() {
this.isShowing ? this.hide() : this.show()
}
toggle() { this.isShowing ? this.hide() : this.show() }

get #hasSnipControls() {
return !!document.getElementById('chorus-snip-controls')
}
get #hasSnipControls() { return !!document.getElementById('chorus-snip-controls') }

#insertIntoDOM() {
if (this.#hasSnipControls) return
Expand All @@ -60,15 +52,14 @@ export default class Chorus {
if (!this.mainElement) return

await this.headerListeners.hide()
this._video.isEditing = false
this.mainElement.style.display = 'none'
this._video.resetTempTimes()
}

show() {
this.#insertIntoDOM()
this.mainElement.style.display = 'block'

this._video.isEditing = true
this.headerListeners.init()
this.actionListeners.init()
}
Expand Down
Loading

0 comments on commit a8a7d4a

Please sign in to comment.