Skip to content

Commit

Permalink
feat: FireFox Port & Release Artifacts (#94)
Browse files Browse the repository at this point in the history
* refactor: remove insertAdjacentHTML calls

* refactor: get attributes using getAttribute()

* styles: add firefox prefixes to stylesheet

* refactor: add guards and mark async functions

* refactor: Dispatcher & content-script messaging

* fix: wait until video available before load

* build: separate chrome & firefox manifest.json

* build: move extension files into src directory

* chore: remove base manifest.json

* build: reset chrome manifest.json background key

* styles: ungroup moz & webkit thumb styles

* chore: ignore unzipped folders

* ci: update release to include firefox artifact

* build: set firefox min version to 109.0

* chore: correct versions to 1.5.1
  • Loading branch information
cdrani authored Sep 1, 2023
1 parent 9a9c1de commit 652ffb4
Show file tree
Hide file tree
Showing 58 changed files with 234 additions and 92 deletions.
20 changes: 16 additions & 4 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,14 @@ jobs:

- name: Update Version
if: steps.semver.outputs.version != ''
run: jq --arg version "${{ steps.semver.outputs.version }}" '.version = $version' manifest.json > tmp && mv tmp manifest.json
run: |
jq --arg version "${{ steps.semver.outputs.version }}" \
'.version = $version' chrome/manifest.json > chrome/tmp && \
mv chrome/tmp chrome/manifest.json
jq --arg version "${{ steps.semver.outputs.version }}" \
'.version = $version' firefox/manifest.json > firefox/tmp && \
mv firefox/tmp firefox/manifest.json
- name: Commit Changes
if: steps.semver.outputs.version != ''
Expand Down Expand Up @@ -51,23 +58,28 @@ jobs:

- name: Archive Extension Files
if: steps.semver.outputs.version != ''
run: zip -r Chorus.zip . -x "*.git*" "*.*rc" "*.md"
run: |
(cd src && zip -r ../Chorus-Chrome.zip .)
(cd chrome && zip -j ../Chorus-Chrome.zip manifest.json)
(cd src && zip -r ../Chorus-FireFox.zip .)
(cd firefox && zip -j ../Chorus-FireFox.zip manifest.json)
- name: Create Release Archive & Notes
if: steps.semver.outputs.version != ''
uses: ncipollo/release-action@v1.12.0
with:
artifacts: 'Chorus.zip'
tag: ${{ steps.semver.outputs.git_tag }}
name: ${{ steps.semver.outputs.git_tag }}
body: ${{ steps.semver.outputs.notes }}
artifacts: 'Chorus-Chrome.zip,Chorus-FireFox.zip'

- name: Upload & Publish
if: steps.semver.outputs.version != ''
uses: cdrani/chrome-extension-upload@ci/silent-update-fail
with:
silent-fail: true
file-path: Chorus.zip
file-path: Chorus-Chrome.zip
client-id: ${{ secrets.CLIENT_ID }}
extension-id: ${{ secrets.EXTENSION_ID }}
client-secret: ${{ secrets.CLIENT_SECRET }}
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
*.zip
*.DS_STORE
Chorus-Chrome
Chorus-FireFox
File renamed without changes.
37 changes: 0 additions & 37 deletions content-script.js

This file was deleted.

20 changes: 0 additions & 20 deletions events/dispatcher.js

This file was deleted.

63 changes: 63 additions & 0 deletions firefox/manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
{
"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.5.1",
"manifest_version": 3,
"author": "cdrani",
"action": {},
"icons": {
"16": "icons/icon16.png",
"24": "icons/icon24.png",
"48": "icons/icon48.png",
"64": "icons/icon64.png",
"128": "icons/icon128.png"
},
"content_scripts": [
{
"run_at": "document_idle",
"js": [
"utils/state.js",
"content-script.js"
],
"css": [
"styles.css"
],
"matches": [
"*://open.spotify.com/*"
]
}
],
"web_accessible_resources": [
{
"matches": [
"*://open.spotify.com/*"
],
"resources": [
"utils/*.js",
"models/*.js",
"events/*.js",
"components/*.js",
"observers/*.js",
"stores/*.js",
"actions/*.js",
"data/*.js"
]
}
],
"permissions": [
"activeTab",
"tabs",
"storage",
"unlimitedStorage"
],
"background": {
"scripts": ["background.js"]
},
"browser_specific_settings": {
"gecko": {
"id": "chorus@cdrani.dev",
"strict_min_version": "109.0"
}
}
}
10 changes: 8 additions & 2 deletions actions/init.js → src/actions/init.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,11 +91,17 @@ class App {
}
}

let loaded = false
const video = spotifyVideo.element

const setup = setInterval(async () => {
const nowPlayingWidget = document.querySelector('[data-testid="now-playing-widget"]')
if (!nowPlayingWidget) return
if (!video && !nowPlayingWidget) return

await load()
if (!loaded) {
await load()
loaded = true
}
clearInterval(setup)
}, 500)

Expand Down
16 changes: 11 additions & 5 deletions actions/main.js → src/actions/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import Chorus from '../models/chorus.js'

import { createAlert } from '../components/alert.js'

import { parseNodeString } from '../utils/parser.js'

export default class Main {
#icon
#snip
Expand All @@ -29,9 +31,10 @@ export default class Main {

if (!iconListContainer) return

iconListContainer.insertAdjacentHTML('beforeend', root)
this.#setIconListener()
const rootEl = parseNodeString(root)
iconListContainer.appendChild(rootEl)

this.#setIconListener()
clearInterval(interval)
}, 50)
}
Expand All @@ -43,10 +46,13 @@ export default class Main {
}

#setupAlert() {
document.body.insertAdjacentHTML('beforeend', createAlert())
const alertEl = parseNodeString(createAlert())
document.body.appendChild(alertEl)

const closeAlert = document.getElementById('chorus-alert-close-button')
closeAlert?.addEventListener('click', (e) => this.#handleAlert({ e, target: closeAlert }))
const closeAlertButton = document.getElementById('chorus-alert-close-button')
closeAlertButton?.addEventListener('click', (e) => {
this.#handleAlert({ e, target: closeAlertButton })
})
}

get element() {
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
52 changes: 52 additions & 0 deletions src/content-script.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
const loadScript = filePath => {
const script = document.createElement('script')
script.src = chrome.runtime.getURL(filePath)
script.type = 'module'
document.body.appendChild(script)
}

loadScript('actions/init.js')


const sendEventToPage = ({ eventType, detail }) => {
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 '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)
sendEventToPage({ eventType: 'storage.get.response', detail: response })
break

case 'storage.delete':
response = await removeState(payload.key)
sendEventToPage({ eventType: 'storage.delete.response', detail: response })
break

case 'storage.populate':
response = await getState(null)
sendEventToPage({ eventType: 'storage.populate.response', detail: response })
break
}
})

chrome.runtime.onMessage.addListener(message => {
sendEventToPage({ eventType: 'app.enabled', detail: { enabled: message.enabled } })
})
File renamed without changes.
34 changes: 34 additions & 0 deletions src/events/dispatcher.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
export default class Dispatcher {
constructor() {
this.#initListener()
}

#initListener() {
window.addEventListener('message', (event) => {
if (event.origin !== window.location.origin) return

if (event?.data?.type === 'FROM_CONTENT_SCRIPT') {
document.dispatchEvent(
new CustomEvent(event.data.requestType, { detail: event.data.payload })
)
}
})
}

sendEvent({ eventType, detail = {} }) {
window.postMessage({
type: 'FROM_PAGE_SCRIPT',
requestType: eventType,
payload: detail
}, window.location.origin)

return new Promise((resolve) => {
const resultListener = (e) => {
resolve(e.detail)
document.removeEventListener(`${eventType}.response`, resultListener)
}

document.addEventListener(`${eventType}.response`, resultListener)
})
}
}
File renamed without changes.
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
10 changes: 6 additions & 4 deletions models/chorus.js → src/models/chorus.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { createSnipControls } from '../components/snip/snip-controls.js'
import { createSpeedControls } from '../components/speed/speed-controls.js'

import { parseNodeString } from '../utils/parser.js'

export default class Chorus {
get isShowing() {
if (!this.mainElement) return false
Expand All @@ -27,11 +29,11 @@ export default class Chorus {
#insertIntoDOM() {
if (this.#hasSnipControls) return

const snipControls = createSnipControls()
const speedControls = createSpeedControls()
const snipControlsEl = parseNodeString(createSnipControls())
const speedControlsEl = parseNodeString(createSpeedControls())

this.chorusControls.insertAdjacentHTML('beforeend', snipControls)
this.chorusControls.insertAdjacentHTML('beforeend', speedControls)
this.chorusControls.appendChild(snipControlsEl)
this.chorusControls.appendChild(speedControlsEl)
}

hide() {
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -66,32 +66,34 @@ export default class TrackList {
if (!song) return

this.#events.forEach(event => {
row?.addEventListener(event, () => {
const snipInfo = this.#snipIcon.getTrack(song.id)
row?.addEventListener(event, async () => {
const snipInfo = await this.#snipIcon.getTrack(song.id)
const icons = this.#getRowIcons(row)
const keys = { snip: 'isSnip', skip: 'isSkipped' }

icons.forEach(icon => {
icon.style.visibility = this.#visibleEvents.includes(event) ? 'visible' : 'hidden'
this.#snipIcon._burn({ icon, burn: snipInfo[keys[icon.role]] })
this.#snipIcon._glow({ icon, glow: snipInfo[keys[icon.role]] })
const role = icon.getAttribute('role')
this.#snipIcon._burn({ icon, burn: snipInfo[keys[role]] })
this.#snipIcon._glow({ icon, glow: snipInfo[keys[role]] })
})
})
})
}

#handleClick = async e => {
const target = e.target
const role = target?.getAttribute('role')

if (['snip', 'skip'].includes(target?.role)) {
if (['snip', 'skip'].includes(role)) {
let row = target.parentElement
do {
row = row.parentElement
} while (row.dataset.testid != 'tracklist-row')

const currentIndex = row.parentElement.ariaRowIndex
const currentIndex = row.parentElement.getAttribute('aria-row-index')

if (target.role == 'snip') {
if (role == 'snip') {
if (!this.#previousRowNum || (currentIndex != this.#previousRowNum)) {
this.#chorus.show()
this.#trackSnip.init(row)
Expand Down
Loading

0 comments on commit 652ffb4

Please sign in to comment.