Add files via upload

Versions 1.2.6 Release, Guide, and Fixes.
This commit is contained in:
ragetrip 2025-09-10 04:10:42 -07:00 committed by GitHub
parent 10a8f99227
commit 638b2ad5fa
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 328 additions and 58 deletions

View file

@ -1,5 +1,13 @@
# Changelog
## 1.2.5 - Quality of life improvements
- Added **macOS** support.
- Added **Hotlink** support.
- Added **Re-scan Playlists** & **Re-scan playlist** features to Tab & Footer views.
- Added **Icons** in drop down selector for easy playlist type identification.
- Added **YouTube Privacy** toggle for privacy-enhanced domain on embeds to help with Error 153 issues.
## 1.2.5 - First aimed community release
- First aimed community release of **Audio Pluglist**.
- Added **External link** support.

136
FULLGUIDE.md Normal file
View file

@ -0,0 +1,136 @@
# Audio PlugList - How To
This guide walks you through setup, use, hotkeys, and common fixes for **Audio PlugList**.
It's very easy without the guild but full details are below if needed.
---
## Quick Start
1. In Obsidian, go to **Settings → Community plugins → Audio PlugList → Enable**.
- **Alternative Method** - If installing via **BRAT**: Select **Add beta plugin**, then enter the repo address: https://github.com/ragetrip/audio-pluglist and select the latest release.
- **Alternative Method** - If manual install. Simply download the latest release (main.js, manifest.json, and styles.css) and unzip into your vault at **.obsidian/plugins/audio-pluglist**
2. Open the plugins **Tab view** (the sidebar view), or use the **footer mini-player**.
3. Create at least one playlist:
- **Folder playlist (📂)**: points to a local folder of audio files in your vault.
- **Link playlist (🔗)**: paste a playlist URL (YouTube, SoundCloud, Spotify, etc.).
> Tip: In dropdowns, folder playlists are prefixed **📂**, link playlists are **🔗** (only in dropdowns; names in Settings remain clean).
---
## Creating Playlists
### 📂 Folder-based
- In **Settings → Audio PlugList**, click **Add Playlist From Folder**.
- Choose a folder in your vault containing audio files.
- Name the playlist.
**Behavior**
- Full control via the plugins `<audio>` element.
- Supports autoplay, hotkeys, and seek/skip (depending on your UI config).
### 🔗 Link-based
- In **Settings → Audio PlugList**, click **Add Playlist From Link**.
- Paste a share link to a playlist (YouTube, SoundCloud, Spotify, etc.).
- Name the playlist.
**Behavior**
- Renders an **embedded player** in the Tab view (iframe).
- Controls are provided by the service; browser policies may block autoplay.
- Optional **Open In Browser** launches the playlist in your default browser/app.
> Note: Some providers (e.g., Spotify without Premium SDK) only allow ~30s previews in embeds. “Open in Browser” is the recommended experience.
---
## Using the Footer Mini-Player
- Choose a playlist from the **footer dropdown** (📂/🔗 prefixes show type).
- Use the **Shuffle** and **Repeat** pills as desired.
- Footer controls fully manage **📂 folder** playlists.
- For **🔗 link** playlists, use the **Tab view** embed controls or **Open In Browser**.
---
## Using the Tab View
- Open Audio PlugList via Ribbon Icon (🎵) or via Commands.
- Select a playlist from the dropdown (📂/🔗 prefixes).
- For link based playlists, the embed renders in an **embed box**.
---
## Re-scan Options
- **Re-scan playlists (All)**: Refreshes all playlists (detect new tracks / update embeds).
- **Re-scan playlist (Single)**: In the Tab view, next to **Optional: Open In Browser**, click **Re-scan playlist** to refresh only the selected playlist.
---
## Hotkeys (Per-Playlist Commands)
**What you get**
- The plugin registers **one command per playlist** automatically:
- `Toggle Play/Pause - <Playlist Name>`
- Bind keys in **Obsidian Settings → Hotkeys** or from **Community plugins → Audio PlugList → Hotkeys**.
**Behavior**
- If a different playlist is active, the command switches to that playlist and toggles play/pause.
- After **adding/renaming** playlists, the plugin updates command labels and callbacks when settings are saved (or after a re-scan).
> Tip: If you reorder playlists and a binding seems off, open the plugin settings and re-scan. Commands refresh in place without losing your keybindings.
---
## Known Limitations (Embeds)
- **Autoplay & control** for 🔗 link playlists depend on the provider:
- YouTube/SoundCloud allow limited programmatic control; autoplay may still be blocked by browser policies.
- **Spotify** embeds without the Web Playback SDK are limited to **previews**. Full playback requires Premium + OAuth + SDK, which this plugin deliberately avoids (use **Open In Browser**).
- **Deezer** login overlays can block embed controls; when detected, use **Open In Browser**.
---
## Troubleshooting
### I cant enable the plugin (red error)
- Ensure your plugin folder contains exactly:
- `main.js`, `manifest.json`, `styles.css`.
- Confirm `manifest.json` has a valid `"version"` and `"minAppVersion"` that matches your Obsidian.
- If youve hand-edited `main.js`, check for missing braces/commas (use a linter or open dev tools).
- Restart Obsidian after replacing files or making changes to any of these three files.
### Audio keeps playing when I switch playlists between Footer/Tab
- Make sure you're running build 1.2.6 (current release at time of writing) or later, where switching playlists calls a universal stop (Footer audio pauses and Tab embeds are blanked).
- If an embed still keeps playing, open the Tab and pause/close the provider player; some providers buffer aggressively.
### My per-playlist hotkeys disappeared / look wrong
- Open **Settings → Audio PlugList** and click **re-scan**. Commands update in place without losing existing bindings.
- Re-bind only if you renamed and want a new label visible in Hotkeys search.
### Link playlist wont autoplay in the Tab
- This is expected in many browsers due to autoplay policies. Use the embeds native play button or **Open In Browser**.
### Deezer shows a login / blocked controls
- Use **Open In Browser**. Some Deezer embeds require an active session and wont play reliably inside the iframe.
---
## Support / Issues
- If you run into something odd:
- Copy the first error from **Developer Tools → Console** (View → Toggle Developer Tools).
- Note which provider youre using (YouTube, SoundCloud, Spotify, etc.).
- Include your Obsidian version and plugin version.
- Post this in the **Issues** section here: https://github.com/ragetrip/audio-pluglist/issues
---
## Feature Request / Suggestions
- If you'd like to suggest a feature or recommendation:
- Visit the Repo's **Discussions** section here: https://github.com/ragetrip/audio-pluglist/discussions
Happy listening!

View file

@ -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** (YouTube, Spotify, Deezer, SoundCloud, or External Media File), then control playback from a clean **tab view** and a compact **footer mini-player** with shuffle/repeat and optional fade-out stop.
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.
> **Version:** 1.2.5 · **Obsidian:** 1.5.0+ · **Platforms:** Desktop & Mobile
> **Version:** 1.2.6 - **Obsidian:** 1.5.0+ - **Platforms:** Desktop & Mobile
---
@ -10,43 +10,45 @@ Playlist-based audio player for Obsidian. Point a playlist at a vault **folder**
- **Playlists**
- Create from a **Folder** (recursively indexes supported audio files).
- Create from a **Link** (direct audio URL).
- Create from a **Link** (external site support).
- **Footer mini-player** with segmented controls (⏮ ⏯ ⏭ ⏹ 🔀 🔁), seek, volume, and a marquee **Now Playing** title.
- **Tab view** showing current playlist, track list, and playback controls.
- **Shuffle / Repeat** (Off · All · One).
- **Shuffle / Repeat** (Off - All - One).
- **Fade-out on Stop** with adjustable duration.
- **Optional columns**: show Artist and/or Album in the track list.
- **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.
- **Browser Button** for easy access to external links if wanted or needed.
**Supported formats:** `mp3`, `wav`, `m4a`, `flac`, `ogg`, `aac`.
---
## 📸 PREVIEW | Easily create playlists from internal library or external link
| Add Playlist from Library or Link | Name and Configure |
## 📸 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.5/Audio-Pluglist-MenuCreated-sc(1.2.5).png) | ![Settings](https://raw.githubusercontent.com/ragetrip/audio-pluglist/main/repo-assets/1.2.5/Audio-Pluglist-MenuCreation-sc(1.2.5).png) |
| ![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) |
---
## 📸 PREVIEW | Tab support, or Footer Mini-Player support (toggle mini-player on/off)
## 📸 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.5/Audio-Pluglist-TabMode-sc(1.2.5).png) | ![Settings](https://raw.githubusercontent.com/ragetrip/audio-pluglist/main/repo-assets/1.2.5/Audio-Pluglist-Footer-MiniPlayer-sc(1.2.5).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.2.6).png) |
---
## 📸 PREVIEW | Easy playlist access and external playlist support
| Playlist Drop Down | External Support |
## 📸 PREVIEW | Easy menu and hotlink support
| Settings | Hotlink Support |
| --- | --- |
| ![Settings](https://raw.githubusercontent.com/ragetrip/audio-pluglist/main/repo-assets/1.2.5/Audio-Pluglist-ExternalPlaylist-Selection-sc(1.2.5).png) | ![Settings](https://raw.githubusercontent.com/ragetrip/audio-pluglist/main/repo-assets/1.2.5/Audio-Pluglist-ExternalPlaylist-sc(1.2.5).png) |
| ![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) |
---
## 📦 Installation
### Option A: Manual (first GitHub upload)
### Option A: Manual
1. Download the latest release assets (`main.js`, `manifest.json`, `styles.css`) from this repository.
2. Create a folder inside your vault at:
`.obsidian/plugins/audio-pluglist/`
@ -90,27 +92,30 @@ After the plugin is accepted into the Obsidian Community Plugin store, youll
- **Folder** (for folder playlists) + **Browse** + **Scan now**
- **Link** (for link playlists)
- **Delete playlist**
- **Re-scan all playlists**
- **Show Album in titles**
- **Show Artist in titles**
- **Show Footer mini-player**
- **Fade out on Stop**
- **Fade duration (ms)**
- **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.
- **Show Artist in titles** - Based on local file data.
- **Show Footer mini-player** - Toggles Footer Mini-Player on/off.
- **Fade out on Stop** - Toggle to enable/disable a user configured fade out on Stop command.
- **Fade duration (ms)** - Adjust by ms to user preferred amount.
---
## 🔍 Known Limitations
- **External links**: Some linked playlists require **log-in**; some services block external playback.
- **External links**: Some linked playlists require **log-in**; some services block external playback. **Re-scan playlis(s)** feature added to help re-attempt broken links.
- **Mobile platforms** Behavior depends on OS media policies (e.g., background playback limits).
---
## 📝 Changelog
### 1.2.5 - Release Notes
### 1.2.6 - Release Notes
- First expected community release of **Audio PlugList**.
- Dynamic playlists (Folder/Link), footer mini-player, shuffle/repeat, fade-out stop, artist/album columns, and scan tools.
- **Hotkey support** for single command play/pause or external link call.
- Added **FULLGUIDE.md** for detailed guide and **troubleshooting tips**.
---

153
main.js
View file

@ -47,6 +47,17 @@ function getSpotifyPlaylistId(input){
}
function spotifyEmbedSrc(id){ return `https://open.spotify.com/embed/playlist/${id}`; }
function getDeezerPlaylistId(input){
try{
const u = new URL(input);
const m = u.pathname.match(/\/playlist\/(\d+)/i);
if (m) return m[1];
}catch(e){}
const rx = /deezer\.com\/(?:[a-z]{2}\/)?playlist\/(\d+)/i;
const m2 = (input||'').match(rx);
return m2 ? m2[1] : null;
}
function clamp(n, a, b){ if(n<a)return a; if(n>b)return b; return n; }
function fmtTime(s) {
@ -67,24 +78,17 @@ function parseArtistTitle(basename){
if (parts.length >= 2) return { artist: parts[0], title: parts.slice(1).join(' - ') };
return { artist: '', title: basename };
}
function fillPlaylistOptions(plugin, sel){
clearEl(sel);
if (!plugin.settings.playlists.length){
var opt = mk('option', '', 'No playlists');
opt.value = '-1';
sel.appendChild(opt);
sel.disabled = true;
return;
function fillPlaylistOptions(self, sel){
sel.innerHTML='';
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<pls.length;i++){
var cfg = pls[i]||{};
var name = (cfg.name||('Playlist '+(i+1)));
if (cfg.type==='folder') name = '📂 ' + name;
else if (cfg.type==='link') name = '🔗 ' + name;
var opt = document.createElement('option'); opt.value=String(i); opt.textContent=name; sel.appendChild(opt);
}
sel.disabled = false;
for (var i=0;i<plugin.settings.playlists.length;i++){
var p = plugin.settings.playlists[i] || {};
var label = (p.name && p.name.length) ? p.name : ('Playlist ' + (i+1));
var opt = mk('option', '', label);
opt.value = String(i);
sel.appendChild(opt);
}
}
/* Simple modal folder picker */
@ -270,10 +274,20 @@ SettingsTab.prototype.display = function(){
// Break line above "Re-scan all playlists" //
containerEl.createEl('div', { cls: 'apl-section-break' });
// Keep remaining settings area as-is for better grouping. Looks better in on smaller devices //
// Keep remaining settings area as-is for better grouping. Looks better in on smaller devices like iPad and mobile devices //
new Setting(containerEl)
.setName('Re-scan all playlists')
.addButton(function(btn){ btn.setButtonText('Scan All').onClick(() => self.plugin.indexAll()); });
.addButton(function(btn){ btn.setButtonText('Scan All').onClick(() => self.plugin.indexAll());
new Setting(containerEl)
.setName('YouTube privacy (youtube-nocookie.com)')
.setDesc('Use the privacy-enhanced domain for YouTube embeds. Helps avoid Error 153.')
.addToggle(t=>{
t.setValue(self.plugin.settings.youtubePrivacy === true)
.onChange(async v=>{ self.plugin.settings.youtubePrivacy = !!v; await self.plugin.saveSettings(); });
});
});
new Setting(containerEl)
.setName('Show Album in titles')
@ -338,7 +352,13 @@ View.prototype.render = function(){
col.appendChild(rowTop);
var sel = mk('select');
rowTop.appendChild(sel);
fillPlaylistOptions(this.plugin, sel); if (this.plugin.currentPlaylist>=0) sel.value = String(this.plugin.currentPlaylist);
fillPlaylistOptions(this.plugin, sel);
// Add refresh button next to playlist dropdown
var refreshBtn = mk('button','ap-refresh-btn','⟳');
refreshBtn.title = 'Re-scan playlists';
refreshBtn.onclick = function(){ try{ this.plugin.indexAll(); new Notice('Audio PlugList: Re-scanning playlists…'); }catch(e){} }.bind(this);
rowTop.appendChild(refreshBtn);
if (this.plugin.currentPlaylist>=0) sel.value = String(this.plugin.currentPlaylist);
sel.onchange = function(){ if (sel.value!=='-1') this.plugin.setCurrentPlaylist(Number(sel.value)); }.bind(this);
// Now playing title //
@ -403,6 +423,12 @@ var wrap = mk('div','ap-embedbox');
var btn = mk('button','ap-open-ext ap-open-ext--mini','Optional: Open In Browser');
btn.onclick = function(){ try{ window.open(_openSrc, '_blank'); }catch(e){} };
btnRow.appendChild(btn);
// Add single-playlist re-scan button (mini)
var resBtn = mk('button','ap-open-ext ap-open-ext--mini','Re-scan playlist');
resBtn.style.marginLeft = '8px';
resBtn.onclick = function(){ try{ var _cp = cp; this.plugin.indexPlaylist(_cp).then(()=>{ new Notice('Audio PlugList: re-scanned this playlist.'); if (this.plugin.onUiRefresh) this.plugin.onUiRefresh(); }); }catch(e){} }.bind(this);
btnRow.appendChild(resBtn);
col.appendChild(btnRow);
} catch(e){}
@ -523,7 +549,8 @@ module.exports = class AudioPlugList extends Plugin {
showArtist: false,
showFooter: true,
fadeOnStop: true,
fadeMs: 3000
fadeMs: 3000,
youtubePrivacy: true
}, await this.loadData());
this.tracksByPlaylist = Array.from({length: this.settings.playlists.length}, ()=>[]);
@ -532,8 +559,8 @@ module.exports = class AudioPlugList extends Plugin {
this.queue = [];
this.index = -1;
this.audio = new Audio();
this.shuffle = true; // default 'true' by request //
this.repeatMode = 'all'; // default 'all' by request //
this.shuffle = true; // default 'true' by user request //
this.repeatMode = 'all'; // default 'all' by user request //
this.onUiRefresh = null;
this.audio.addEventListener('ended', this._onEnded.bind(this));
@ -552,6 +579,9 @@ module.exports = class AudioPlugList extends Plugin {
this.addSettingTab(new SettingsTab(this.app, this));
// Register per-playlist hotkeys (one command per playlist)
this._registerPlaylistHotkeys();
if (this.settings.autoIndexOnLoad){
const run = async ()=>{ try{ await this.indexAll(); }catch(e){} };
if (this.app.workspace && this.app.workspace.onLayoutReady){ this.app.workspace.onLayoutReady(run); }
@ -567,7 +597,7 @@ module.exports = class AudioPlugList extends Plugin {
this.audio.pause(); this.audio.src = '';
}
async saveSettings(){ await this.saveData(this.settings); }
async saveSettings(){ await this.saveData(this.settings); try{ this._registerPlaylistHotkeys(); }catch(e){} }
async activateView(){
var leaves = this.app.workspace.getLeavesOfType(VIEW_TYPE);
@ -587,7 +617,8 @@ module.exports = class AudioPlugList extends Plugin {
var el = mk('div', 'ap-footer-player');
var sel = mk('select');
fillPlaylistOptions(this, sel); if (this.currentPlaylist>=0) sel.value = String(this.currentPlaylist);
fillPlaylistOptions(this, sel);
if (this.currentPlaylist>=0) sel.value = String(this.currentPlaylist);
sel.onchange = function(){ if (sel.value!=='-1') this.setCurrentPlaylist(Number(sel.value)); }.bind(this);
// Segmented controls ⏮ | ⏯ | ⏭ | ⏹ | 🔀 | 🔁 - some of these had to be done the way that are. Switched from 1.0.3 due to mobile and device view issues so below ones are different but working. //
@ -667,15 +698,72 @@ module.exports = class AudioPlugList extends Plugin {
});
}
setCurrentPlaylist(i){ if (!this.settings.playlists.length){ this.currentPlaylist=-1; this._applyPlaylistQueue(); if(this.onUiRefresh) this.onUiRefresh(); return; } this.currentPlaylist = clamp(i,0,this.settings.playlists.length-1);
setCurrentPlaylist(i){
if (!this.settings.playlists.length){
this.currentPlaylist = -1;
this._applyPlaylistQueue();
if (typeof this.onUiRefresh === 'function') this.onUiRefresh();
return;
}
var next = clamp(i,0,this.settings.playlists.length-1);
if (this.currentPlaylist !== next){
try{ this._stopAllPlayback(); }catch(_){ }
}
this.currentPlaylist = next;
this.settings.currentPlaylist = this.currentPlaylist;
this.saveSettings();
this._applyPlaylistQueue();
if (typeof this.onUiRefresh === 'function') this.onUiRefresh();
}
// Per-playlist Hotkeys //
togglePlaylistByIndex(i){
try{
i = Number(i);
if (!isFinite(i)) return;
if (i<0 || i >= (this.settings.playlists ? this.settings.playlists.length : 0)) return;
if (this.currentPlaylist !== i) this.setCurrentPlaylist(i);
this.togglePlay();
}catch(e){ try{console.error('APL togglePlaylistByIndex error', e);}catch(_){} }
}
_registerPlaylistHotkeys(){
try{
const cmdApi = (this.app && this.app.commands) ? this.app.commands : null;
const cmds = cmdApi && cmdApi.commands ? cmdApi.commands : {};
const pls = (this.settings && Array.isArray(this.settings.playlists)) ? this.settings.playlists : [];
for (let i=0;i<pls.length;i++){
const cfg = pls[i] || {};
const id = `apl-toggle-playlist-${i}`;
const label = `Toggle Play/Pause — ${cfg.name || ('Playlist ' + (i+1))}`;
if (!(cmds && cmds[id])){
this.addCommand({ id, name: label, callback: ()=> this.togglePlaylistByIndex(i) });
} else {
// Update name & callback in place so bindings persist //
try { cmds[id].name = label; } catch(_){}
try { cmds[id].callback = ()=> this.togglePlaylistByIndex(i); } catch(_){}
}
}
}catch(e){ try{console.error('APL _registerPlaylistHotkeys error', e);}catch(_){} }
}
// Indexing //
async indexAll(){ for (var i=0;i<this.settings.playlists.length;i++) await this.indexPlaylist(i); this._applyPlaylistQueue(); }
// Stop any active playback (internal audio + external embeds) //
_stopAllPlayback(){
try{
if (this.audio){ try{ this.audio.pause(); }catch(_){ } try{ this.audio.currentTime = 0; }catch(_){ } }
try{
var frames = document.querySelectorAll('.ap-embedbox iframe');
frames.forEach(function(fr){ try{ fr.src = 'about:blank'; }catch(_){ } });
}catch(_){ }
}catch(_){ }
try{ if (this.onUiRefresh) this.onUiRefresh(); }catch(_){ }
}
async indexAll(){ for (var i=0;i<this.settings.playlists.length;i++) await this.indexPlaylist(i); this._applyPlaylistQueue(); }
async indexPlaylist(i){
var cfg = this.settings.playlists[i] || {};
// LINK-based playlist support //
@ -690,7 +778,7 @@ module.exports = class AudioPlugList extends Plugin {
var ytid = getYouTubePlaylistId(link);
if (ytid){
this.tracksByPlaylist[i] = [];
this.embedByPlaylist[i] = { provider:'youtube', src: ytPlaylistEmbedSrc(ytid), height: 380, original: link };
this.embedByPlaylist[i] = { provider:'youtube', src: (self?self.plugin.settings.youtubePrivacy:this.settings.youtubePrivacy) ? `https://www.youtube-nocookie.com/embed/videoseries?list=${encodeURIComponent(ytid)}&rel=0&modestbranding=1&enablejsapi=1` : `https://www.youtube.com/embed/videoseries?list=${encodeURIComponent(ytid)}&rel=0&modestbranding=1&enablejsapi=1`, height: 480, original: link };
new Notice('Audio PlugList: embedded YouTube playlist.');
return;
}
@ -711,6 +799,15 @@ module.exports = class AudioPlugList extends Plugin {
this.embedByPlaylist[i] = { provider:'spotify', src: spotifyEmbedSrc(spid), height: 380, original: link };
new Notice('Audio PlugList: embedded Spotify playlist.');
return;
// Deezer playlist (no iframe embed; open externally due to login overlay) //
var dzid = getDeezerPlaylistId(link);
if (dzid){
this.tracksByPlaylist[i] = []; // avoid trying to parse tracks here
this.embedByPlaylist[i] = null; // no embed; rely on action row buttons
try { new Notice('Deezer playlist detected. Use "Open In Browser" to play.'); } catch(e) {}
return;
}
}
// Direct audio URL //

View file

@ -1,9 +1,9 @@
{
"id": "audio-pluglist",
"name": "Audio PlugList",
"version": "1.2.5",
"version": "1.2.6",
"minAppVersion": "1.5.0",
"description": "Create playlists from folders, files, or links (YouTube/SoundCloud/Spotify/direct audio). Tab view + footer controls.",
"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",

View file

@ -11,7 +11,7 @@
border-top:1px solid var(--background-modifier-border);
background:var(--background-primary);
z-index:1000;
width:50vw;
width:52vw;
}
.ap-footer-player select{ font-size:12px }
.ap-footer-player .ap-title{ position:relative; overflow:hidden; white-space:nowrap; width:26ch; max-width:26ch; }
@ -198,7 +198,7 @@
.ap-diag-panel { margin-top: 6px; padding: 6px; border: 1px dashed var(--background-modifier-border); border-radius: 6px; font-size: 0.85em; }
.ap-diag-line { margin: 2px 0; word-break: break-all; }
.ap-embedbox{min-height:180px}
.ap-embedbox{height:205px} /* set at 205px for youtube tracklist so you can see track2 to skip in case of error 153 */
.ap-embedbox iframe{display:block;width:100%;height:100%}
/* Make repeat pill match shuffle pill */
@ -222,8 +222,32 @@
height: 14px;
}
/* APL footer: Better alignment for the repeat button that carries over to smaller hardware/devices */
/* APL footer: Used for smaller hardware/devices */
.ap-footer-player .ap-footer-group button[title^="Repeat"] {
padding-left: 4px !important;
padding-right: 16px !important;
}
padding-right: 10px !important;
}
/* small refresh button next to playlist dropdowns */
.ap-refresh-btn{
margin-left: 8px;
padding: 2px 8px;
height: 24px;
line-height: 20px;
border: 1px solid var(--background-modifier-border);
border-radius: 6px;
background: var(--background-secondary);
cursor: pointer;
}
.ap-refresh-btn:hover{ background: var(--background-modifier-hover); }
/* Balance shuffle/repeat pill widths */
.ap-shuffle button, .ap-shuffle {
padding-left: 6px !important;
padding-right: 6px !important;
}
.ap-repeat button, .ap-repeat {
padding-left: 6px !important;
padding-right: 6px !important;
}

View file

@ -1,3 +1,3 @@
{
"1.2.5": "1.5.0"
}
"1.2.6": "1.5.0"
}