mirror of
https://github.com/9001/copyparty.git
synced 2026-06-22 14:02:53 -06:00
410 lines
12 KiB
HTML
410 lines
12 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en" id="ht_brw">
|
|
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<title>{{ title }}</title>
|
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
<meta name="viewport" content="width=device-width, initial-scale=0.8, minimum-scale=0.6">
|
|
<meta name="theme-color" content="#{{ tcolor }}">
|
|
<link rel="stylesheet" media="screen" href="{{ r }}/.cpr/w/ui.css?_={{ ts }}">
|
|
<link rel="stylesheet" media="screen" href="{{ r }}/.cpr/w/browser.css?_={{ ts }}">
|
|
{{ html_head }}
|
|
{%- if css %}
|
|
<link rel="stylesheet" media="screen" href="{{ css }}_={{ ts }}">
|
|
{%- endif %}
|
|
</head>
|
|
|
|
<body>
|
|
<div id="ops"></div>
|
|
|
|
<div id="op_search" class="opview">
|
|
{%- if have_tags_idx %}
|
|
<div id="srch_form" class="tags opbox"></div>
|
|
{%- else %}
|
|
<div id="srch_form" class="opbox"></div>
|
|
{%- endif %}
|
|
<div id="srch_q"></div>
|
|
</div>
|
|
|
|
<div id="op_player" class="opview opbox opwide"></div>
|
|
|
|
<div id="op_bup" class="opview opbox {% if not ls0 %}act{% endif %}">
|
|
<div id="u2err"></div>
|
|
<form id="bup_form" method="post" enctype="multipart/form-data" accept-charset="utf-8" action="{{ url_suf }}">
|
|
<input type="hidden" name="act" value="bput" />
|
|
<input type="file" id="bup_files" name="f" multiple /><br />
|
|
<input type="submit" id="bup_submit" value="start upload">
|
|
</form>
|
|
<div id="bup_progress" style="display:none; margin-top:10px;">
|
|
<div id="bup_status" style="margin-bottom:5px; font-weight:bold;"></div>
|
|
<div id="bup_fileinfo" style="margin-bottom:5px; font-size:0.9em;"></div>
|
|
<div style="width:100%; background:#333; height:20px; border-radius:10px; overflow:hidden;">
|
|
<div id="bup_bar" style="width:0%; height:100%; background:linear-gradient(90deg, #09d, #4b0); transition:width 0.1s;"></div>
|
|
</div>
|
|
<div id="bup_percent" style="text-align:center; margin-top:5px; font-size:0.9em;"></div>
|
|
<div id="bup_speed" style="text-align:center; margin-top:5px; font-size:0.9em; color:#888;"></div>
|
|
</div>
|
|
<div id="bup_result" style="display:none; margin-top:10px; padding:10px; border-radius:5px;"></div>
|
|
<a id="bbsw" href="?b=u" rel="nofollow"><br />switch to basic browser</a>
|
|
</div>
|
|
|
|
<div id="op_mkdir" class="opview opbox {% if not ls0 %}act{% endif %}">
|
|
<form method="post" enctype="multipart/form-data" accept-charset="utf-8" action="{{ url_suf }}">
|
|
<input type="hidden" name="act" value="mkdir" />
|
|
📂<input type="text" name="name" class="i" placeholder="awesome mix vol.1">
|
|
<input type="submit" value="make directory">
|
|
</form>
|
|
</div>
|
|
|
|
<div id="op_new_md" class="opview opbox">
|
|
<form method="post" enctype="multipart/form-data" accept-charset="utf-8" action="{{ url_suf }}">
|
|
<input type="hidden" name="act" value="new_md" />
|
|
📝<input type="text" name="name" class="i" placeholder="weekend-plans">
|
|
<input type="submit" value="new file">
|
|
</form>
|
|
<span id="new_mdi"></span>
|
|
</div>
|
|
|
|
<div id="op_msg" class="opview opbox {% if not ls0 %}act{% endif %}">
|
|
<form method="post" enctype="application/x-www-form-urlencoded" accept-charset="utf-8" action="{{ url_suf }}">
|
|
📟<input type="text" name="msg" class="i" placeholder="lorem ipsum dolor sit amet">
|
|
<input type="submit" value="send msg to srv log">
|
|
</form>
|
|
</div>
|
|
|
|
<div id="op_unpost" class="opview opbox"></div>
|
|
|
|
<div id="op_up2k" class="opview"></div>
|
|
|
|
<div id="op_cfg" class="opview opbox opwide"></div>
|
|
|
|
<h1 id="path">
|
|
<a href="#" id="entree">🌲</a>
|
|
{%- for n in vpnodes %}
|
|
<a href="{{ r }}/{{ n[0] }}">{{ n[1] }}</a>
|
|
{%- endfor %}
|
|
</h1>
|
|
|
|
<div id="tree"></div>
|
|
|
|
<div id="wrap">
|
|
|
|
{%- if doc %}
|
|
<div id="bdoc"><pre>{{ doc|e }}</pre></div>
|
|
{%- else %}
|
|
<div id="bdoc"></div>
|
|
{%- endif %}
|
|
|
|
<div id="pro" class="logue">{{ "" if sb_lg else logues[0] }}</div>
|
|
|
|
<table id="files">
|
|
<thead>
|
|
<tr>
|
|
<th name="lead"><span>c</span></th>
|
|
<th name="href"><span>File Name</span></th>
|
|
<th name="sz" sort="int"><span>Size</span></th>
|
|
{%- for k in taglist %}
|
|
{%- if k.startswith('.') %}
|
|
<th name="tags/{{ k }}" sort="int"><span>{{ k[1:] }}</span></th>
|
|
{%- else %}
|
|
<th name="tags/{{ k }}"><span>{{ k[0]|upper }}{{ k[1:] }}</span></th>
|
|
{%- endif %}
|
|
{%- endfor %}
|
|
<th name="ext"><span>T</span></th>
|
|
<th name="ts"><span>Date</span></th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
|
|
{%- for f in files %}
|
|
<tr><td>{{ f.lead }}</td><td><a href="{{ f.href }}">{{ f.name|e }}</a></td><td>{{ f.sz }}</td>
|
|
{%- if f.tags is defined %}
|
|
{%- for k in taglist %}<td>{{ f.tags[k]|e }}</td>{%- endfor %}
|
|
{%- endif %}<td>{{ f.ext }}</td><td>{{ f.dt }}</td></tr>
|
|
{%- endfor %}
|
|
|
|
</tbody>
|
|
</table>
|
|
|
|
<div id="epi" class="logue">{{ "" if sb_lg else logues[1] }}</div>
|
|
|
|
<h2 id="wfp"><a href="{{ r }}/?h" id="goh">control-panel</a></h2>
|
|
|
|
<a href="#" id="repl">π</a>
|
|
|
|
</div>
|
|
|
|
<div id="srv_info"><span>{{ srv_info }}</span></div>
|
|
|
|
<div id="widget"></div>
|
|
|
|
<div id="rcm" tabindex="0"></div>
|
|
|
|
<script>
|
|
var SR = "{{ r }}",
|
|
CGV1 = {{ cgv1 }},
|
|
CGV = {{ cgv|tojson }},
|
|
TS = "{{ ts }}",
|
|
dtheme = "{{ dtheme }}",
|
|
lang = "{{ lang }}",
|
|
dfavico = "{{ favico }}",
|
|
have_tags_idx = {{ have_tags_idx }},
|
|
logues = {{ logues|tojson if sb_lg else "[]" }},
|
|
ls0 = {{ ls0|tojson }};
|
|
|
|
var STG = window.localStorage;
|
|
document.documentElement.className = (STG && STG.cpp_thm) || dtheme;
|
|
</script>
|
|
<script src="{{ r }}/.cpr/w/util.js?_={{ ts }}"></script>
|
|
{%- if lang != "eng" %}
|
|
<script src="{{ r }}/.cpr/w/tl/{{ lang }}.js?_={{ ts }}"></script>
|
|
{%- endif %}
|
|
<script src="{{ r }}/.cpr/w/baguettebox.js?_={{ ts }}"></script>
|
|
<script src="{{ r }}/.cpr/w/browser.js?_={{ ts }}"></script>
|
|
<script src="{{ r }}/.cpr/w/up2k.js?_={{ ts }}"></script>
|
|
{%- if js %}
|
|
<script src="{{ js }}_={{ ts }}"></script>
|
|
{%- endif %}
|
|
<script>
|
|
Date.now();function jsldp(a,b){2!=window[a]&&alert("FATAL ERROR: cannot load "+b+".js due to unreliable network or broken reverse-proxy; try CTRL-SHIFT-R")}
|
|
jsldp("J_UTL","util");
|
|
jsldp("J_BBX","baguettebox");
|
|
jsldp("J_BRW","browser");
|
|
jsldp("J_U2K","up2k");
|
|
</script>
|
|
<script>
|
|
(function() {
|
|
var MAX_RETRIES = 3,
|
|
RETRY_DELAY = 1000,
|
|
progressDiv = null,
|
|
progressBar = null,
|
|
progressPercent = null,
|
|
progressSpeed = null,
|
|
progressStatus = null,
|
|
progressFileinfo = null,
|
|
resultDiv = null,
|
|
form = null,
|
|
submitBtn = null,
|
|
fileInput = null,
|
|
uploadStartTime = 0,
|
|
currentRetry = 0,
|
|
currentFiles = [],
|
|
currentFileIndex = 0,
|
|
totalFilesSize = 0;
|
|
|
|
function formatSize(bytes) {
|
|
if (bytes === 0) return '0 B';
|
|
var k = 1024,
|
|
sizes = ['B', 'KB', 'MB', 'GB', 'TB'],
|
|
i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
|
|
}
|
|
|
|
function formatSpeed(bytesPerSec) {
|
|
if (bytesPerSec === 0) return '0 B/s';
|
|
var k = 1024,
|
|
sizes = ['B/s', 'KB/s', 'MB/s', 'GB/s'],
|
|
i = Math.floor(Math.log(bytesPerSec) / Math.log(k));
|
|
return parseFloat((bytesPerSec / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
|
|
}
|
|
|
|
function showProgress(show) {
|
|
if (progressDiv) {
|
|
progressDiv.style.display = show ? 'block' : 'none';
|
|
}
|
|
}
|
|
|
|
function showResult(success, message) {
|
|
if (resultDiv) {
|
|
resultDiv.style.display = 'block';
|
|
resultDiv.style.background = success ? '#050' : '#500';
|
|
resultDiv.style.color = '#fff';
|
|
resultDiv.innerHTML = message;
|
|
}
|
|
}
|
|
|
|
function hideResult() {
|
|
if (resultDiv) {
|
|
resultDiv.style.display = 'none';
|
|
}
|
|
}
|
|
|
|
function updateProgress(loaded, total) {
|
|
if (!progressBar || !progressPercent) return;
|
|
|
|
var percent = total > 0 ? (loaded / total * 100) : 0;
|
|
progressBar.style.width = percent + '%';
|
|
progressPercent.textContent = percent.toFixed(1) + '%';
|
|
|
|
if (uploadStartTime > 0 && loaded > 0) {
|
|
var elapsed = (Date.now() - uploadStartTime) / 1000;
|
|
var speed = loaded / elapsed;
|
|
if (progressSpeed) {
|
|
progressSpeed.textContent = formatSpeed(speed);
|
|
}
|
|
}
|
|
}
|
|
|
|
function setStatus(text) {
|
|
if (progressStatus) {
|
|
progressStatus.textContent = text;
|
|
}
|
|
}
|
|
|
|
function setFileinfo(text) {
|
|
if (progressFileinfo) {
|
|
progressFileinfo.textContent = text;
|
|
}
|
|
}
|
|
|
|
function setFormEnabled(enabled) {
|
|
if (submitBtn) {
|
|
submitBtn.disabled = !enabled;
|
|
}
|
|
if (fileInput) {
|
|
fileInput.disabled = !enabled;
|
|
}
|
|
}
|
|
|
|
function uploadFile(file, formAction, callback) {
|
|
var xhr = new XMLHttpRequest();
|
|
var formData = new FormData();
|
|
|
|
formData.append('act', 'bput');
|
|
formData.append('f', file);
|
|
|
|
uploadStartTime = Date.now();
|
|
currentRetry = 0;
|
|
|
|
setStatus('Uploading: ' + file.name);
|
|
setFileinfo('Size: ' + formatSize(file.size) + ' | Retry: ' + currentRetry + '/' + MAX_RETRIES);
|
|
updateProgress(0, file.size);
|
|
|
|
function doUpload() {
|
|
xhr.open('POST', formAction, true);
|
|
|
|
xhr.upload.onprogress = function(e) {
|
|
if (e.lengthComputable) {
|
|
updateProgress(e.loaded, e.total);
|
|
}
|
|
};
|
|
|
|
xhr.onload = function() {
|
|
if (xhr.status === 200) {
|
|
var responseText = xhr.responseText || '';
|
|
if (responseText.indexOf('error') === -1 && responseText.indexOf('ERR') === -1) {
|
|
callback(null, xhr);
|
|
} else {
|
|
callback(new Error('Server error: ' + responseText), xhr);
|
|
}
|
|
} else {
|
|
callback(new Error('HTTP error: ' + xhr.status), xhr);
|
|
}
|
|
};
|
|
|
|
xhr.onerror = function() {
|
|
if (currentRetry < MAX_RETRIES) {
|
|
currentRetry++;
|
|
setFileinfo('Size: ' + formatSize(file.size) + ' | Retry: ' + currentRetry + '/' + MAX_RETRIES + ' - retrying...');
|
|
setTimeout(doUpload, RETRY_DELAY * currentRetry);
|
|
} else {
|
|
callback(new Error('Network error after ' + MAX_RETRIES + ' retries'), xhr);
|
|
}
|
|
};
|
|
|
|
xhr.ontimeout = function() {
|
|
if (currentRetry < MAX_RETRIES) {
|
|
currentRetry++;
|
|
setFileinfo('Size: ' + formatSize(file.size) + ' | Retry: ' + currentRetry + '/' + MAX_RETRIES + ' - timeout, retrying...');
|
|
setTimeout(doUpload, RETRY_DELAY * currentRetry);
|
|
} else {
|
|
callback(new Error('Timeout after ' + MAX_RETRIES + ' retries'), xhr);
|
|
}
|
|
};
|
|
|
|
xhr.timeout = 300000;
|
|
xhr.send(formData);
|
|
}
|
|
|
|
doUpload();
|
|
}
|
|
|
|
function uploadNextFile(formAction) {
|
|
if (currentFileIndex >= currentFiles.length) {
|
|
showProgress(false);
|
|
showResult(true, 'All files uploaded successfully! (' + currentFiles.length + ' file(s), ' + formatSize(totalFilesSize) + ')');
|
|
setFormEnabled(true);
|
|
return;
|
|
}
|
|
|
|
var file = currentFiles[currentFileIndex];
|
|
|
|
uploadFile(file, formAction, function(err, xhr) {
|
|
if (err) {
|
|
showProgress(false);
|
|
showResult(false, 'Upload failed for "' + file.name + '": ' + err.message);
|
|
setFormEnabled(true);
|
|
} else {
|
|
currentFileIndex++;
|
|
uploadNextFile(formAction);
|
|
}
|
|
});
|
|
}
|
|
|
|
function initBupUpload() {
|
|
form = document.getElementById('bup_form');
|
|
submitBtn = document.getElementById('bup_submit');
|
|
fileInput = document.getElementById('bup_files');
|
|
progressDiv = document.getElementById('bup_progress');
|
|
progressBar = document.getElementById('bup_bar');
|
|
progressPercent = document.getElementById('bup_percent');
|
|
progressSpeed = document.getElementById('bup_speed');
|
|
progressStatus = document.getElementById('bup_status');
|
|
progressFileinfo = document.getElementById('bup_fileinfo');
|
|
resultDiv = document.getElementById('bup_result');
|
|
|
|
if (!form || !submitBtn || !fileInput) {
|
|
console.log('Basic upload form not found');
|
|
return;
|
|
}
|
|
|
|
form.addEventListener('submit', function(e) {
|
|
e.preventDefault();
|
|
|
|
if (!fileInput.files || fileInput.files.length === 0) {
|
|
showResult(false, 'Please select at least one file to upload.');
|
|
return;
|
|
}
|
|
|
|
hideResult();
|
|
showProgress(true);
|
|
setFormEnabled(false);
|
|
|
|
currentFiles = Array.from(fileInput.files);
|
|
currentFileIndex = 0;
|
|
totalFilesSize = 0;
|
|
|
|
for (var i = 0; i < currentFiles.length; i++) {
|
|
totalFilesSize += currentFiles[i].size;
|
|
}
|
|
|
|
setStatus('Preparing upload...');
|
|
setFileinfo('Total: ' + currentFiles.length + ' file(s), ' + formatSize(totalFilesSize));
|
|
|
|
var formAction = form.action || window.location.href;
|
|
uploadNextFile(formAction);
|
|
});
|
|
}
|
|
|
|
if (document.readyState === 'loading') {
|
|
document.addEventListener('DOMContentLoaded', initBupUpload);
|
|
} else {
|
|
initBupUpload();
|
|
}
|
|
})();
|
|
</script>
|
|
</body>
|
|
</html>
|
|
|