Skip to content

Commit

Permalink
feat: new speed input step + manual inputs (#190)
Browse files Browse the repository at this point in the history
  • Loading branch information
cdrani authored Nov 29, 2023
1 parent dd74096 commit 9ef8ef2
Show file tree
Hide file tree
Showing 11 changed files with 90 additions and 72 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.17.1",
"version": "1.18.0",
"scripts": {
"build": "rollup -c",
"watch": "rollup -c -w"
Expand Down
2 changes: 1 addition & 1 deletion src/components/speed/speed-range.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export const createSpeedRange = () => `
<input
min="0.1"
max="4"
step="0.05"
step="0.001"
type="range"
class="input"
id="speed-input"
Expand Down
14 changes: 7 additions & 7 deletions src/components/speed/speed-toggler.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import { createToggleButton } from '../toggle-button.js'

const createTag = ({ tag, id, text, style = '' }) => `
<div style="display:flex;align-items:center;${style}">
<span class="chorus-text chorus-pill">${tag}</span>
<span class="chorus-text" id="${id}" style="height:100%;margin-left:4px;padding:0 4px">${text}</span>
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>
`

export const createSpeedToggler = () => `
<div style="display:flex;justify-content:space-between;align-items:center;width:100%">
<div style="display:flex;justify-content:space-between;align-items:center;width:100%;">
<div style="display:flex;flex-direction:column;justify-content:space-between;">
${createTag({ tag: 'T', id: 'speed-track-value', text: '1x', style: 'margin-bottom:4px' })}
${createTag({ tag: 'G', id: 'speed-global-value', text: '1x' })}
${createTag({ tag: 'Track', id: 'speed-track-value', style: 'margin-bottom:4px' })}
${createTag({ tag: 'Global', id: 'speed-global-value' })}
</div>
<div style="display:flex;flex-direction:column;justify-content:space-between;align-items:flex-end">
Expand Down
2 changes: 1 addition & 1 deletion src/data/song-state.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const sharedSnipValues = () => {
endTime: parseInt(endTime, 10),
startTime: parseInt(startTime, 10),
preservesPitch: parseInt(preservesPitch, 10) == 1,
playbackRate: parseFloat(playbackRate) / 100,
playbackRate: parseFloat(playbackRate) / 1000,
}
}

Expand Down
2 changes: 1 addition & 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.17.1",
"version": "1.18.0",
"manifest_version": 3,
"author": "cdrani",
"action": {
Expand Down
2 changes: 1 addition & 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.17.1",
"version": "1.18.0",
"manifest_version": 3,
"author": "cdrani",
"action": {
Expand Down
128 changes: 71 additions & 57 deletions src/models/range/range.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,16 @@
export default class RangeSlider {
#video
#data

constructor(video) {
this.#video = video
this._delay = 50
this._video = video
this._data = null
this._delayTimeout = null
}

init(data) {
if (!this.#data) {
this.#setupEvents()
}
if (!this._data) this.#setupEvents()

const { track, globals, preferredRate, preferredPitch } = data
const {
input, speedTrackValue, speedGlobalValue, speedCheckbox, pitchCheckbox
} = this.elements
const { input, speedTrackValue, speedGlobalValue, speedCheckbox, pitchCheckbox } = this.elements

input.value = preferredRate
this.#setSpeedValue({ playbackRate: preferredRate, preservesPitch: preferredPitch })
Expand All @@ -27,29 +23,29 @@ export default class RangeSlider {

this.#setCheckedUI({ speedChecked, pitchChecked })

speedTrackValue.textContent = `${this.#padValue(track?.playbackRate || 1)}x`
speedGlobalValue.textContent = `${this.#padValue(globals?.playbackRate || 1)}x`
speedTrackValue.value = this.#padValue(track?.playbackRate || 1)
speedGlobalValue.value = this.#padValue(globals?.playbackRate || 1)

this.#hightlightSpeedValue(speedChecked)

this.#data = data
this._data = data
}

// TODO: move into utils
#padValue(value, decimalPlace = 2) {
if (isNaN(parseFloat(value))) {
return value
}
#padValue(value, decimalPlace = 3) {
if (isNaN(parseFloat(value))) return value

return parseFloat(value).toFixed(decimalPlace);
return parseFloat(value).toFixed(decimalPlace)
}

#setupEvents() {
const {
input, thumb, pitchToggleButton, speedToggleButton,
const {
input, thumb, speedGlobalValue, speedTrackValue, pitchToggleButton, speedToggleButton
} = this.elements

input.oninput = () => this.#setSpeedValue({})
input.oninput = () => this.#handleSlider()
speedTrackValue.onchange = (e) => this.#handleInput(e.target.value)
speedGlobalValue.onchange = (e) => this.#handleInput(e.target.value)

input.addEventListener('mouseover', () => thumb.classList.add('hover'))
input.addEventListener('mouseout', () => thumb.classList.remove('hover'))
Expand All @@ -60,56 +56,79 @@ export default class RangeSlider {
pitchToggleButton.onclick = () => this.#togglePitchCheckbox()
}

#isValidRate(value) {
if (isNaN(value) || value < 0.1 || value > 4) return false

return true
}

#handleInput(inputValue) {
const parsedValue = parseFloat(inputValue)
const isValid = this.#isValidRate(parsedValue)
const currentValue = this.elements.input.value
const playbackRate = isValid ? this.#padValue(parsedValue) : this.#padValue(currentValue)

this.elements.input.value = playbackRate
this.#setSpeedValue({ playbackRate })
}

#handleSlider() {
if (this._delayTimeout) clearTimeout(this._delayTimeout)
this._delayTimeout = setTimeout(() => this.#setSpeedValue({}), this._delay)
}

#setCheckedUI({ speedChecked, pitchChecked }) {
const {
speedLabel,
speedCheckbox, speedToggleOn, speedToggleOff,
pitchCheckbox, pitchToggleOn, pitchToggleOff
} = this.elements
const { pitchToggleOn, pitchToggleOff, speedToggleOn, speedToggleOff } = this.elements

speedToggleOn.style.display = speedChecked ? 'block' : 'none'
speedToggleOff.style.display = speedChecked ? 'none' : 'block'

pitchToggleOn.style.display = pitchChecked ? 'block' : 'none'
pitchToggleOff.style.display = pitchChecked ? 'none' : 'block'

speedLabel.textContent = speedChecked ? 'Global Speed' : 'Track Speed'
const { pitchCheckbox, speedLabel, speedCheckbox } = this.elements

speedLabel.textContent = speedChecked ? 'Global Speed' : 'Track Speed'
speedCheckbox.checked = speedChecked
pitchCheckbox.checked = pitchChecked
}

#toggleSpeedCheckbox() {
const {
input, speedCheckbox, speedTrackValue, speedGlobalValue,
pitchCheckbox
} = this.elements
const { input, speedCheckbox, speedTrackValue, speedGlobalValue, pitchCheckbox } = this.elements
speedCheckbox.checked = !speedCheckbox.checked

const { checked } = speedCheckbox
this.#setCheckedUI({ speedChecked: checked, pitchChecked: pitchCheckbox.checked })

const { track, globals } = this.#data
const { track, globals } = this._data

input.value = checked
? parseFloat(speedGlobalValue.textContent) || globals?.playbackRate || 1
: parseFloat(speedTrackValue.textContent)|| track?.playbackRate || 1
? parseFloat(speedGlobalValue.value) || globals?.playbackRate || 1
: parseFloat(speedTrackValue.value)|| track?.playbackRate || 1

this.#video.currentSpeed = input.value
this._video.currentSpeed = input.value

this.#hightlightSpeedValue(checked)
this.#setSpeedValue({ playbackRate: input.value })
}

#hightlightSpeedValue(checked) {
#hightlightSpeedValue(speedChecked) {
const { speedTrackValue, speedGlobalValue } = this.elements

if (checked) {
speedGlobalValue.parentElement.style.background = 'green'
speedTrackValue.parentElement.style.background = 'unset'
speedGlobalValue.disabled = !speedChecked
speedTrackValue.disabled = speedChecked

speedGlobalValue.style.backgroundColor = speedChecked ? 'green' : 'unset'
speedGlobalValue.style.outline = speedChecked ? 'solid 1px white' : ''

speedTrackValue.style.backgroundColor = !speedChecked ? 'green' : 'unset'
speedTrackValue.style.outline = !speedChecked ? 'solid 1px white' : ''

if (speedChecked) {
speedGlobalValue.focus()
speedTrackValue.blur()
} else {
speedGlobalValue.parentElement.style.background = 'unset'
speedTrackValue.parentElement.style.background = 'green'
speedGlobalValue.blur()
speedTrackValue.focus()
}
}

Expand All @@ -121,7 +140,7 @@ export default class RangeSlider {
pitchToggleOn.style.display = checked ? 'block' : 'none'
pitchToggleOff.style.display = checked ? 'none' : 'block'

this.#video.preservesPitch = checked
this._video.preservesPitch = checked
}

get elements() {
Expand Down Expand Up @@ -150,11 +169,7 @@ export default class RangeSlider {
}

#setSpeedValue({ playbackRate, preservesPitch }) {
const {
input, speedCheckbox, pitchCheckbox, range, thumb,
speedTrackValue, speedGlobalValue,
minOutput, maxOutput
} = this.elements
const { input, speedCheckbox, pitchCheckbox, range, thumb } = this.elements

const value = playbackRate ?? input.value
const pitchPreserved = preservesPitch ?? pitchCheckbox?.checked
Expand All @@ -163,17 +178,16 @@ export default class RangeSlider {
thumb.style.right = `${100 - percent}%`
range.style.right = `${100 - percent}%`

const { speedTrackValue, speedGlobalValue, minOutput, maxOutput } = this.elements

minOutput.textContent = `${input.min}x`
maxOutput.textContent = `${input.max}x`

if (speedCheckbox?.checked) {
speedGlobalValue.textContent = ` ${this.#padValue(value)}x`
} else {
speedTrackValue.textContent = ` ${this.#padValue(value)}x`
}
if (speedCheckbox?.checked) (speedGlobalValue.value = this.#padValue(value))
if (!speedCheckbox?.checked) (speedTrackValue.value = this.#padValue(value))

this.#video.playbackRate = value
this.#video.currentSpeed = value
this.#video.preservesPitch = pitchPreserved
this._video.playbackRate = value
this._video.currentSpeed = value
this._video.preservesPitch = pitchPreserved
}
}
2 changes: 1 addition & 1 deletion src/models/snip/snip.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export default class Snip {
async _share() {
const { startTime, endTime, playbackRate = '1.00', preservesPitch = true } = await this.read()
const pitch = preservesPitch ? 1 : 0
const rate = parseFloat(playbackRate) * 100
const rate = parseFloat(playbackRate) * 1000

const { tempEndTime = startTime, tempStartTime = endTime } = this.tempShareTimes

Expand Down
2 changes: 2 additions & 0 deletions src/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,7 @@ input[type=number]::-webkit-outer-spin-button {
width: 12px;
height: 12px;
border-radius: 50%;
cursor: grab;
}

.input[type="range"]::-webkit-slider-thumb {
Expand All @@ -255,6 +256,7 @@ input[type=number]::-webkit-outer-spin-button {
width: 12px;
height: 12px;
border-radius: 50%;
cursor: grab;
}

.slider>.thumb.hover {
Expand Down
2 changes: 1 addition & 1 deletion src/utils/higlight.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ const isHighlightable = ({
playbackRate = '1',
preservesPitch = true,
}) => (
isSnip || isSkipped || !preservesPitch || playbackRate !== '1'
isSnip || isSkipped || !preservesPitch || !['1', '1.000', '1000'].includes(playbackRate)
)

export const highlightElement = ({
Expand Down
4 changes: 3 additions & 1 deletion src/utils/song.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,9 @@ const getTrackId = row => {
const getArtists = row => {
const artistsList = row.querySelectorAll('span > div > a')
// Here means we are at artist page and can get name from h1
if (!artistsList.length) return document.querySelector('span[data-testid="entityTitle"] > h1').textContent
if (!artistsList.length) {
return document.querySelector('span[data-testid="entityTitle"] > h1')?.textContent || ''
}

return Array.from(artistsList).filter(artist => artist.href.includes('artist')).map(artist => artist.textContent).join(', ')
}

0 comments on commit 9ef8ef2

Please sign in to comment.