Do not auto-download enclosures that are not audio or video
Blog feeds put each article's header image in an <enclosure>, so a text feed read as a podcast full of episodes: 149 images, 74 MB across 11 feeds. media_types defaults to audio and video, with a per-feed override. Such enclosures stay listed and stay downloadable by hand; the row names what it is rather than saying "skipped". An unknown type is allowed, since the real type is only known after downloading, and a torrent is allowed as a container judged once unpacked. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AdXho5tTkjFLeUXKbEjKBh
This commit is contained in:
@@ -606,7 +606,8 @@ function epEl(e){
|
||||
${num?`<span>${num}</span><span class="dot"></span>`:''}
|
||||
<span>${dateOf(e.published)}</span>
|
||||
${left?'<span class="dot"></span><span>'+left+'</span>':''}
|
||||
${enc?`<span class="dot"></span><span class="chip ${esc(enc.state)}">${has?'downloaded':esc(enc.state)}</span>`:''}
|
||||
${enc?`<span class="dot"></span><span class="chip ${esc(enc.state)}">${
|
||||
has?'downloaded':(enc.state==='skipped'?kindOf(enc):esc(enc.state))}</span>`:''}
|
||||
${enc&&enc.length?`<span>${mb(enc.length)}</span>`:''}
|
||||
${e.flagged?'<span class="dot"></span><span>★ kept</span>':''}
|
||||
</div>
|
||||
@@ -615,7 +616,8 @@ function epEl(e){
|
||||
</div>
|
||||
<div class="rowacts">
|
||||
${has?`<button class="iconbtn" data-a="play" title="Play">▶</button>`:
|
||||
(enc?`<button class="iconbtn" data-a="get" title="Download">⤓</button>`:'')}
|
||||
(enc?`<button class="iconbtn" data-a="get" title="Download this ${
|
||||
enc.state==='skipped'?kindOf(enc):'file'}">⤓</button>`:'')}
|
||||
<button class="iconbtn" data-a="flag" title="${e.flagged?'Stop keeping':'Keep (never auto-delete)'}">${e.flagged?'★':'☆'}</button>
|
||||
<button class="iconbtn" data-a="read" title="Mark ${e.read?'unread':'read'}">${e.read?'○':'●'}</button>
|
||||
${has?`<button class="iconbtn" data-a="del" title="Delete file">🗑</button>`:''}
|
||||
@@ -630,6 +632,18 @@ function epEl(e){
|
||||
if(S.open.has(e.guid)) showNotes(e,el);
|
||||
return el;
|
||||
}
|
||||
/// What an enclosure is, for a row that is not an episode: "image", "pdf", "document".
|
||||
function kindOf(enc){
|
||||
const m=(enc.mime||'').toLowerCase();
|
||||
if(m.startsWith('image/')) return 'image';
|
||||
if(m.startsWith('video/')) return 'video';
|
||||
if(m.startsWith('audio/')) return 'audio';
|
||||
if(m.includes('pdf')) return 'pdf';
|
||||
if(m.includes('torrent')) return 'torrent';
|
||||
const ext=(enc.url||'').split('?')[0].split('.').pop();
|
||||
return (ext && ext.length<=5) ? ext.toLowerCase() : 'file';
|
||||
}
|
||||
|
||||
function feedArt(){ const f=S.feeds.find(x=>x.id===S.feed); return f&&f.image; }
|
||||
|
||||
function toggleNotes(e,el){
|
||||
@@ -937,6 +951,11 @@ async function prefsModal(){
|
||||
<span class="hint">Applies to any feed that does not set its own — including every feed
|
||||
inside an OPML subscription. <b>0 means unlimited</b>, which will pull a whole back
|
||||
catalogue the first time a feed is scanned.</span></div>
|
||||
<div class="field"><label>Download these media types automatically</label>
|
||||
<input type="text" id="gtypes" value="${esc((g.media_types||[]).join(', '))}"
|
||||
placeholder="audio, video">
|
||||
<span class="hint">Anything else is still listed and can be downloaded by hand — blog feeds
|
||||
put article images in enclosures, and those are not episodes. Empty takes everything.</span></div>
|
||||
<div class="field"><label>Disk quota (GB, 0 = unlimited)</label>
|
||||
<input type="number" id="gquota" min="0" step="0.5" value="${g.max_total_gb}">
|
||||
<span class="hint">Over this, the oldest played episodes are deleted first. Starred
|
||||
@@ -952,6 +971,7 @@ async function prefsModal(){
|
||||
await api('/api/settings',{method:'PATCH',body:JSON.stringify({
|
||||
schedule:`every ${Math.max(1,Number($('#gnum').value)||1)}${$('#gunit').value}`,
|
||||
max_new_per_check:Math.max(0,Number($('#gmax').value)||0),
|
||||
media_types:$('#gtypes').value.split(',').map(t=>t.trim()).filter(Boolean),
|
||||
max_total_gb:Number($('#gquota').value)||0,
|
||||
max_age_days:Number($('#gage').value)||0})});
|
||||
closeModal(); toast('Settings saved');
|
||||
|
||||
Reference in New Issue
Block a user