mirror of
https://github.com/forkless/Piperless.git
synced 2026-08-25 20:12:38 +02:00
Fix: FFmpeg Binaries Path now accepts directory-only paths (auto-appends /ffmpeg)
This commit is contained in:
@@ -255,6 +255,11 @@
|
||||
color: #50575e;
|
||||
}
|
||||
|
||||
.piperless-cache-badge--opus {
|
||||
background: #e3f2fd;
|
||||
color: #1565c0;
|
||||
}
|
||||
|
||||
.piperless-cache-badge--orphan {
|
||||
background: #fcf0f1;
|
||||
color: #b32d2e;
|
||||
|
||||
+66
-32
@@ -214,6 +214,54 @@
|
||||
let cacheSortKey = 'created';
|
||||
let cacheSortAsc = false;
|
||||
|
||||
/**
|
||||
* Build WordPress-style pagination bar with Previous / Next buttons
|
||||
* and page numbers. Renders a full .tablenav div.
|
||||
*
|
||||
* @param {number} current Current page.
|
||||
* @param {number} totalPages Total pages.
|
||||
* @param {number} totalItems Total items.
|
||||
* @return {string} HTML string, or empty string if only one page.
|
||||
*/
|
||||
function buildPaginationHtml( current, totalPages, totalItems ) {
|
||||
if ( totalPages <= 1 ) return '';
|
||||
|
||||
var html = '<div class="tablenav top" style="display:flex;align-items:center;justify-content:flex-end;gap:12px;margin-bottom:8px;">';
|
||||
html += '<div class="tablenav-pages" style="display:flex;align-items:center;gap:4px;">';
|
||||
html += '<span class="displaying-num" style="margin-right:8px;">' + totalItems + ' items</span>';
|
||||
|
||||
// First page button.
|
||||
html += '<a href="#" class="first-page button piperless-cache-page' + ( current === 1 ? ' disabled' : '' ) + '" data-page="1" aria-label="First page">«</a>';
|
||||
// Previous button.
|
||||
html += '<a href="#" class="prev-page button piperless-cache-page' + ( current === 1 ? ' disabled' : '' ) + '" data-page="' + ( current - 1 ) + '" aria-label="Previous page">‹</a>';
|
||||
|
||||
// Page numbers.
|
||||
html += '<span class="paging-input" style="display:flex;align-items:center;gap:2px;">';
|
||||
for ( var i = 1; i <= totalPages; i++ ) {
|
||||
if ( Math.abs( i - current ) <= 2 || i === 1 || i === totalPages ) {
|
||||
if ( i === current ) {
|
||||
html += '<span class="tablenav-paging-text"><strong>' + i + '</strong></span>';
|
||||
} else {
|
||||
html += '<a href="#" class="piperless-cache-page" data-page="' + i + '" style="text-decoration:none;padding:0 4px;">' + i + '</a>';
|
||||
}
|
||||
} else if ( i === 2 && current > 4 ) {
|
||||
html += '<span class="tablenav-paging-text">…</span>';
|
||||
} else if ( i === totalPages - 1 && current < totalPages - 3 ) {
|
||||
html += '<span class="tablenav-paging-text">…</span>';
|
||||
}
|
||||
}
|
||||
html += '</span>';
|
||||
|
||||
// Next button.
|
||||
html += '<a href="#" class="next-page button piperless-cache-page' + ( current === totalPages ? ' disabled' : '' ) + '" data-page="' + ( current + 1 ) + '" aria-label="Next page">›</a>';
|
||||
// Last page button.
|
||||
html += '<a href="#" class="last-page button piperless-cache-page' + ( current === totalPages ? ' disabled' : '' ) + '" data-page="' + totalPages + '" aria-label="Last page">»</a>';
|
||||
|
||||
html += '</div></div>';
|
||||
|
||||
return html;
|
||||
}
|
||||
|
||||
function loadCacheBrowser( page ) {
|
||||
const $browser = $( '#piperless-cache-browser' );
|
||||
$browser.html( '<p>' + 'Loading…' + '</p>' );
|
||||
@@ -223,6 +271,8 @@
|
||||
nonce: admin.nonce,
|
||||
page: page || 1,
|
||||
per_page: 15,
|
||||
sort_by: cacheSortKey,
|
||||
sort_order: cacheSortAsc ? 'asc' : 'desc',
|
||||
} ).done( function ( resp ) {
|
||||
if ( ! resp.success || ! resp.data ) {
|
||||
$browser.html( '<p>Failed to load cache entries.</p>' );
|
||||
@@ -236,6 +286,12 @@
|
||||
if ( d.total === 0 ) {
|
||||
html = '<p>No cached audio files.</p>';
|
||||
} else {
|
||||
// ── Pagination bar (top) ──
|
||||
var paginationHtml = buildPaginationHtml( cachePage, d.pages, d.total );
|
||||
if ( paginationHtml ) {
|
||||
html += paginationHtml;
|
||||
}
|
||||
|
||||
html += '<table class="wp-list-table widefat fixed striped">';
|
||||
html += '<thead><tr>';
|
||||
html += '<th><input type="checkbox" class="piperless-select-all"></th>';
|
||||
@@ -245,23 +301,7 @@
|
||||
html += '<th>Format</th><th>Model</th><th>Shortcode</th><th>Status</th><th>Actions</th>';
|
||||
html += '</tr></thead><tbody>';
|
||||
|
||||
// Apply client-side sort if active.
|
||||
let entries = d.entries;
|
||||
if ( cacheSortKey === 'size' ) {
|
||||
entries = entries.slice().sort( function ( a, b ) {
|
||||
return cacheSortAsc
|
||||
? ( a.size_bytes || 0 ) - ( b.size_bytes || 0 )
|
||||
: ( b.size_bytes || 0 ) - ( a.size_bytes || 0 );
|
||||
} );
|
||||
} else if ( cacheSortKey === 'created' ) {
|
||||
entries = entries.slice().sort( function ( a, b ) {
|
||||
const da = a.created || '';
|
||||
const db = b.created || '';
|
||||
return cacheSortAsc ? da.localeCompare( db ) : db.localeCompare( da );
|
||||
} );
|
||||
}
|
||||
|
||||
entries.forEach( function ( entry ) {
|
||||
d.entries.forEach( function ( entry ) {
|
||||
const sizeKB = ( entry.size_bytes / 1024 ).toFixed( 1 );
|
||||
const postIdCell = entry.post_id
|
||||
? '<a href="' + entry.edit_url + '">#' + entry.post_id + '</a>'
|
||||
@@ -272,9 +312,12 @@
|
||||
const bitrateSuffix = entry.bitrate ? ' · ' + entry.bitrate : '';
|
||||
const formatBadge = entry.orphaned
|
||||
? '<span class="piperless-cache-badge piperless-cache-badge--orphan">—</span>'
|
||||
: ( entry.has_mp3
|
||||
? '<span class="piperless-cache-badge piperless-cache-badge--ok">MP3' + bitrateSuffix + '</span>'
|
||||
: '<span class="piperless-cache-badge piperless-cache-badge--wav">WAV only</span>'
|
||||
: ( entry.has_opus
|
||||
? '<span class="piperless-cache-badge piperless-cache-badge--opus">Opus' + bitrateSuffix + '</span>'
|
||||
: ( entry.has_mp3
|
||||
? '<span class="piperless-cache-badge piperless-cache-badge--ok">MP3' + bitrateSuffix + '</span>'
|
||||
: '<span class="piperless-cache-badge piperless-cache-badge--wav">WAV only</span>'
|
||||
)
|
||||
);
|
||||
const statusBadge = entry.enabled
|
||||
? '<span class="piperless-cache-badge piperless-cache-badge--ok">Enabled</span>'
|
||||
@@ -300,18 +343,9 @@
|
||||
|
||||
html += '</tbody></table>';
|
||||
|
||||
// Pagination.
|
||||
if ( d.pages > 1 ) {
|
||||
html += '<div class="tablenav"><div class="tablenav-pages">';
|
||||
html += '<span class="displaying-num">' + d.total + ' items</span>';
|
||||
for ( let i = 1; i <= d.pages; i++ ) {
|
||||
if ( i === cachePage ) {
|
||||
html += '<span class="page-numbers current">' + i + '</span>';
|
||||
} else {
|
||||
html += '<a href="#" class="page-numbers piperless-cache-page" data-page="' + i + '">' + i + '</a>';
|
||||
}
|
||||
}
|
||||
html += '</div></div>';
|
||||
// ── Pagination bar (bottom) ──
|
||||
if ( paginationHtml ) {
|
||||
html += paginationHtml;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+11
-3
@@ -53,6 +53,7 @@
|
||||
|
||||
const [ generating, setGenerating ] = useState( false );
|
||||
const [ audioUrl, setAudioUrl ] = useState( null );
|
||||
const [ audioFormat, setAudioFormat ] = useState( 'mp3' );
|
||||
const [ audioDuration, setAudioDuration ] = useState( null );
|
||||
const [ models, setModels ] = useState( [] );
|
||||
const [ voices, setVoices ] = useState( [] );
|
||||
@@ -70,6 +71,7 @@
|
||||
.then( function ( data ) {
|
||||
if ( data.has_audio ) {
|
||||
setAudioUrl( data.url );
|
||||
setAudioFormat( data.format || 'mp3' );
|
||||
setAudioDuration( data.duration );
|
||||
}
|
||||
} )
|
||||
@@ -108,6 +110,7 @@
|
||||
} )
|
||||
.then( function ( data ) {
|
||||
setAudioUrl( data.url );
|
||||
setAudioFormat( data.format || 'mp3' );
|
||||
setAudioDuration( data.duration );
|
||||
setGenerating( false );
|
||||
createNotice( 'success', piperlessEditor.i18n.success, {
|
||||
@@ -243,7 +246,7 @@
|
||||
placeholder: '1.0',
|
||||
value: postMeta._piperless_length_scale || '',
|
||||
onChange: function ( val ) { updateMeta( '_piperless_length_scale', val ); },
|
||||
} )
|
||||
} ),
|
||||
),
|
||||
// ── Display Settings ────────────────────────────────────────
|
||||
createElement(
|
||||
@@ -283,9 +286,14 @@
|
||||
? createElement( 'div', null,
|
||||
createElement( 'audio', {
|
||||
controls: true,
|
||||
src: audioUrl,
|
||||
style: { width: '100%', marginBottom: '8px' },
|
||||
}, piperlessEditor.i18n.noAudio ),
|
||||
},
|
||||
createElement( 'source', {
|
||||
src: audioUrl,
|
||||
type: audioFormat === 'opus' ? 'audio/ogg' : 'audio/mpeg',
|
||||
} ),
|
||||
piperlessEditor.i18n.noAudio
|
||||
),
|
||||
audioDuration && createElement( 'p', {
|
||||
style: { color: '#757575', fontSize: '12px' },
|
||||
}, piperlessEditor.i18n.duration + ' ' + formatDuration( audioDuration ) )
|
||||
|
||||
Reference in New Issue
Block a user