From db06f37eb2acd6eb267d9fd07fe182a97dda6e67 Mon Sep 17 00:00:00 2001 From: sleeperhit Date: Wed, 17 Dec 2025 00:43:43 -0800 Subject: [PATCH] Add files via upload --- CHANGELOG.md | 8 +- FULLGUIDE.md | 32 +++++ README.md | 26 +++- main.js | 391 +++++++++++++++++++++++++++++++++++++++++++------- manifest.json | 5 +- styles.css | 98 ++++++++++++- versions.json | 2 +- 7 files changed, 497 insertions(+), 65 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b7288b6..fad6bd2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## 1.3.2 - Community Submission Edits & EQ Feature +- Added **EQ** with default and 3 preset that can be edited. +- Cleaned up main.js and styles.css to **Community Submission** standard. +- Updated ribbon and tab **icons**. + + ## 1.2.6 - Quality of life improvements - Added **macOS** support. - Added **Hotlink** support. @@ -17,4 +23,4 @@ ## 1.0.3 - Initial public release - First GitHub release of **Audio PlugList**. -- Features: Folder/Link playlists, footer mini-player, shuffle/repeat, fade-out stop, artist/album columns, and scan tools. +- Features: Folder/Link playlists, footer mini-player, shuffle/repeat, fade-out stop, artist/album columns, and scan tools. \ No newline at end of file diff --git a/FULLGUIDE.md b/FULLGUIDE.md index 907ec21..15dd6b7 100644 --- a/FULLGUIDE.md +++ b/FULLGUIDE.md @@ -83,6 +83,38 @@ It's very easy without the guild but full details are below if needed. --- +## Equalizer (EQ) + +Audio PlugList includes a built-in **10-band equalizer** designed for **folder-based playlists** played through the plugin’s internal audio player. The EQ is intentionally lightweight, menu-driven, and persistent across sessions. + +> Note: The EQ does **not** affect link-based or embedded playlists (YouTube, SoundCloud, Spotify, etc.), as those are rendered via provider iframes and cannot be processed locally. + +### EQ Presets + +The EQ supports multiple presets plus a bypass option: + +- **None** — EQ disabled (no processing) +- **Preset 0 – Default** — Flat response (all bands at 0 dB) +- **Preset 1 – Warm** — Gentle low-end and low-mid emphasis +- **Preset 2 – Bright** — Increased clarity and presence +- **Preset 3 – V-Curve** — Boosted lows/highs with reduced mids + +All presets are fully editable. + +### Editing EQ Settings + +EQ settings are managed from **Settings → Audio PlugList → Custom Equalizer Settings**. +Each preset uses **10 comma-separated gain values** corresponding to the following frequency bands: + +`32, 62, 128, 250, 500, 1000, 2000, 4000, 8000, 16000 Hz` + +Positive values boost, negative values cut. A preview graph displays the current EQ curve, and each preset includes a **Reset** button to restore its defaults. + +### EQ Toggle Button + +An **EQ toggle button** appears to the right of **Repeat** in both the **Tab view** and the **Footer mini-player**. Clicking the button cycles through presets in order, while hovering shows the currently active preset. This allows quick EQ switching without opening the Settings panel. + + ## Known Limitations (Embeds) - **Autoplay & control** for 🔗 link playlists depend on the provider: diff --git a/README.md b/README.md index d7b6f3f..817ce47 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # Audio PlugList -Playlist-based audio player for Obsidian. Point a playlist at a vault **folder** (auto-index audio files), an external **link** (with multi site support), then control playback from a clean **tab view** and a compact **footer mini-player** with shuffle/repeat, optional fade-out stop, and hotkey support. +Playlist-based audio player for Obsidian. Point a playlist at a vault **folder** (auto-index audio files), an external **link** (with multi site support), then control playback from a clean **tab view** and a compact **footer mini-player** with shuffle/repeat, optional fade-out stop, EQ presets, and hotkey support. -> **Version:** 1.2.6 - **Obsidian:** 1.5.0+ - **Platforms:** Desktop & Mobile +> **Version:** 1.3.2 - **Obsidian:** 1.5.0+ - **Platforms:** Desktop & Mobile --- @@ -19,6 +19,7 @@ Playlist-based audio player for Obsidian. Point a playlist at a vault **folder** - **Quick re-scan**: index one playlist or **Scan All** from settings. - **File name parser**: `Artist - Title` (em dash or hyphen) convenience. - **Hotkey support** for assignable play/pause command per playlist. +- **EQ support** with bypass option and 3 editable presets. - **Browser Button** for easy access to external links if wanted or needed. **Supported formats:** `mp3`, `wav`, `m4a`, `flac`, `ogg`, `aac`. @@ -28,21 +29,21 @@ Playlist-based audio player for Obsidian. Point a playlist at a vault **folder** ## 📸 PREVIEW | Easily create playlists from internal library or external links | Library Based Playlist | External Link Based Playlist | | --- | --- | -| ![Settings](https://raw.githubusercontent.com/ragetrip/audio-pluglist/main/repo-assets/1.2.6/Audio-Pluglist-LibraryPlaylist-(1.2.6).png) | ![Settings](https://raw.githubusercontent.com/ragetrip/audio-pluglist/main/repo-assets/1.2.6/Audio-Pluglist-LinkPlaylist-(1.2.6).png) | +| ![Settings](https://raw.githubusercontent.com/ragetrip/audio-pluglist/main/repo-assets/1.2.6/Audio-Pluglist-LibraryPlaylist-(1.3.2).png) | ![Settings](https://raw.githubusercontent.com/ragetrip/audio-pluglist/main/repo-assets/1.2.6/Audio-Pluglist-LinkPlaylist-(1.2.6).png) | --- ## 📸 PREVIEW | Tab support, or Footer Mini-Player support (toggle mini-player on/off) with easy playlist selections | Tab View | Footer Only View | | --- | --- | -| ![Settings](https://raw.githubusercontent.com/ragetrip/audio-pluglist/main/repo-assets/1.2.6/Audio-Pluglist-PlaylistSelection-(1.2.6).png) | ![Settings](https://raw.githubusercontent.com/ragetrip/audio-pluglist/main/repo-assets/1.2.6/Audio-Pluglist-FooterMiniPlayer-(1.2.6).png) | +| ![Settings](https://raw.githubusercontent.com/ragetrip/audio-pluglist/main/repo-assets/1.2.6/Audio-Pluglist-PlaylistSelection-(1.2.6).png) | ![Settings](https://raw.githubusercontent.com/ragetrip/audio-pluglist/main/repo-assets/1.2.6/Audio-Pluglist-FooterMiniPlayer-(1.3.2).png) | --- -## 📸 PREVIEW | Easy menu and hotlink support +## 📸 PREVIEW | Easy menu with hotlink & EQ support | Settings | Hotlink Support | | --- | --- | -| ![Settings](https://raw.githubusercontent.com/ragetrip/audio-pluglist/main/repo-assets/1.2.6/Audio-Pluglist-Settings-(1.2.6).png) | ![Settings](https://raw.githubusercontent.com/ragetrip/audio-pluglist/main/repo-assets/1.2.6/Audio-Pluglist-HotkeySupport-(1.2.6).png) | +| ![Settings](https://raw.githubusercontent.com/ragetrip/audio-pluglist/main/repo-assets/1.2.6/Audio-Pluglist-Settings-(1.3.2).png) | ![Settings](https://raw.githubusercontent.com/ragetrip/audio-pluglist/main/repo-assets/1.2.6/Audio-Pluglist-HotkeySupport-(1.2.6).png) | --- @@ -92,6 +93,10 @@ After the plugin is accepted into the Obsidian Community Plugin store, you’ll - **Folder** (for folder playlists) + **Browse** + **Scan now** - **Link** (for link playlists) - **Delete playlist** +- **Custom Equilizer Settings** + - **Active Preset** (current default EQ) + - **EQ Table** (current editable presets) + - **NOTE:** (10 comma separated numbers w/Reset button to revert back to default) - **Re-scan all playlists** - Index local folder playlists, re-sync external link connections. Also available on Tab and Footer Mini-Player. - **YouTube privacy (youtube-nocookie.com)** - Assigns privacy-enhanced domain for youtube embeds to help with Error 153 from blocked youtube links. - **Show Album in titles** - Based on local file data. @@ -117,6 +122,15 @@ After the plugin is accepted into the Obsidian Community Plugin store, you’ll - **Hotkey support** for single command play/pause or external link call. - Added **FULLGUIDE.md** for detailed guide and **troubleshooting tips**. +### 1.3.2 - Release Notes +- Edits to comply with **Community Plugin** submission standards. +- Added **EQ** support for folder based playlists. Includes multiple presets plus a bypass option. +- Updated **Ribbon/Tab Icon**. +- Various bug cleanup. + - Dynamic title lock-up addressed. + - Footer player not updating current playlist on tab change addressed. + - Icon and pill adjustments for tablet users. + --- ## 🤝 Contributing diff --git a/main.js b/main.js index db5473c..c51c39d 100644 --- a/main.js +++ b/main.js @@ -7,8 +7,7 @@ NOTE: If this was helpful to you, please feel free to visit https://buymeacoffee Anything is appreciated and motivates to continue creating more useful plugins for the community. Thank you - Enjoy */ -const { Plugin, PluginSettingTab, Setting, ItemView, TFile, TFolder, Notice } = require('obsidian'); - +const { Plugin, PluginSettingTab, Setting, ItemView, TFile, TFolder, Notice, normalizePath } = require('obsidian'); const VIEW_TYPE = 'audio-pluglist-view'; const AUDIO_EXTS = { mp3:1, wav:1, m4a:1, flac:1, ogg:1, aac:1 }; @@ -79,7 +78,7 @@ function parseArtistTitle(basename){ return { artist: '', title: basename }; } function fillPlaylistOptions(self, sel){ - sel.innerHTML=''; + while (sel.firstChild) sel.removeChild(sel.firstChild); var pls = self.settings.playlists; var opt0 = document.createElement('option'); opt0.value='-1'; opt0.textContent='(no playlist selected)'; sel.appendChild(opt0); for (var i=0;i{ - b.setButtonText('Add Playlist From Folder').onClick(async ()=>{ + b.setButtonText('Add playlist from folder').onClick(async ()=>{ self.plugin.settings.playlists.push({ type:'folder', name:'', folderPath:'' }); self.plugin.tracksByPlaylist.push([]); if (!self.plugin.embedByPlaylist) self.plugin.embedByPlaylist = []; @@ -184,10 +175,10 @@ SettingsTab.prototype.display = function(){ // Link button // new Setting(addWrap) - .setName('From Link') + .setName('From link') .setDesc('Create a playlist from a link: YouTube playlist, SoundCloud track/set, Spotify playlist, or a direct audio URL (.mp3/.m4a/.wav/.ogg/.flac/.aac)') .addButton(b=>{ - b.setButtonText('Add Playlist From Link').onClick(async ()=>{ + b.setButtonText('Add playlist from link').onClick(async ()=>{ self.plugin.settings.playlists.push({ type:'link', name:'', link:'' }); self.plugin.tracksByPlaylist.push([]); if (!self.plugin.embedByPlaylist) self.plugin.embedByPlaylist = []; @@ -232,7 +223,7 @@ SettingsTab.prototype.display = function(){ .addText(function(t){ t.setPlaceholder('Browse to select...') .setValue((cfg.folderPath||'')) - .onChange(async (v) => { self.plugin.settings.playlists[idx].folderPath = (v||'').trim(); await self.plugin.saveSettings(); }); + .onChange(async (v) => { self.plugin.settings.playlists[idx].folderPath = normalizePath((v||'').trim()); await self.plugin.saveSettings(); }); }) .addButton(function(btn){ btn.setButtonText('Browse').onClick(async () => { @@ -271,6 +262,92 @@ SettingsTab.prototype.display = function(){ for (var i=0;i{ new Notice('Audio PlugList: re-scanned this playlist.'); if (this.plugin.onUiRefresh) this.plugin.onUiRefresh(); }); }catch(e){} }.bind(this); btnRow.appendChild(resBtn); @@ -437,14 +523,15 @@ btnRow.appendChild(resBtn); // Controls (hidden when an external embed is active) // var controls = null; if (!(activeEmbed && activeEmbed.src)) { controls = mk('div', 'ap-row ap-controls'); col.appendChild(controls); } - var prev = mk('button', '', 'Prev ◀︎◀︎'); prev.title='Previous'; - var play = mk('button', '', (this.plugin.audio.paused ? 'Play ▶︎' : 'Pause Ⅱ')); play.title='Play/Pause'; - var next = mk('button', '', 'Skip ▶︎▶︎'); next.title='Next'; + var prev = mk('button', '', 'Prev ◀︎◀︎'); prev.title='Previous track'; + var play = mk('button', '', (this.plugin.audio.paused ? 'Play ▶︎' : 'Pause Ⅱ')); play.title='Play/pause'; + var next = mk('button', '', 'Skip ▶︎▶︎'); next.title='Next track'; var stop = mk('button', '', 'Stop ■'); stop.title='Stop (fade)'; var shuffle = mk('button', '', this.plugin.shuffle ? 'Shuffle (ON)' : 'Shuffle'); shuffle.title='Shuffle'; var rptLabel = this.plugin.repeatMode === 'all' ? 'Repeat (All)' : (this.plugin.repeatMode === 'one' ? 'Repeat (One)' : 'Repeat'); var repeatBtn = mk('button', '', rptLabel); repeatBtn.title='Repeat mode'; - if (controls) { controls.appendChild(prev); controls.appendChild(play); controls.appendChild(next); controls.appendChild(stop); controls.appendChild(shuffle); controls.appendChild(repeatBtn); } + var eqBtn = mk('button', '', 'EQ'); eqBtn.title='Equalizer preset (click to cycle)'; + if (controls) { controls.appendChild(prev); controls.appendChild(play); controls.appendChild(next); controls.appendChild(stop); controls.appendChild(shuffle); controls.appendChild(repeatBtn); controls.appendChild(eqBtn); } if (controls) prev.onclick = function(){ this.plugin.prev(); }.bind(this); if (controls) play.onclick = function(){ this.plugin.togglePlay(); play.textContent = (this.plugin.audio.paused ? 'Play ▶︎' : 'Pause Ⅱ'); }.bind(this); @@ -455,6 +542,15 @@ btnRow.appendChild(resBtn); if (controls) repeatBtn.classList.toggle('is-active', this.plugin.repeatMode !== 'off'); if (controls) repeatBtn.onclick = function(){ this.plugin.cycleRepeat(); var lbl = this.plugin.repeatMode === 'all' ? 'Repeat (All)' : (this.plugin.repeatMode === 'one' ? 'Repeat (One)' : 'Repeat'); repeatBtn.textContent = lbl; repeatBtn.classList.toggle('is-active', this.plugin.repeatMode !== 'off'); }.bind(this); + // EQ preset cycle button // + if (controls) { + try{ this.plugin._aplSyncEqButtonState(eqBtn); }catch(_){} + eqBtn.onclick = function(){ + try{ this.plugin._aplCycleEqPreset(); }catch(_){} + try{ this.plugin._aplSyncEqButtonState(eqBtn); }catch(_){} + }.bind(this); + } + // Seek // var seekRow = null; if (!(activeEmbed && activeEmbed.src)) { seekRow = mk('div', 'ap-row ap-seek'); col.appendChild(seekRow); } @@ -550,7 +646,15 @@ module.exports = class AudioPlugList extends Plugin { showFooter: true, fadeOnStop: true, fadeMs: 3000, - youtubePrivacy: true + youtubePrivacy: true, +eqBands: [32,62,128,250,500,1000,2000,4000,8000,16000], +eqPresets: [ + [0,0,0,0,0,0,0,0,0,0], // Preset 0 — Default (Flat) + [3,2.5,1.5,0.5,0,-0.5,0,0.5,1,1.5], // Preset 1 — Warm + [0,0.5,1,1.5,3,3.5,4,3.5,2,1.5], // Preset 2 — Bright + [3,2.5,2,0.5,-1.5,-2,-0.5,1.5,2.5,2] // Preset 3 — V-Curve +], +activeEQ: "none", }, await this.loadData()); this.tracksByPlaylist = Array.from({length: this.settings.playlists.length}, ()=>[]); @@ -559,6 +663,9 @@ module.exports = class AudioPlugList extends Plugin { this.queue = []; this.index = -1; this.audio = new Audio(); +// Equalizer (menu-only; applies to local audio playback only) // +this._aplEq = { ctx: null, source: null, filters: null }; +try { this._aplInitEQ(this.audio); } catch(e) { try{console.error('APL EQ init failed', e);}catch(_){} } this.shuffle = true; // default 'true' by user request // this.repeatMode = 'all'; // default 'all' by user request // this.onUiRefresh = null; @@ -566,20 +673,20 @@ module.exports = class AudioPlugList extends Plugin { this.audio.addEventListener('ended', this._onEnded.bind(this)); // Ribbon icon // - this.addRibbonIcon('music', 'Audio PlugList', () => this.activateView()); + this.addRibbonIcon('cassette-tape', 'Audio PlugList', () => this.activateView()); this.registerView(VIEW_TYPE, (leaf) => new View(leaf, this)); this.addCommand({ id:'apl-open', name:'Open Audio PlugList', callback: () => this.activateView() }); - this.addCommand({ id:'apl-play-pause', name:'Play/Pause', callback: () => this.togglePlay() }); - this.addCommand({ id:'apl-next', name:'Next Track', callback: () => this.next() }); - this.addCommand({ id:'apl-prev', name:'Previous Track', callback: () => this.prev() }); - this.addCommand({ id:'apl-stop', name:'Stop (Fade Out)', callback: () => this.stopFade(3000) }); - this.addCommand({ id:'apl-rescan-all', name:'Re-scan All Playlists', callback: () => this.indexAll() }); + this.addCommand({ id:'apl-play-pause', name:'Play/pause', callback: () => this.togglePlay() }); + this.addCommand({ id:'apl-next', name:'Next track', callback: () => this.next() }); + this.addCommand({ id:'apl-prev', name:'Previous track', callback: () => this.prev() }); + this.addCommand({ id:'apl-stop', name:'Stop (fade out)', callback: () => this.stopFade(3000) }); + this.addCommand({ id:'apl-rescan-all', name:'Rescan all playlists', callback: () => this.indexAll() }); this.addSettingTab(new SettingsTab(this.app, this)); - // Register per-playlist hotkeys (one command per playlist) + // Register per-playlist hotkeys (one command per playlist) // this._registerPlaylistHotkeys(); if (this.settings.autoIndexOnLoad){ @@ -592,8 +699,8 @@ module.exports = class AudioPlugList extends Plugin { } onunload() { - this._detachFooter(); - this.app.workspace.detachLeavesOfType(VIEW_TYPE); + try{ this._aplDestroyEQ(); }catch(e){} +this._detachFooter(); this.audio.pause(); this.audio.src = ''; } @@ -630,6 +737,16 @@ module.exports = class AudioPlugList extends Plugin { var bShuf = controls.createEl('button', { cls:'ap-footer-seg', text:'🔀', title:'Shuffle' }); bShuf.onclick = ()=>{ this.toggleShuffle(); bShuf.classList.toggle('is-active', this.shuffle); }; var bRpt = controls.createEl('button', { cls:'ap-footer-seg', text:(this.repeatMode==='one'?'🔂':'🔁'), title:'Repeat' }); bRpt.onclick = ()=>{ this.cycleRepeat(); bRpt.textContent = (this.repeatMode==='one'?'🔂':'🔁'); bRpt.classList.toggle('is-active', this.repeatMode!=='off'); }; + + // EQ preset cycle button (0-3) // + var bEq = controls.createEl('button', { cls:'ap-footer-seg', text:'EQ', title:'Equalizer preset (click to cycle)' }); + this._aplEqFooterBtn = bEq; + try{ this._aplSyncEqButtonState(bEq); }catch(_){} + bEq.onclick = async () => { + try{ this._aplCycleEqPreset(); }catch(_){} + try{ this._aplSyncEqButtonState(bEq); }catch(_){} + }; + var seekWrap = mk('div', 'ap-seek'); var cur = mk('span','', '0:00'); var seek = mk('input'); seek.type='range'; seek.min='0'; seek.max='1000'; seek.value='0'; @@ -654,7 +771,7 @@ module.exports = class AudioPlugList extends Plugin { root.appendChild(el); this.footerEl = el; - // init active states only for shuffle/repeat + // init active states only for shuffle/repeat // if (this.shuffle) bShuf.classList.add('is-active'); if (this.repeatMode !== 'off') bRpt.classList.add('is-active'); @@ -671,7 +788,7 @@ module.exports = class AudioPlugList extends Plugin { this.audio.addEventListener('timeupdate', updateTime); this.audio.addEventListener('loadedmetadata', updateTime); } - _detachFooter(){ if (this.footerEl){ this.footerEl.remove(); this.footerEl = null; } } + _detachFooter(){ if (this.footerEl){ this.footerEl.remove(); this.footerEl = null; } this._aplEqFooterBtn = null; } _setFooterTitle(container, text){ if (this._footerTitleText === text && container._marqueeInitialized) return; @@ -737,7 +854,7 @@ module.exports = class AudioPlugList extends Plugin { for (let i=0;i this.togglePlaylistByIndex(i) }); } else { @@ -802,8 +919,8 @@ async indexAll(){ for (var i=0;i { + const f = ctx.createBiquadFilter(); + f.type = 'peaking'; + f.frequency.value = freq; + f.Q.value = 1.1; + f.gain.value = 0; + return f; + }); + + // Chain: source -> f0 -> ... -> f9 -> destination // + let chain = source; + for (let i=0;i { + try{ if (ctx && ctx.state === 'suspended') ctx.resume().catch(()=>{}); }catch(_){} + }); + }catch(_){} + + // Apply current preset // + this._aplApplyEQ(); +} + +_aplEqPresetName(i){ + try{ + const n = Number(i); + if (n === 0) return "Preset 0 — Default"; + if (n === 1) return "Preset 1 — Warm"; + if (n === 2) return "Preset 2 — Bright"; + if (n === 3) return "Preset 3 — V-Curve"; + }catch(_){} + return "Preset"; +} + +_aplSyncEqButtonState(btn){ + try{ + if (!btn) return; + const active = (this.settings && (this.settings.activeEQ !== undefined)) ? this.settings.activeEQ : "none"; + let idx = (active === "none" || active === null || active === undefined || active === "") ? null : Number(active); + if (idx === null || !isFinite(idx)) idx = null; + + const label = (idx === null) ? "EQ" : ("EQ" + idx); + btn.textContent = label; + + if (idx === null){ + btn.title = "Equalizer: None (click to cycle presets 0–3)"; + } else { + btn.title = "Equalizer: " + this._aplEqPresetName(idx) + " (click to cycle)"; + } + }catch(_){} +} + +_aplCycleEqPreset(){ + try{ + const active = (this.settings && (this.settings.activeEQ !== undefined)) ? this.settings.activeEQ : "none"; + let idx = (active === "none" || active === null || active === undefined || active === "") ? -1 : Number(active); + if (!isFinite(idx)) idx = -1; + + // cycle: none -> 0 -> 1 -> 2 -> 3 -> 0 ... // + idx = (idx < 0) ? 0 : ((idx + 1) % 4); + + this.settings.activeEQ = idx; + + // persist + apply // + try{ this.saveSettings(); }catch(_){} + try{ this._aplApplyEQ(); }catch(_){} + + // keep footer button in sync // + try{ if (this._aplEqFooterBtn) this._aplSyncEqButtonState(this._aplEqFooterBtn); }catch(_){} + }catch(e){ + try{ console.error("APL EQ cycle error", e); }catch(_){} + } +} + + +_aplDestroyEQ(){ + try{ + if (this._aplEq && this._aplEq.filters){ + try{ this._aplEq.filters.forEach(f=>{ try{ f.disconnect(); }catch(_){}}); }catch(_){} + } + if (this._aplEq && this._aplEq.source){ try{ this._aplEq.source.disconnect(); }catch(_){ } } + if (this._aplEq && this._aplEq.ctx){ try{ this._aplEq.ctx.close(); }catch(_){ } } + }catch(_){} + this._aplEq = { ctx:null, source:null, filters:null }; +} + +_aplApplyEQ(){ + try{ + if (!this._aplEq || !this._aplEq.filters) return; + + const filters = this._aplEq.filters; + const active = (this.settings && (this.settings.activeEQ !== undefined)) ? this.settings.activeEQ : "none"; + + // none => bypass (all gains 0) // + if (active === "none" || active === null || active === undefined){ + for (let i=0;i 15) clearInterval(timer); // ~12s + if (++count > 15) clearInterval(timer); // ~12s // }, 800); // observe future DOM changes (lightweight filter) // diff --git a/manifest.json b/manifest.json index aa9665b..0aa1220 100644 --- a/manifest.json +++ b/manifest.json @@ -1,11 +1,12 @@ { "id": "audio-pluglist", "name": "Audio PlugList", - "version": "1.2.6", + "version": "1.3.2", "minAppVersion": "1.5.0", "description": "Create playlists from folders, files, or external links. Tab view + footer controls. Hotlink support", "author": "Ragetrip", "authorUrl": "https://github.com/ragetrip", "fundingUrl": "https://buymeacoffee.com/ragetrip", - "isDesktopOnly": false + "isDesktopOnly": false, + "main": "main.js" } \ No newline at end of file diff --git a/styles.css b/styles.css index 270304d..7a26f56 100644 --- a/styles.css +++ b/styles.css @@ -222,12 +222,6 @@ height: 14px; } -/* APL footer: Used for smaller hardware/devices */ -.ap-footer-player .ap-footer-group button[title^="Repeat"] { - padding-left: 4px !important; - padding-right: 10px !important; -} - /* small refresh button next to playlist dropdowns */ .ap-refresh-btn{ margin-left: 8px; @@ -251,3 +245,95 @@ padding-left: 6px !important; padding-right: 6px !important; } + +/* === Audio PlugList EQ Styles (namespaced) === */ +.apl-eq-card{ + border:1px solid var(--background-modifier-border); + border-radius:10px; + padding:14px; + margin:16px 0 6px; + background: var(--background-primary); +} +.apl-eq-title{ font-size:1.05rem; font-weight:600; margin-bottom:2px; } +.apl-eq-sub{ font-size:0.8rem; opacity:0.75; margin:8px 0 12px; } +.apl-eq-row{ + display:grid; + grid-template-columns:160px 200px 1fr auto; + gap:12px; + align-items:center; + margin:10px 0; +} +.apl-eq-label{ font-size:0.85rem; font-weight:600; } +.apl-eq-graph{ + width:200px; + height:50px; + border:1px solid var(--background-modifier-border); + border-radius:6px; + background: var(--background-secondary); +} +.apl-eq-input{ + width:100%; + padding:6px 8px; + font-size:0.85rem; +} +.apl-eq-reset{ + padding:6px 10px; + font-size:0.85rem; +} + + +/* === APL modal (moved from JS inline styles for theme compatibility) === */ +.apl-modal-overlay{ + position: fixed; + inset: 0; + background: rgba(0,0,0,.4); + z-index: 10000; + display: flex; + align-items: center; + justify-content: center; +} +.apl-modal{ + background: var(--background-primary); + border: 1px solid var(--background-modifier-border); + border-radius: 8px; + min-width: 420px; + max-height: 70vh; + display: flex; + flex-direction: column; +} +.apl-modal-head{ + padding: 10px 12px; + border-bottom: 1px solid var(--background-modifier-border); + display: flex; + gap: 8px; + align-items: center; +} +.apl-modal-search{ + flex: 1; + margin-left: 8px; +} +.apl-modal-body{ + padding: 8px 12px; + overflow: auto; + display: flex; + flex-direction: column; + gap: 6px; +} +.apl-modal-footer{ + padding: 10px 12px; + border-top: 1px solid var(--background-modifier-border); + display: flex; + gap: 8px; + justify-content: flex-end; +} +.apl-modal-row{ + padding: 6px 8px; + border-radius: 6px; + cursor: pointer; +} +.apl-modal-row:hover{ + background: var(--background-modifier-hover); +} + +/* Mini rescan button spacing (moved from JS inline style) */ +.ap-open-ext--mini{ margin-left: 8px; } diff --git a/versions.json b/versions.json index 2ad9a6f..89f6369 100644 --- a/versions.json +++ b/versions.json @@ -1,3 +1,3 @@ { - "1.2.6": "1.5.0" + "1.3.2": "1.5.0" }