diff --git a/Screenshot_20250827_214521.png b/Screenshot_20250827_214521.png new file mode 100644 index 0000000..41f631a Binary files /dev/null and b/Screenshot_20250827_214521.png differ diff --git a/internal/web/static/upload.js b/internal/web/static/upload.js index a89edb3..4382eb8 100644 --- a/internal/web/static/upload.js +++ b/internal/web/static/upload.js @@ -597,64 +597,108 @@ class GatewayUI { window.open(url, '_blank'); } - shareFile(hash, name) { - const baseUrl = window.location.origin; - const shareText = `${name}\n\nDownload: ${baseUrl}/api/download/${hash}\nStream: ${baseUrl}/api/stream/${hash}/playlist.m3u8\nTorrent: ${baseUrl}/api/torrent/${hash}`; - - if (navigator.clipboard && navigator.clipboard.writeText) { - navigator.clipboard.writeText(shareText).then(() => { - this.showToast('Share links copied to clipboard!', 'success'); - }); - } else { - // Fallback for older browsers - const textarea = document.createElement('textarea'); - textarea.value = shareText; - document.body.appendChild(textarea); - textarea.select(); - document.execCommand('copy'); - document.body.removeChild(textarea); - this.showToast('Share links copied to clipboard!', 'success'); + async shareFile(hash, name) { + try { + // Get file metadata to check for streaming info + const response = await fetch(`/api/metadata/${hash}`); + let fileData = null; + + if (response.ok) { + fileData = await response.json(); + } + + const baseUrl = window.location.origin; + const links = { + direct: `${baseUrl}/api/download/${hash}`, + torrent: `${baseUrl}/api/torrent/${hash}`, + magnet: `magnet:?xt=urn:btih:${hash}&dn=${encodeURIComponent(name)}` + }; + + // Add streaming links if available + if (fileData && fileData.streaming_info) { + links.stream = `${baseUrl}/api/stream/${hash}`; + links.hls = `${baseUrl}/api/stream/${hash}/playlist.m3u8`; + } + + this.showShareModal(name, links); + } catch (error) { + console.error('Failed to get file metadata:', error); + // Fallback to basic links + const baseUrl = window.location.origin; + const links = { + direct: `${baseUrl}/api/download/${hash}`, + torrent: `${baseUrl}/api/torrent/${hash}`, + magnet: `magnet:?xt=urn:btih:${hash}&dn=${encodeURIComponent(name)}` + }; + this.showShareModal(name, links); } } + showShareModal(fileName, links) { + const modal = document.getElementById('share-modal'); + const fileNameEl = document.getElementById('share-file-name'); + const linksContainer = document.getElementById('share-links'); + + if (!modal || !fileNameEl || !linksContainer) { + console.error('Share modal elements not found'); + return; + } + + fileNameEl.textContent = fileName; + + const linkTypes = [ + { key: 'direct', label: 'Direct Download', icon: '⬇️' }, + { key: 'torrent', label: 'Torrent File', icon: '🧲' }, + { key: 'magnet', label: 'Magnet Link', icon: '🧲' }, + { key: 'stream', label: 'Stream Video', icon: '▶️' }, + { key: 'hls', label: 'HLS Playlist', icon: '📺' } + ]; + + linksContainer.innerHTML = linkTypes + .filter(type => links[type.key]) + .map(type => ` + + `).join(''); + + modal.style.display = 'block'; + } + async deleteFile(hash, name) { - if (!confirm(`Are you sure you want to delete "${name}"?\n\nThis action cannot be undone.`)) { + if (!window.nostrAuth || !window.nostrAuth.isAuthenticated()) { + alert('You must be logged in to delete files'); return; } - + + if (!confirm(`Are you sure you want to delete "${name}"?`)) { + return; + } + try { - const headers = { - 'Accept': 'application/json' - }; - if (window.nostrAuth && window.nostrAuth.sessionToken) { - headers['Authorization'] = `Bearer ${window.nostrAuth.sessionToken}`; - } - - const response = await fetch(`/api/delete/${hash}`, { - method: 'DELETE', - headers: headers - }); - - if (response.ok) { - const result = await response.json(); - this.showToast(`File "${name}" deleted successfully!`, 'success'); - - // Remove from local storage if it exists + const result = await window.nostrAuth.deleteFile(hash); + if (result.success) { + // Remove from recent uploads this.recentUploads = this.recentUploads.filter(upload => upload.hash !== hash); - localStorage.setItem('recentUploads', JSON.stringify(this.recentUploads)); + this.saveRecentUploads(); - // Refresh the file list - this.loadServerFiles(); - } else { - const error = await response.json(); - this.showToast(`Failed to delete file: ${error.error?.message || 'Unknown error'}`, 'error'); + // Refresh file list + await this.loadServerFiles(); + + alert(`File "${name}" deleted successfully`); } } catch (error) { - console.error('Delete error:', error); - this.showToast(`Error deleting file: ${error.message}`, 'error'); + console.error('Delete failed:', error); + alert(`Failed to delete file: ${error.message}`); } } + + showToast(message, type = 'info') { const toast = document.createElement('div'); toast.className = `toast ${type}`; @@ -709,6 +753,39 @@ class GatewayUI { } } +// Global functions for share modal +async function copyToClipboard(text) { + try { + await navigator.clipboard.writeText(text); + // Show a temporary success message + const copyBtn = event.target; + const originalText = copyBtn.textContent; + copyBtn.textContent = 'Copied!'; + copyBtn.style.backgroundColor = '#4CAF50'; + setTimeout(() => { + copyBtn.textContent = originalText; + copyBtn.style.backgroundColor = ''; + }, 2000); + } catch (error) { + console.error('Failed to copy to clipboard:', error); + // Fallback for older browsers + const textarea = document.createElement('textarea'); + textarea.value = text; + document.body.appendChild(textarea); + textarea.select(); + document.execCommand('copy'); + document.body.removeChild(textarea); + alert('Copied to clipboard!'); + } +} + +function closeShareModal() { + const modal = document.getElementById('share-modal'); + if (modal) { + modal.style.display = 'none'; + } +} + // Global functions for navigation and theme function showServices() { hideAllSections();