Compare commits
2 Commits
c57fea80eb
...
7ec39ff1e6
Author | SHA1 | Date | |
---|---|---|---|
7ec39ff1e6 | |||
5d89f5f1b6 |
BIN
Screenshot_20250827_214521.png
Normal file
BIN
Screenshot_20250827_214521.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 33 KiB |
@ -597,64 +597,108 @@ class GatewayUI {
|
|||||||
window.open(url, '_blank');
|
window.open(url, '_blank');
|
||||||
}
|
}
|
||||||
|
|
||||||
shareFile(hash, name) {
|
async shareFile(hash, name) {
|
||||||
const baseUrl = window.location.origin;
|
try {
|
||||||
const shareText = `${name}\n\nDownload: ${baseUrl}/api/download/${hash}\nStream: ${baseUrl}/api/stream/${hash}/playlist.m3u8\nTorrent: ${baseUrl}/api/torrent/${hash}`;
|
// Get file metadata to check for streaming info
|
||||||
|
const response = await fetch(`/api/metadata/${hash}`);
|
||||||
if (navigator.clipboard && navigator.clipboard.writeText) {
|
let fileData = null;
|
||||||
navigator.clipboard.writeText(shareText).then(() => {
|
|
||||||
this.showToast('Share links copied to clipboard!', 'success');
|
if (response.ok) {
|
||||||
});
|
fileData = await response.json();
|
||||||
} else {
|
}
|
||||||
// Fallback for older browsers
|
|
||||||
const textarea = document.createElement('textarea');
|
const baseUrl = window.location.origin;
|
||||||
textarea.value = shareText;
|
const links = {
|
||||||
document.body.appendChild(textarea);
|
direct: `${baseUrl}/api/download/${hash}`,
|
||||||
textarea.select();
|
torrent: `${baseUrl}/api/torrent/${hash}`,
|
||||||
document.execCommand('copy');
|
magnet: `magnet:?xt=urn:btih:${hash}&dn=${encodeURIComponent(name)}`
|
||||||
document.body.removeChild(textarea);
|
};
|
||||||
this.showToast('Share links copied to clipboard!', 'success');
|
|
||||||
|
// 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 => `
|
||||||
|
<div class="share-link">
|
||||||
|
<label>${type.icon} ${type.label}</label>
|
||||||
|
<div class="input-group">
|
||||||
|
<input type="text" value="${links[type.key]}" readonly>
|
||||||
|
<button onclick="copyToClipboard('${links[type.key].replace(/'/g, '\\\'')}')" class="copy-btn">Copy</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`).join('');
|
||||||
|
|
||||||
|
modal.style.display = 'block';
|
||||||
|
}
|
||||||
|
|
||||||
async deleteFile(hash, name) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!confirm(`Are you sure you want to delete "${name}"?`)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const headers = {
|
const result = await window.nostrAuth.deleteFile(hash);
|
||||||
'Accept': 'application/json'
|
if (result.success) {
|
||||||
};
|
// Remove from recent uploads
|
||||||
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
|
|
||||||
this.recentUploads = this.recentUploads.filter(upload => upload.hash !== hash);
|
this.recentUploads = this.recentUploads.filter(upload => upload.hash !== hash);
|
||||||
localStorage.setItem('recentUploads', JSON.stringify(this.recentUploads));
|
this.saveRecentUploads();
|
||||||
|
|
||||||
// Refresh the file list
|
// Refresh file list
|
||||||
this.loadServerFiles();
|
await this.loadServerFiles();
|
||||||
} else {
|
|
||||||
const error = await response.json();
|
alert(`File "${name}" deleted successfully`);
|
||||||
this.showToast(`Failed to delete file: ${error.error?.message || 'Unknown error'}`, 'error');
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Delete error:', error);
|
console.error('Delete failed:', error);
|
||||||
this.showToast(`Error deleting file: ${error.message}`, 'error');
|
alert(`Failed to delete file: ${error.message}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
showToast(message, type = 'info') {
|
showToast(message, type = 'info') {
|
||||||
const toast = document.createElement('div');
|
const toast = document.createElement('div');
|
||||||
toast.className = `toast ${type}`;
|
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
|
// Global functions for navigation and theme
|
||||||
function showServices() {
|
function showServices() {
|
||||||
hideAllSections();
|
hideAllSections();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user