mirror of
				https://github.com/9001/copyparty.git
				synced 2025-11-03 21:43:12 +00:00 
			
		
		
		
	Compare commits
	
		
			21 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					04f1b2cf3a | ||
| 
						 | 
					c06d928bb5 | ||
| 
						 | 
					ab09927e7b | ||
| 
						 | 
					779437db67 | ||
| 
						 | 
					28cbdb652e | ||
| 
						 | 
					2b2415a7d8 | ||
| 
						 | 
					746a8208aa | ||
| 
						 | 
					a2a041a98a | ||
| 
						 | 
					10b436e449 | ||
| 
						 | 
					4d62b34786 | ||
| 
						 | 
					0546210687 | ||
| 
						 | 
					f8c11faada | ||
| 
						 | 
					16d6e9be1f | ||
| 
						 | 
					aff8185f2e | ||
| 
						 | 
					217d15fe81 | ||
| 
						 | 
					171e93c201 | ||
| 
						 | 
					acc1d2e9e3 | ||
| 
						 | 
					49c2f37154 | ||
| 
						 | 
					69e54497aa | ||
| 
						 | 
					9aa1885669 | ||
| 
						 | 
					4418508513 | 
							
								
								
									
										10
									
								
								.vscode/launch.py
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										10
									
								
								.vscode/launch.py
									
									
									
									
										vendored
									
									
								
							@@ -5,6 +5,7 @@
 | 
			
		||||
 | 
			
		||||
import os
 | 
			
		||||
import sys
 | 
			
		||||
import shlex
 | 
			
		||||
 | 
			
		||||
sys.path.insert(0, os.getcwd())
 | 
			
		||||
 | 
			
		||||
@@ -16,9 +17,16 @@ with open(".vscode/launch.json", "r") as f:
 | 
			
		||||
 | 
			
		||||
oj = jstyleson.loads(tj)
 | 
			
		||||
argv = oj["configurations"][0]["args"]
 | 
			
		||||
 | 
			
		||||
try:
 | 
			
		||||
    sargv = " ".join([shlex.quote(x) for x in argv])
 | 
			
		||||
    print(sys.executable + " -m copyparty " + sargv + "\n")
 | 
			
		||||
except:
 | 
			
		||||
    pass
 | 
			
		||||
 | 
			
		||||
argv = [os.path.expanduser(x) if x.startswith("~") else x for x in argv]
 | 
			
		||||
try:
 | 
			
		||||
    copyparty(argv)
 | 
			
		||||
    copyparty(["a"] + argv)
 | 
			
		||||
except SystemExit as ex:
 | 
			
		||||
    if ex.code:
 | 
			
		||||
        raise
 | 
			
		||||
 
 | 
			
		||||
@@ -111,6 +111,8 @@ the browser has the following hotkeys
 | 
			
		||||
* `I/K` prev/next folder
 | 
			
		||||
* `P` parent folder
 | 
			
		||||
 | 
			
		||||
you can link a particular timestamp in an audio file by adding it to the URL, such as `&20` / `&20s` / `&1m20` / `&1:20` after the `.../#af-c8960dab`
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## zip downloads
 | 
			
		||||
 | 
			
		||||
@@ -339,7 +341,6 @@ in the `scripts` folder:
 | 
			
		||||
 | 
			
		||||
roughly sorted by priority
 | 
			
		||||
 | 
			
		||||
* audio link with timestamp
 | 
			
		||||
* separate sqlite table per tag
 | 
			
		||||
* audio fingerprinting
 | 
			
		||||
* readme.md as epilogue
 | 
			
		||||
 
 | 
			
		||||
@@ -1,8 +1,8 @@
 | 
			
		||||
# coding: utf-8
 | 
			
		||||
 | 
			
		||||
VERSION = (0, 10, 8)
 | 
			
		||||
VERSION = (0, 10, 13)
 | 
			
		||||
CODENAME = "zip it"
 | 
			
		||||
BUILD_DT = (2021, 4, 11)
 | 
			
		||||
BUILD_DT = (2021, 4, 20)
 | 
			
		||||
 | 
			
		||||
S_VERSION = ".".join(map(str, VERSION))
 | 
			
		||||
S_BUILD_DT = "{0:04d}-{1:02d}-{2:02d}".format(*BUILD_DT)
 | 
			
		||||
 
 | 
			
		||||
@@ -111,7 +111,27 @@ class VFS(object):
 | 
			
		||||
        if rem:
 | 
			
		||||
            rp += "/" + rem
 | 
			
		||||
 | 
			
		||||
        return fsdec(os.path.realpath(fsenc(rp)))
 | 
			
		||||
        try:
 | 
			
		||||
            return fsdec(os.path.realpath(fsenc(rp)))
 | 
			
		||||
        except:
 | 
			
		||||
            if not WINDOWS:
 | 
			
		||||
                raise
 | 
			
		||||
 | 
			
		||||
            # cpython bug introduced in 3.8, still exists in 3.9.1;
 | 
			
		||||
            # some win7sp1 and win10:20H2 boxes cannot realpath a
 | 
			
		||||
            # networked drive letter such as b"n:" or b"n:\\"
 | 
			
		||||
            #
 | 
			
		||||
            # requirements to trigger:
 | 
			
		||||
            #  * bytestring (not unicode str)
 | 
			
		||||
            #  * just the drive letter (subfolders are ok)
 | 
			
		||||
            #  * networked drive (regular disks and vmhgfs are ok)
 | 
			
		||||
            #  * on an enterprise network (idk, cannot repro with samba)
 | 
			
		||||
            #
 | 
			
		||||
            # hits the following exceptions in succession:
 | 
			
		||||
            #  * access denied at L601: "path = _getfinalpathname(path)"
 | 
			
		||||
            #  * "cant concat str to bytes" at L621: "return path + tail"
 | 
			
		||||
            #
 | 
			
		||||
            return os.path.realpath(rp)
 | 
			
		||||
 | 
			
		||||
    def ls(self, rem, uname, scandir, lstat=False):
 | 
			
		||||
        """return user-readable [fsdir,real,virt] items at vpath"""
 | 
			
		||||
 
 | 
			
		||||
@@ -101,17 +101,18 @@ class Up2k(object):
 | 
			
		||||
            thr.daemon = True
 | 
			
		||||
            thr.start()
 | 
			
		||||
 | 
			
		||||
            thr = threading.Thread(target=self._tagger)
 | 
			
		||||
            thr.daemon = True
 | 
			
		||||
            thr.start()
 | 
			
		||||
 | 
			
		||||
            thr = threading.Thread(target=self._hasher)
 | 
			
		||||
            thr.daemon = True
 | 
			
		||||
            thr.start()
 | 
			
		||||
 | 
			
		||||
            thr = threading.Thread(target=self._run_all_mtp)
 | 
			
		||||
            thr.daemon = True
 | 
			
		||||
            thr.start()
 | 
			
		||||
            if self.mtag:
 | 
			
		||||
                thr = threading.Thread(target=self._tagger)
 | 
			
		||||
                thr.daemon = True
 | 
			
		||||
                thr.start()
 | 
			
		||||
 | 
			
		||||
                thr = threading.Thread(target=self._run_all_mtp)
 | 
			
		||||
                thr.daemon = True
 | 
			
		||||
                thr.start()
 | 
			
		||||
 | 
			
		||||
    def log(self, msg, c=0):
 | 
			
		||||
        self.log_func("up2k", msg + "\033[K", c)
 | 
			
		||||
@@ -1068,6 +1069,8 @@ class Up2k(object):
 | 
			
		||||
        with self.mutex:
 | 
			
		||||
            job = self.registry[ptop].get(wark, None)
 | 
			
		||||
            if not job:
 | 
			
		||||
                known = " ".join([x for x in self.registry[ptop].keys()])
 | 
			
		||||
                self.log("unknown wark [{}], known: {}".format(wark, known))
 | 
			
		||||
                raise Pebkac(400, "unknown wark")
 | 
			
		||||
 | 
			
		||||
            if chash not in job["need"]:
 | 
			
		||||
 
 | 
			
		||||
@@ -284,7 +284,7 @@ a, #files tbody div a:last-child {
 | 
			
		||||
	line-height: 1em;
 | 
			
		||||
}
 | 
			
		||||
#wtoggle.sel {
 | 
			
		||||
	width: 6em;
 | 
			
		||||
	width: 6.4em;
 | 
			
		||||
}
 | 
			
		||||
#wtoggle.sel #wzip {
 | 
			
		||||
	display: inline-block;
 | 
			
		||||
@@ -685,3 +685,173 @@ input[type="checkbox"]:checked+label {
 | 
			
		||||
	font-family: monospace, monospace;
 | 
			
		||||
	line-height: 2em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
html.light {
 | 
			
		||||
	color: #333;
 | 
			
		||||
	background: #eee;
 | 
			
		||||
	text-shadow: none;
 | 
			
		||||
}
 | 
			
		||||
html.light #ops,
 | 
			
		||||
html.light .opbox,
 | 
			
		||||
html.light #srch_form {
 | 
			
		||||
	background: #f7f7f7;
 | 
			
		||||
	box-shadow: 0 0 .3em #ddd;
 | 
			
		||||
	border-color: #f7f7f7;
 | 
			
		||||
}
 | 
			
		||||
html.light #ops a.act {
 | 
			
		||||
	box-shadow: 0 .2em .2em #ccc;
 | 
			
		||||
	background: #f7f7f7;
 | 
			
		||||
	border-color: #07a;
 | 
			
		||||
	padding-top: .4em;
 | 
			
		||||
}
 | 
			
		||||
html.light #op_cfg h3 {
 | 
			
		||||
	border-color: #ccc;
 | 
			
		||||
}
 | 
			
		||||
html.light .tglbtn,
 | 
			
		||||
html.light #tree > a + a {
 | 
			
		||||
	color: #666;
 | 
			
		||||
	background: #ddd;
 | 
			
		||||
	box-shadow: none;
 | 
			
		||||
}
 | 
			
		||||
html.light .tglbtn:hover,
 | 
			
		||||
html.light #tree > a + a:hover {
 | 
			
		||||
	background: #caf;
 | 
			
		||||
}
 | 
			
		||||
html.light .tglbtn.on,
 | 
			
		||||
html.light #tree > a + a.on {
 | 
			
		||||
	background: #4a0;
 | 
			
		||||
	color: #fff;
 | 
			
		||||
}
 | 
			
		||||
html.light #srv_info {
 | 
			
		||||
	color: #c83;
 | 
			
		||||
	text-shadow: 1px 1px 0 #fff;
 | 
			
		||||
}
 | 
			
		||||
html.light #srv_info span {
 | 
			
		||||
	color: #000;
 | 
			
		||||
}
 | 
			
		||||
html.light #treeul a+a {
 | 
			
		||||
	background: inherit;
 | 
			
		||||
	color: #06a;
 | 
			
		||||
}
 | 
			
		||||
html.light #treeul a.hl {
 | 
			
		||||
	background: #07a;
 | 
			
		||||
	color: #fff;
 | 
			
		||||
}
 | 
			
		||||
html.light #tree li {
 | 
			
		||||
	border-color: #ddd #fff #f7f7f7 #fff;
 | 
			
		||||
}
 | 
			
		||||
html.light #tree ul {
 | 
			
		||||
	border-color: #ccc;
 | 
			
		||||
}
 | 
			
		||||
html.light a,
 | 
			
		||||
html.light #ops a,
 | 
			
		||||
html.light #files tbody div a:last-child {
 | 
			
		||||
	color: #06a;
 | 
			
		||||
}
 | 
			
		||||
html.light #files tbody {
 | 
			
		||||
	background: #f7f7f7;
 | 
			
		||||
}
 | 
			
		||||
html.light #files {
 | 
			
		||||
	box-shadow: 0 0 .3em #ccc;
 | 
			
		||||
}
 | 
			
		||||
html.light #files thead th {
 | 
			
		||||
	background: #eee;
 | 
			
		||||
}
 | 
			
		||||
html.light #files tr+tr td {
 | 
			
		||||
	border-top: 1px solid #ddd;
 | 
			
		||||
}
 | 
			
		||||
html.light #files td {
 | 
			
		||||
	border-bottom: 1px solid #f7f7f7;
 | 
			
		||||
}
 | 
			
		||||
html.light #files tbody tr:last-child td {
 | 
			
		||||
	border-bottom: .2em solid #ccc;
 | 
			
		||||
}
 | 
			
		||||
html.light #files td:nth-child(2n) {
 | 
			
		||||
	color: #d38;
 | 
			
		||||
}
 | 
			
		||||
html.light #files tr:hover td {
 | 
			
		||||
	background: #fff;
 | 
			
		||||
}
 | 
			
		||||
html.light #files tbody a.play {
 | 
			
		||||
	color: #c0f;
 | 
			
		||||
}
 | 
			
		||||
html.light tr.play td {
 | 
			
		||||
	background: #fc5;
 | 
			
		||||
}
 | 
			
		||||
html.light tr.play a {
 | 
			
		||||
	color: #406;
 | 
			
		||||
}
 | 
			
		||||
html.light #files > thead > tr > th.min span {
 | 
			
		||||
	background: linear-gradient(90deg, rgba(68,68,68,0), rgba(68,68,68,0.2) 70%, rgba(68,68,68,0.5));
 | 
			
		||||
}
 | 
			
		||||
html.light #blocked {
 | 
			
		||||
	background: #eee;
 | 
			
		||||
}
 | 
			
		||||
html.light #blk_play a,
 | 
			
		||||
html.light #blk_abrt a {
 | 
			
		||||
	background: #fff;
 | 
			
		||||
	box-shadow: 0 .2em .4em #ddd;
 | 
			
		||||
}
 | 
			
		||||
html.light #widget a {
 | 
			
		||||
	color: #fc5;
 | 
			
		||||
}
 | 
			
		||||
html.light #files tr.sel:hover td {
 | 
			
		||||
	background: #c37;
 | 
			
		||||
}
 | 
			
		||||
html.light #files tr.sel td {
 | 
			
		||||
	color: #fff;
 | 
			
		||||
}
 | 
			
		||||
html.light #files tr.sel a {
 | 
			
		||||
	color: #fff;
 | 
			
		||||
}
 | 
			
		||||
html.light input[type="checkbox"] + label {
 | 
			
		||||
	color: #333;
 | 
			
		||||
}
 | 
			
		||||
html.light .opview input[type="text"] {
 | 
			
		||||
	background: #fff;
 | 
			
		||||
	color: #333;
 | 
			
		||||
	box-shadow: 0 0 2px #888;
 | 
			
		||||
	border-color: #38d;
 | 
			
		||||
}
 | 
			
		||||
html.light #ops:hover #opdesc {
 | 
			
		||||
	background: #fff;
 | 
			
		||||
	box-shadow: 0 .3em 1em #ccc;
 | 
			
		||||
}
 | 
			
		||||
html.light #opdesc code {
 | 
			
		||||
	background: #060;
 | 
			
		||||
	color: #fff;
 | 
			
		||||
}
 | 
			
		||||
html.light #u2tab a>span,
 | 
			
		||||
html.light #files td div span {
 | 
			
		||||
	color: #000;
 | 
			
		||||
}
 | 
			
		||||
html.light #path {
 | 
			
		||||
	background: #f7f7f7;
 | 
			
		||||
	text-shadow: none;
 | 
			
		||||
	box-shadow: 0 0 .3em #bbb;
 | 
			
		||||
}
 | 
			
		||||
html.light #path a {
 | 
			
		||||
	color: #333;
 | 
			
		||||
}
 | 
			
		||||
html.light #path a:not(:last-child)::after {
 | 
			
		||||
	border-color: #ccc;
 | 
			
		||||
	background: none;
 | 
			
		||||
	border-width: .1em .1em 0 0;
 | 
			
		||||
	margin: -.2em .3em -.2em -.3em;
 | 
			
		||||
}
 | 
			
		||||
html.light #path a:hover {
 | 
			
		||||
	background: none;
 | 
			
		||||
	color: #60a;
 | 
			
		||||
}
 | 
			
		||||
html.light #files tbody div a {
 | 
			
		||||
	color: #d38;
 | 
			
		||||
}
 | 
			
		||||
html.light #files a:hover,
 | 
			
		||||
html.light #files tr.sel a:hover {
 | 
			
		||||
	color: #000;
 | 
			
		||||
	background: #fff;
 | 
			
		||||
}
 | 
			
		||||
@@ -13,8 +13,8 @@
 | 
			
		||||
<body>
 | 
			
		||||
    <div id="ops">
 | 
			
		||||
        <a href="#" data-dest="" data-desc="close submenu">---</a>
 | 
			
		||||
        <a href="#" data-perm="read" data-dest="search" data-desc="search for files by attributes, path/name, music tags, or any combination of those.<br /><br /><code>foo bar</code> = must contain both foo and bar,<br /><code>foo -bar</code> = must contain foo but not bar,<br /><code>^yana .opus$</code> = must start with yana and have the opus extension">🔎</a>
 | 
			
		||||
        {%- if have_up2k_idx %}
 | 
			
		||||
        <a href="#" data-perm="read" data-dest="search" data-desc="search for files by attributes, path/name, music tags, or any combination of those.<br /><br /><code>foo bar</code> = must contain both foo and bar,<br /><code>foo -bar</code> = must contain foo but not bar,<br /><code>^yana .opus$</code> = must start with yana and have the opus extension">🔎</a>
 | 
			
		||||
        <a href="#" data-dest="up2k" data-desc="up2k: upload files (if you have write-access) or toggle into the search-mode and drag files onto the search button to see if they exist somewhere on the server">🚀</a>
 | 
			
		||||
        {%- else %}
 | 
			
		||||
        <a href="#" data-perm="write" data-dest="up2k" data-desc="up2k: upload files with resume support (close your browser and drop the same files in later)">🚀</a>
 | 
			
		||||
@@ -39,14 +39,17 @@
 | 
			
		||||
    {%- include 'upload.html' %}
 | 
			
		||||
 | 
			
		||||
    <div id="op_cfg" class="opview opbox">
 | 
			
		||||
        <h3>key notation</h3>
 | 
			
		||||
        <div id="key_notation"></div>
 | 
			
		||||
        <h3>switches</h3>
 | 
			
		||||
        <div>
 | 
			
		||||
            <a id="tooltips" class="tglbtn" href="#">tooltips</a>
 | 
			
		||||
            <a id="lightmode" class="tglbtn" href="#">lightmode</a>
 | 
			
		||||
        </div>
 | 
			
		||||
        {%- if have_zip %}
 | 
			
		||||
        <h3>folder download</h3>
 | 
			
		||||
        <div id="arc_fmt"></div>
 | 
			
		||||
        {%- endif %}
 | 
			
		||||
        <h3>tooltips</h3>
 | 
			
		||||
        <div><a id="tooltips" class="tglbtn" href="#">enable</a></div>
 | 
			
		||||
        <h3>key notation</h3>
 | 
			
		||||
        <div id="key_notation"></div>
 | 
			
		||||
    </div>
 | 
			
		||||
    
 | 
			
		||||
    <h1 id="path">
 | 
			
		||||
@@ -117,8 +120,8 @@
 | 
			
		||||
                <a href="#" id="selall">sel.<br />all</a>
 | 
			
		||||
                <a href="#" id="selinv">sel.<br />inv.</a>
 | 
			
		||||
                <a href="#" id="selzip">zip</a>
 | 
			
		||||
            </span>
 | 
			
		||||
            <a href="#" id="wtico">♫</a>
 | 
			
		||||
            </span><a
 | 
			
		||||
                href="#" id="wtico">♫</a>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div id="widgeti">
 | 
			
		||||
            <div id="pctl"><a href="#" id="bprev">⏮</a><a href="#" id="bplay">▶</a><a href="#" id="bnext">⏭</a></div>
 | 
			
		||||
 
 | 
			
		||||
@@ -314,8 +314,8 @@ function seek_au_sec(seek) {
 | 
			
		||||
 | 
			
		||||
	mp.au.currentTime = seek;
 | 
			
		||||
 | 
			
		||||
	// ogv.js breaks on .play() during playback
 | 
			
		||||
	if (mp.au === mp.au_native)
 | 
			
		||||
		// hack: ogv.js breaks on .play() during playback
 | 
			
		||||
		mp.au.play();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -427,7 +427,7 @@ catch (ex) { }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// plays the tid'th audio file on the page
 | 
			
		||||
function play(tid, call_depth) {
 | 
			
		||||
function play(tid, seek, call_depth) {
 | 
			
		||||
	if (mp.order.length == 0)
 | 
			
		||||
		return alert('no audio found wait what');
 | 
			
		||||
 | 
			
		||||
@@ -449,7 +449,7 @@ function play(tid, call_depth) {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// ogv.js breaks on .play() unless directly user-triggered
 | 
			
		||||
	var hack_attempt_play = true;
 | 
			
		||||
	var attempt_play = true;
 | 
			
		||||
 | 
			
		||||
	var url = mp.tracks[tid];
 | 
			
		||||
	if (need_ogv && /\.(ogg|opus)$/i.test(url)) {
 | 
			
		||||
@@ -458,7 +458,7 @@ function play(tid, call_depth) {
 | 
			
		||||
		}
 | 
			
		||||
		else if (window['OGVPlayer']) {
 | 
			
		||||
			mp.au = mp.au_ogvjs = new OGVPlayer();
 | 
			
		||||
			hack_attempt_play = false;
 | 
			
		||||
			attempt_play = false;
 | 
			
		||||
			mp.au.addEventListener('error', evau_error, true);
 | 
			
		||||
			mp.au.addEventListener('progress', pbar.drawpos, false);
 | 
			
		||||
			widget.open();
 | 
			
		||||
@@ -470,7 +470,7 @@ function play(tid, call_depth) {
 | 
			
		||||
			show_modal('<h1>loading ogv.js</h1><h2>thanks apple</h2>');
 | 
			
		||||
 | 
			
		||||
			import_js('/.cpr/deps/ogv.js', function () {
 | 
			
		||||
				play(tid, 1);
 | 
			
		||||
				play(tid, seek, 1);
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			return;
 | 
			
		||||
@@ -498,21 +498,26 @@ function play(tid, call_depth) {
 | 
			
		||||
	ebi(oid).parentElement.parentElement.className += ' play';
 | 
			
		||||
 | 
			
		||||
	try {
 | 
			
		||||
		if (hack_attempt_play)
 | 
			
		||||
		if (attempt_play)
 | 
			
		||||
			mp.au.play();
 | 
			
		||||
 | 
			
		||||
		if (mp.au.paused)
 | 
			
		||||
			autoplay_blocked();
 | 
			
		||||
			autoplay_blocked(seek);
 | 
			
		||||
		else if (seek) {
 | 
			
		||||
			seek_au_sec(seek);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		var o = ebi(oid);
 | 
			
		||||
		o.setAttribute('id', 'thx_js');
 | 
			
		||||
		if (window.history && history.replaceState) {
 | 
			
		||||
			hist_replace(document.location.pathname + '#' + oid);
 | 
			
		||||
		if (!seek) {
 | 
			
		||||
			var o = ebi(oid);
 | 
			
		||||
			o.setAttribute('id', 'thx_js');
 | 
			
		||||
			if (window.history && history.replaceState) {
 | 
			
		||||
				hist_replace(document.location.pathname + '#' + oid);
 | 
			
		||||
			}
 | 
			
		||||
			else {
 | 
			
		||||
				document.location.hash = oid;
 | 
			
		||||
			}
 | 
			
		||||
			o.setAttribute('id', oid);
 | 
			
		||||
		}
 | 
			
		||||
		else {
 | 
			
		||||
			document.location.hash = oid;
 | 
			
		||||
		}
 | 
			
		||||
		o.setAttribute('id', oid);
 | 
			
		||||
 | 
			
		||||
		pbar.drawbuf();
 | 
			
		||||
		return true;
 | 
			
		||||
@@ -576,7 +581,7 @@ function unblocked() {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// show ui to manually start playback of a linked song
 | 
			
		||||
function autoplay_blocked() {
 | 
			
		||||
function autoplay_blocked(seek) {
 | 
			
		||||
	show_modal(
 | 
			
		||||
		'<div id="blk_play"><a href="#" id="blk_go"></a></div>' +
 | 
			
		||||
		'<div id="blk_abrt"><a href="#" id="blk_na">Cancel<br />(show file list)</a></div>');
 | 
			
		||||
@@ -592,6 +597,8 @@ function autoplay_blocked() {
 | 
			
		||||
		if (e) e.preventDefault();
 | 
			
		||||
		unblocked();
 | 
			
		||||
		mp.au.play();
 | 
			
		||||
		if (seek)
 | 
			
		||||
			seek_au_sec(seek);
 | 
			
		||||
	};
 | 
			
		||||
	na.onclick = unblocked;
 | 
			
		||||
}
 | 
			
		||||
@@ -600,8 +607,20 @@ function autoplay_blocked() {
 | 
			
		||||
// autoplay linked track
 | 
			
		||||
(function () {
 | 
			
		||||
	var v = location.hash;
 | 
			
		||||
	if (v && v.length == 12 && v.indexOf('#af-') === 0)
 | 
			
		||||
		play(v.slice(2));
 | 
			
		||||
	if (v && v.indexOf('#af-') === 0) {
 | 
			
		||||
		var id = v.slice(2).split('&');
 | 
			
		||||
		if (id[0].length != 10)
 | 
			
		||||
			return;
 | 
			
		||||
 | 
			
		||||
		if (id.length == 1)
 | 
			
		||||
			return play(id[0]);
 | 
			
		||||
 | 
			
		||||
		var m = /^[Tt=0]*([0-9]+[Mm:])?0*([0-9]+)[Ss]?$/.exec(id[1]);
 | 
			
		||||
		if (!m)
 | 
			
		||||
			return play(id[0]);
 | 
			
		||||
 | 
			
		||||
		return play(id[0], parseInt(m[1] || 0) * 60 + parseInt(m[2] || 0));
 | 
			
		||||
	}
 | 
			
		||||
})();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -1549,8 +1568,11 @@ function addcrc() {
 | 
			
		||||
			ebi('unsearch') ? 'div>a:last-child' : 'a'));
 | 
			
		||||
 | 
			
		||||
	for (var a = 0, aa = links.length; a < aa; a++)
 | 
			
		||||
		if (!links[a].getAttribute('id'))
 | 
			
		||||
			links[a].setAttribute('id', 'f-' + crc32(links[a].textContent || links[a].innerText));
 | 
			
		||||
		if (!links[a].getAttribute('id')) {
 | 
			
		||||
			var crc = crc32(links[a].textContent || links[a].innerText);
 | 
			
		||||
			crc = ('00000000' + crc).slice(-8);
 | 
			
		||||
			links[a].setAttribute('id', 'f-' + crc);
 | 
			
		||||
		}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -1577,6 +1599,24 @@ function addcrc() {
 | 
			
		||||
})();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
(function () {
 | 
			
		||||
	var light = bcfg_get('lightmode', false);
 | 
			
		||||
 | 
			
		||||
	function freshen() {
 | 
			
		||||
		document.documentElement.setAttribute("class", light ? "light" : "");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ebi('lightmode').onclick = function (e) {
 | 
			
		||||
		ev(e);
 | 
			
		||||
		light = !light;
 | 
			
		||||
		bcfg_set('lightmode', light);
 | 
			
		||||
		freshen();
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	freshen();
 | 
			
		||||
})();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
var arcfmt = (function () {
 | 
			
		||||
	if (!ebi('arc_fmt'))
 | 
			
		||||
		return { "render": function () { } };
 | 
			
		||||
 
 | 
			
		||||
@@ -138,10 +138,10 @@ var md_opt = {
 | 
			
		||||
        document.documentElement.setAttribute("class", dark ? "dark" : "");
 | 
			
		||||
        btn.innerHTML = "go " + (dark ? "light" : "dark");
 | 
			
		||||
        if (window.localStorage)
 | 
			
		||||
            localStorage.setItem('darkmode', dark ? 1 : 0);
 | 
			
		||||
            localStorage.setItem('lightmode', dark ? 0 : 1);
 | 
			
		||||
    };
 | 
			
		||||
    btn.onclick = toggle;
 | 
			
		||||
    if (window.localStorage && localStorage.getItem('darkmode') == 1)
 | 
			
		||||
    if (window.localStorage && localStorage.getItem('lightmode') != 1)
 | 
			
		||||
		toggle();
 | 
			
		||||
})();
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -31,12 +31,12 @@ var md_opt = {
 | 
			
		||||
 | 
			
		||||
var lightswitch = (function () {
 | 
			
		||||
	var fun = function () {
 | 
			
		||||
		var dark = !!!document.documentElement.getAttribute("class");
 | 
			
		||||
		var dark = !document.documentElement.getAttribute("class");
 | 
			
		||||
		document.documentElement.setAttribute("class", dark ? "dark" : "");
 | 
			
		||||
		if (window.localStorage)
 | 
			
		||||
			localStorage.setItem('darkmode', dark ? 1 : 0);
 | 
			
		||||
			localStorage.setItem('lightmode', dark ? 0 : 1);
 | 
			
		||||
	};
 | 
			
		||||
	if (window.localStorage && localStorage.getItem('darkmode') == 1)
 | 
			
		||||
	if (window.localStorage && localStorage.getItem('lightmode') != 1)
 | 
			
		||||
		fun();
 | 
			
		||||
	
 | 
			
		||||
	return fun;
 | 
			
		||||
 
 | 
			
		||||
@@ -38,7 +38,7 @@
 | 
			
		||||
    </div>
 | 
			
		||||
    <script>
 | 
			
		||||
 | 
			
		||||
if (window.localStorage && localStorage.getItem('darkmode') == 1)
 | 
			
		||||
if (window.localStorage && localStorage.getItem('lightmode') != 1)
 | 
			
		||||
    document.documentElement.setAttribute("class", "dark");
 | 
			
		||||
 | 
			
		||||
</script>
 | 
			
		||||
 
 | 
			
		||||
@@ -132,9 +132,285 @@ function up2k_flagbus() {
 | 
			
		||||
    return flag;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function U2pvis(act, btns) {
 | 
			
		||||
    this.act = act;
 | 
			
		||||
    this.ctr = { "ok": 0, "ng": 0, "bz": 0, "q": 0 };
 | 
			
		||||
    this.tab = [];
 | 
			
		||||
    this.head = 0;
 | 
			
		||||
    this.tail = -1;
 | 
			
		||||
    this.wsz = 3;
 | 
			
		||||
 | 
			
		||||
    this.addfile = function (entry, sz) {
 | 
			
		||||
        this.tab.push({
 | 
			
		||||
            "hn": entry[0],
 | 
			
		||||
            "ht": entry[1],
 | 
			
		||||
            "hp": entry[2],
 | 
			
		||||
            "in": 'q',
 | 
			
		||||
            "nh": 0, //hashed
 | 
			
		||||
            "nd": 0, //done
 | 
			
		||||
            "cb": [], // bytes done in chunk
 | 
			
		||||
            "bt": sz, // bytes total
 | 
			
		||||
            "bd": 0,  // bytes done
 | 
			
		||||
            "bd0": 0  // upload start
 | 
			
		||||
        });
 | 
			
		||||
        this.ctr["q"]++;
 | 
			
		||||
        this.drawcard("q");
 | 
			
		||||
        if (this.act == "q") {
 | 
			
		||||
            this.addrow(this.tab.length - 1);
 | 
			
		||||
        }
 | 
			
		||||
        if (this.act == "bz") {
 | 
			
		||||
            this.bzw();
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    this.is_act = function (card) {
 | 
			
		||||
        if (this.act == "done")
 | 
			
		||||
            return card == "ok" || card == "ng";
 | 
			
		||||
 | 
			
		||||
        return this.act == card;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    this.seth = function (nfile, field, html) {
 | 
			
		||||
        var fo = this.tab[nfile];
 | 
			
		||||
        field = ['hn', 'ht', 'hp'][field];
 | 
			
		||||
        if (fo[field] === html)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        fo[field] = html;
 | 
			
		||||
        if (!this.is_act(fo.in))
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        var obj = ebi('f{0}{1}'.format(nfile, field.slice(1)));
 | 
			
		||||
        obj.innerHTML = html;
 | 
			
		||||
        if (field == 'hp') {
 | 
			
		||||
            obj.style.color = '';
 | 
			
		||||
            obj.style.background = '';
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    this.setab = function (nfile, nblocks) {
 | 
			
		||||
        var t = [];
 | 
			
		||||
        for (var a = 0; a < nblocks; a++)
 | 
			
		||||
            t.push(0);
 | 
			
		||||
 | 
			
		||||
        this.tab[nfile].cb = t;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    this.setat = function (nfile, blocktab) {
 | 
			
		||||
        this.tab[nfile].cb = blocktab;
 | 
			
		||||
 | 
			
		||||
        var bd = 0;
 | 
			
		||||
        for (var a = 0; a < blocktab.length; a++)
 | 
			
		||||
            bd += blocktab[a];
 | 
			
		||||
 | 
			
		||||
        this.tab[nfile].bd = bd;
 | 
			
		||||
        this.tab[nfile].bd0 = bd;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    this.perc = function (bd, bd0, sz, t0) {
 | 
			
		||||
        var td = new Date().getTime() - t0,
 | 
			
		||||
            p = bd * 100.0 / sz,
 | 
			
		||||
            nb = bd - bd0,
 | 
			
		||||
            spd = nb / (td / 1000),
 | 
			
		||||
            eta = (sz - bd) / spd;
 | 
			
		||||
 | 
			
		||||
        return [p, s2ms(eta), spd / (1024 * 1024)];
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    this.hashed = function (fobj) {
 | 
			
		||||
        var fo = this.tab[fobj.n];
 | 
			
		||||
        var nb = fo.bt * (++fo.nh / fo.cb.length);
 | 
			
		||||
        var p = this.perc(nb, 0, fobj.size, fobj.t1);
 | 
			
		||||
        fo.hp = '{0}%, {1}, {2} MB/s'.format(
 | 
			
		||||
            p[0].toFixed(2), p[1], p[2].toFixed(2)
 | 
			
		||||
        );
 | 
			
		||||
        if (!this.is_act(fo.in))
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        var obj = ebi('f{0}p'.format(fobj.n));
 | 
			
		||||
        obj.innerHTML = fo.hp;
 | 
			
		||||
        obj.style.color = '#fff';
 | 
			
		||||
        var o1 = p[0] - 2, o2 = p[0] - 0.1, o3 = p[0];
 | 
			
		||||
        obj.style.background = 'linear-gradient(90deg, #025, #06a ' + o1 + '%, #09d ' + o2 + '%, #333 ' + o3 + '%, #333 99%, #777)';
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    this.prog = function (fobj, nchunk, cbd) {
 | 
			
		||||
        var fo = this.tab[fobj.n];
 | 
			
		||||
        var delta = cbd - fo.cb[nchunk];
 | 
			
		||||
        fo.cb[nchunk] = cbd;
 | 
			
		||||
        fo.bd += delta;
 | 
			
		||||
 | 
			
		||||
        var p = this.perc(fo.bd, fo.bd0, fo.bt, fobj.t3);
 | 
			
		||||
        fo.hp = '{0}%, {1}, {2} MB/s'.format(
 | 
			
		||||
            p[0].toFixed(2), p[1], p[2].toFixed(2)
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        if (!this.is_act(fo.in))
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        var obj = ebi('f{0}p'.format(fobj.n));
 | 
			
		||||
        obj.innerHTML = fo.hp;
 | 
			
		||||
        obj.style.color = '#fff';
 | 
			
		||||
        var o1 = p[0] - 2, o2 = p[0] - 0.1, o3 = p[0];
 | 
			
		||||
        obj.style.background = 'linear-gradient(90deg, #050, #270 ' + o1 + '%, #4b0 ' + o2 + '%, #333 ' + o3 + '%, #333 99%, #777)';
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    this.move = function (nfile, newcat) {
 | 
			
		||||
        var fo = this.tab[nfile],
 | 
			
		||||
            oldcat = fo.in,
 | 
			
		||||
            bz_act = this.act == "bz";
 | 
			
		||||
 | 
			
		||||
        if (oldcat == newcat) {
 | 
			
		||||
            throw 42;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        fo.in = newcat;
 | 
			
		||||
        this.ctr[oldcat]--;
 | 
			
		||||
        this.ctr[newcat]++;
 | 
			
		||||
        this.drawcard(oldcat);
 | 
			
		||||
        this.drawcard(newcat);
 | 
			
		||||
        if (this.is_act(newcat)) {
 | 
			
		||||
            this.tail++;
 | 
			
		||||
            if (!ebi('f' + nfile))
 | 
			
		||||
                this.addrow(nfile);
 | 
			
		||||
        }
 | 
			
		||||
        else if (this.is_act(oldcat)) {
 | 
			
		||||
            this.head++;
 | 
			
		||||
            if (!bz_act) {
 | 
			
		||||
                var tr = ebi("f" + nfile);
 | 
			
		||||
                tr.parentNode.removeChild(tr);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (bz_act) {
 | 
			
		||||
            this.bzw();
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    this.bzw_log = function (first, last) {
 | 
			
		||||
        console.log("first %d   head %d   tail %d   last %d", first, this.head, this.tail, last);
 | 
			
		||||
        var trs = document.querySelectorAll('#u2tab>tbody>tr'), msg = [];
 | 
			
		||||
        for (var a = 0; a < trs.length; a++)
 | 
			
		||||
            msg.push(trs[a].getAttribute('id'));
 | 
			
		||||
 | 
			
		||||
        console.log(msg.join(' '));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    this.bzw = function () {
 | 
			
		||||
        var first = document.querySelector('#u2tab>tbody>tr:first-child');
 | 
			
		||||
        if (!first)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        var last = document.querySelector('#u2tab>tbody>tr:last-child');
 | 
			
		||||
        first = parseInt(first.getAttribute('id').slice(1));
 | 
			
		||||
        last = parseInt(last.getAttribute('id').slice(1));
 | 
			
		||||
        //this.bzw_log(first, last);
 | 
			
		||||
 | 
			
		||||
        while (this.head - first > this.wsz) {
 | 
			
		||||
            var obj = ebi('f' + (first++));
 | 
			
		||||
            obj.parentNode.removeChild(obj);
 | 
			
		||||
        }
 | 
			
		||||
        while (last - this.tail < this.wsz && last < this.tab.length - 2) {
 | 
			
		||||
            var obj = ebi('f' + (++last));
 | 
			
		||||
            if (!obj)
 | 
			
		||||
                this.addrow(last);
 | 
			
		||||
        }
 | 
			
		||||
        //this.bzw_log(first, last);
 | 
			
		||||
        //console.log('--');
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    this.drawcard = function (cat) {
 | 
			
		||||
        var cards = document.querySelectorAll('#u2cards>a>span');
 | 
			
		||||
 | 
			
		||||
        if (cat == "q") {
 | 
			
		||||
            cards[4].innerHTML = this.ctr[cat];
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        if (cat == "bz") {
 | 
			
		||||
            cards[3].innerHTML = this.ctr[cat];
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        cards[2].innerHTML = this.ctr["ok"] + this.ctr["ng"];
 | 
			
		||||
 | 
			
		||||
        if (cat == "ng") {
 | 
			
		||||
            cards[1].innerHTML = this.ctr[cat];
 | 
			
		||||
        }
 | 
			
		||||
        if (cat == "ok") {
 | 
			
		||||
            cards[0].innerHTML = this.ctr[cat];
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    this.changecard = function (card) {
 | 
			
		||||
        this.act = card;
 | 
			
		||||
        var html = [];
 | 
			
		||||
        this.head = -1;
 | 
			
		||||
        this.tail = -1;
 | 
			
		||||
        for (var a = 0; a < this.tab.length; a++) {
 | 
			
		||||
            var rt = this.tab[a].in;
 | 
			
		||||
            if (this.is_act(rt)) {
 | 
			
		||||
                html.push(this.genrow(a, true));
 | 
			
		||||
 | 
			
		||||
                this.tail = a;
 | 
			
		||||
                if (this.head == -1)
 | 
			
		||||
                    this.head = a;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (this.head == -1) {
 | 
			
		||||
            this.head = this.tab.length;
 | 
			
		||||
            this.tail = this.head - 1;
 | 
			
		||||
        }
 | 
			
		||||
        if (card == "bz") {
 | 
			
		||||
            for (var a = this.head - 1; a >= this.head - this.wsz && a >= 0; a--) {
 | 
			
		||||
                html.unshift(this.genrow(a, true).replace(/><td>/, "><td>a "));
 | 
			
		||||
            }
 | 
			
		||||
            for (var a = this.tail + 1; a <= this.tail + this.wsz && a < this.tab.length; a++) {
 | 
			
		||||
                html.push(this.genrow(a, true).replace(/><td>/, "><td>b "));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        ebi('u2tab').tBodies[0].innerHTML = html.join('\n');
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    this.genrow = function (nfile, as_html) {
 | 
			
		||||
        var r = this.tab[nfile],
 | 
			
		||||
            td1 = '<td id="f' + nfile,
 | 
			
		||||
            td = '</td>' + td1,
 | 
			
		||||
            ret = td1 + 'n">' + r.hn +
 | 
			
		||||
                td + 't">' + r.ht +
 | 
			
		||||
                td + 'p" class="prog">' + r.hp + '</td>';
 | 
			
		||||
 | 
			
		||||
        if (as_html)
 | 
			
		||||
            return '<tr id="f' + nfile + '">' + ret + '</tr>';
 | 
			
		||||
 | 
			
		||||
        var obj = document.createElement('tr');
 | 
			
		||||
        obj.setAttribute('id', 'f' + nfile);
 | 
			
		||||
        obj.innerHTML = ret;
 | 
			
		||||
        return obj;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    this.addrow = function (nfile) {
 | 
			
		||||
        var tr = this.genrow(nfile);
 | 
			
		||||
        ebi('u2tab').tBodies[0].appendChild(tr);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    var that = this;
 | 
			
		||||
    btns = document.querySelectorAll(btns + '>a[act]');
 | 
			
		||||
    for (var a = 0; a < btns.length; a++) {
 | 
			
		||||
        btns[a].onclick = function (e) {
 | 
			
		||||
            ev(e);
 | 
			
		||||
            var newtab = this.getAttribute('act');
 | 
			
		||||
            for (var b = 0; b < btns.length; b++) {
 | 
			
		||||
                btns[b].className = (
 | 
			
		||||
                    btns[b].getAttribute('act') == newtab) ? 'act' : '';
 | 
			
		||||
            }
 | 
			
		||||
            that.changecard(newtab);
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function up2k_init(have_crypto) {
 | 
			
		||||
    //have_crypto = false;
 | 
			
		||||
    var need_filereader_cache = undefined;
 | 
			
		||||
 | 
			
		||||
    // show modal message
 | 
			
		||||
    function showmodal(msg) {
 | 
			
		||||
@@ -216,10 +492,6 @@ function up2k_init(have_crypto) {
 | 
			
		||||
    var flag_en = bcfg_get('flag_en', false);
 | 
			
		||||
    var fsearch = bcfg_get('fsearch', false);
 | 
			
		||||
 | 
			
		||||
    var col_hashing = '#00bbff';
 | 
			
		||||
    var col_hashed = '#004466';
 | 
			
		||||
    var col_uploading = '#ffcc44';
 | 
			
		||||
    var col_uploaded = '#00bb00';
 | 
			
		||||
    var fdom_ctr = 0;
 | 
			
		||||
    var st = {
 | 
			
		||||
        "files": [],
 | 
			
		||||
@@ -239,6 +511,8 @@ function up2k_init(have_crypto) {
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    var pvis = new U2pvis("bz", '#u2cards');
 | 
			
		||||
 | 
			
		||||
    var bobslice = null;
 | 
			
		||||
    if (window.File)
 | 
			
		||||
        bobslice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice;
 | 
			
		||||
@@ -413,12 +687,12 @@ function up2k_init(have_crypto) {
 | 
			
		||||
            if (skip)
 | 
			
		||||
                continue;
 | 
			
		||||
 | 
			
		||||
            var tr = document.createElement('tr');
 | 
			
		||||
            tr.innerHTML = '<td id="f{0}n"></td><td id="f{0}t">hashing</td><td id="f{0}p" class="prog"></td>'.format(st.files.length);
 | 
			
		||||
            tr.getElementsByTagName('td')[0].innerHTML = fsearch ? esc(entry.name) : linksplit(
 | 
			
		||||
                esc(uricom_dec(entry.purl)[0] + entry.name)).join(' ');
 | 
			
		||||
            ebi('u2tab').appendChild(tr);
 | 
			
		||||
 | 
			
		||||
            pvis.addfile([
 | 
			
		||||
                fsearch ? esc(entry.name) : linksplit(
 | 
			
		||||
                    esc(uricom_dec(entry.purl)[0] + entry.name)).join(' '),
 | 
			
		||||
                '📐 hash',
 | 
			
		||||
                ''
 | 
			
		||||
            ], fobj.size);
 | 
			
		||||
            st.files.push(entry);
 | 
			
		||||
            st.todo.hash.push(entry);
 | 
			
		||||
        }
 | 
			
		||||
@@ -439,7 +713,10 @@ function up2k_init(have_crypto) {
 | 
			
		||||
        for (var a = 0; a < st.files.length; a++) {
 | 
			
		||||
            var t = st.files[a];
 | 
			
		||||
            if (t.done && t.name) {
 | 
			
		||||
                var tr = ebi('f{0}p'.format(t.n)).parentNode;
 | 
			
		||||
                var tr = ebi('f' + t.n);
 | 
			
		||||
                if (!tr)
 | 
			
		||||
                    continue;
 | 
			
		||||
 | 
			
		||||
                tr.parentNode.removeChild(tr);
 | 
			
		||||
                t.name = undefined;
 | 
			
		||||
            }
 | 
			
		||||
@@ -462,7 +739,8 @@ function up2k_init(have_crypto) {
 | 
			
		||||
    function hashing_permitted() {
 | 
			
		||||
        if (multitask) {
 | 
			
		||||
            var ahead = st.bytes.hashed - st.bytes.uploaded;
 | 
			
		||||
            return ahead < 1024 * 1024 * 128;
 | 
			
		||||
            return ahead < 1024 * 1024 * 1024 * 4 &&
 | 
			
		||||
                st.todo.handshake.length + st.busy.handshake.length < 16;
 | 
			
		||||
        }
 | 
			
		||||
        return handshakes_permitted() && 0 ==
 | 
			
		||||
            st.todo.handshake.length +
 | 
			
		||||
@@ -628,31 +906,6 @@ function up2k_init(have_crypto) {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function test_filereader_speed(segm_err) {
 | 
			
		||||
        var f = st.todo.hash[0].fobj,
 | 
			
		||||
            sz = Math.min(2, f.size),
 | 
			
		||||
            reader = new FileReader(),
 | 
			
		||||
            t0, ctr = 0;
 | 
			
		||||
 | 
			
		||||
        var segm_next = function () {
 | 
			
		||||
            var t = new Date().getTime(),
 | 
			
		||||
                td = t - t0;
 | 
			
		||||
 | 
			
		||||
            if (++ctr > 2) {
 | 
			
		||||
                need_filereader_cache = td > 50;
 | 
			
		||||
                st.busy.hash.pop();
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            t0 = t;
 | 
			
		||||
            reader.onload = segm_next;
 | 
			
		||||
            reader.onerror = segm_err;
 | 
			
		||||
            reader.readAsArrayBuffer(
 | 
			
		||||
                bobslice.call(f, 0, sz));
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        segm_next();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function ensure_rendered(func) {
 | 
			
		||||
        var hidden = false;
 | 
			
		||||
        var keys = ['hidden', 'msHidden', 'webkitHidden'];
 | 
			
		||||
@@ -667,122 +920,88 @@ function up2k_init(have_crypto) {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function exec_hash() {
 | 
			
		||||
        if (need_filereader_cache === undefined) {
 | 
			
		||||
            st.busy.hash.push(1);
 | 
			
		||||
            return test_filereader_speed(segm_err);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var t = st.todo.hash.shift();
 | 
			
		||||
        st.busy.hash.push(t);
 | 
			
		||||
        st.bytes.hashed += t.size;
 | 
			
		||||
        t.bytes_uploaded = 0;
 | 
			
		||||
        t.t1 = new Date().getTime();
 | 
			
		||||
 | 
			
		||||
        var nchunk = 0;
 | 
			
		||||
        var chunksize = get_chunksize(t.size);
 | 
			
		||||
        var nchunks = Math.ceil(t.size / chunksize);
 | 
			
		||||
        var bpend = 0,
 | 
			
		||||
            nchunk = 0,
 | 
			
		||||
            chunksize = get_chunksize(t.size),
 | 
			
		||||
            nchunks = Math.ceil(t.size / chunksize),
 | 
			
		||||
            hashtab = {};
 | 
			
		||||
 | 
			
		||||
        // android-chrome has 180ms latency on FileReader calls,
 | 
			
		||||
        // detect this and do 32MB at a time
 | 
			
		||||
        var cache_buf = undefined,
 | 
			
		||||
            cache_ofs = 0,
 | 
			
		||||
            subchunks = 2;
 | 
			
		||||
 | 
			
		||||
        while (subchunks * chunksize <= 32 * 1024 * 1024)
 | 
			
		||||
            subchunks++;
 | 
			
		||||
 | 
			
		||||
        subchunks--;
 | 
			
		||||
        if (!need_filereader_cache)
 | 
			
		||||
            subchunks = 1;
 | 
			
		||||
 | 
			
		||||
        var pb_html = '';
 | 
			
		||||
        var pb_perc = 99.9 / nchunks;
 | 
			
		||||
        for (var a = 0; a < nchunks; a++)
 | 
			
		||||
            pb_html += '<div id="f{0}p{1}" style="width:{2}%"><div></div></div>'.format(
 | 
			
		||||
                t.n, a, pb_perc);
 | 
			
		||||
 | 
			
		||||
        ebi('f{0}p'.format(t.n)).innerHTML = pb_html;
 | 
			
		||||
 | 
			
		||||
        var reader = new FileReader();
 | 
			
		||||
        pvis.setab(t.n, nchunks);
 | 
			
		||||
        pvis.move(t.n, 'bz');
 | 
			
		||||
 | 
			
		||||
        var segm_next = function () {
 | 
			
		||||
            if (cache_buf) {
 | 
			
		||||
                return hash_calc();
 | 
			
		||||
            }
 | 
			
		||||
            reader.onload = segm_load;
 | 
			
		||||
            reader.onerror = segm_err;
 | 
			
		||||
            if (nchunk >= nchunks || (bpend > chunksize && bpend >= 32 * 1024 * 1024))
 | 
			
		||||
                return false;
 | 
			
		||||
 | 
			
		||||
            var reader = new FileReader(),
 | 
			
		||||
                nch = nchunk++,
 | 
			
		||||
                car = nch * chunksize,
 | 
			
		||||
                cdr = car + chunksize;
 | 
			
		||||
 | 
			
		||||
            var car = nchunk * chunksize;
 | 
			
		||||
            var cdr = car + chunksize * subchunks;
 | 
			
		||||
            if (cdr >= t.size)
 | 
			
		||||
                cdr = t.size;
 | 
			
		||||
 | 
			
		||||
            bpend += cdr - car;
 | 
			
		||||
 | 
			
		||||
            reader.onload = function (e) {
 | 
			
		||||
                hash_calc(nch, e.target.result);
 | 
			
		||||
            };
 | 
			
		||||
            reader.onerror = segm_err;
 | 
			
		||||
            reader.readAsArrayBuffer(
 | 
			
		||||
                bobslice.call(t.fobj, car, cdr));
 | 
			
		||||
 | 
			
		||||
            prog(t.n, nchunk, col_hashing);
 | 
			
		||||
            return true;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        var segm_load = function (e) {
 | 
			
		||||
            cache_buf = e.target.result;
 | 
			
		||||
            cache_ofs = 0;
 | 
			
		||||
            hash_calc();
 | 
			
		||||
        };
 | 
			
		||||
        var hash_calc = function (nch, buf) {
 | 
			
		||||
            while (segm_next());
 | 
			
		||||
 | 
			
		||||
        var hash_calc = function () {
 | 
			
		||||
            var buf = cache_buf;
 | 
			
		||||
            if (chunksize >= buf.byteLength)
 | 
			
		||||
                cache_buf = undefined;
 | 
			
		||||
            else {
 | 
			
		||||
                var ofs = cache_ofs;
 | 
			
		||||
                var ofs2 = ofs + Math.min(chunksize, cache_buf.byteLength - cache_ofs);
 | 
			
		||||
                cache_ofs = ofs2;
 | 
			
		||||
                buf = new Uint8Array(cache_buf).subarray(ofs, ofs2);
 | 
			
		||||
                if (ofs2 >= cache_buf.byteLength)
 | 
			
		||||
                    cache_buf = undefined;
 | 
			
		||||
            }
 | 
			
		||||
            var hash_done = function (hashbuf) {
 | 
			
		||||
                var hslice = new Uint8Array(hashbuf).subarray(0, 32);
 | 
			
		||||
                var b64str = buf2b64(hslice).replace(/=$/, '');
 | 
			
		||||
                hashtab[nch] = b64str;
 | 
			
		||||
                t.hash.push(nch);
 | 
			
		||||
                pvis.hashed(t);
 | 
			
		||||
 | 
			
		||||
            var func = function () {
 | 
			
		||||
                if (have_crypto)
 | 
			
		||||
                    crypto.subtle.digest('SHA-512', buf).then(hash_done);
 | 
			
		||||
                else {
 | 
			
		||||
                    var hasher = new asmCrypto.Sha512();
 | 
			
		||||
                    hasher.process(new Uint8Array(buf));
 | 
			
		||||
                    hasher.finish();
 | 
			
		||||
                    hash_done(hasher.result);
 | 
			
		||||
                bpend -= buf.byteLength;
 | 
			
		||||
                if (t.hash.length < nchunks) {
 | 
			
		||||
                    return segm_next();
 | 
			
		||||
                }
 | 
			
		||||
                t.hash = [];
 | 
			
		||||
                for (var a = 0; a < nchunks; a++) {
 | 
			
		||||
                    t.hash.push(hashtab[a]);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                t.t2 = new Date().getTime();
 | 
			
		||||
                if (t.n == 0 && window.location.hash == '#dbg') {
 | 
			
		||||
                    var spd = (t.size / ((t.t2 - t.t1) / 1000.)) / (1024 * 1024.);
 | 
			
		||||
                    alert('{0} ms, {1} MB/s\n'.format(t.t2 - t.t1, spd.toFixed(3)) + t.hash.join('\n'));
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                pvis.seth(t.n, 2, 'hashing done');
 | 
			
		||||
                pvis.seth(t.n, 1, '📦 wait');
 | 
			
		||||
                st.busy.hash.splice(st.busy.hash.indexOf(t), 1);
 | 
			
		||||
                st.todo.handshake.push(t);
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            if (cache_buf)
 | 
			
		||||
                ensure_rendered(func);
 | 
			
		||||
            else
 | 
			
		||||
                func();
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        var hash_done = function (hashbuf) {
 | 
			
		||||
            var hslice = new Uint8Array(hashbuf).subarray(0, 32);
 | 
			
		||||
            var b64str = buf2b64(hslice).replace(/=$/, '');
 | 
			
		||||
            t.hash.push(b64str);
 | 
			
		||||
 | 
			
		||||
            prog(t.n, nchunk, col_hashed);
 | 
			
		||||
            if (++nchunk < nchunks) {
 | 
			
		||||
                prog(t.n, nchunk, col_hashing);
 | 
			
		||||
                return segm_next();
 | 
			
		||||
            if (have_crypto)
 | 
			
		||||
                crypto.subtle.digest('SHA-512', buf).then(hash_done);
 | 
			
		||||
            else {
 | 
			
		||||
                var hasher = new asmCrypto.Sha512();
 | 
			
		||||
                hasher.process(new Uint8Array(buf));
 | 
			
		||||
                hasher.finish();
 | 
			
		||||
                hash_done(hasher.result);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            t.t2 = new Date().getTime();
 | 
			
		||||
            if (t.n == 0 && window.location.hash == '#dbg') {
 | 
			
		||||
                var spd = (t.size / ((t.t2 - t.t1) / 1000.)) / (1024 * 1024.);
 | 
			
		||||
                alert('{0} ms, {1} MB/s\n'.format(t.t2 - t.t1, spd.toFixed(3)) + t.hash.join('\n'));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            ebi('f{0}t'.format(t.n)).innerHTML = 'connecting';
 | 
			
		||||
            st.busy.hash.splice(st.busy.hash.indexOf(t), 1);
 | 
			
		||||
            st.todo.handshake.push(t);
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        var segm_err = function () {
 | 
			
		||||
            alert('y o u   b r o k e    i t\n\n(was that a folder? just files please)');
 | 
			
		||||
            alert('y o u   b r o k e    i t\nerror: ' + reader.error);
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        segm_next();
 | 
			
		||||
@@ -821,8 +1040,9 @@ function up2k_init(have_crypto) {
 | 
			
		||||
 | 
			
		||||
                        msg += '<br /><small>' + tr + ' (srv), ' + tu + ' (You), ' + sdiff + '</span></span>';
 | 
			
		||||
                    }
 | 
			
		||||
                    ebi('f{0}p'.format(t.n)).innerHTML = msg;
 | 
			
		||||
                    ebi('f{0}t'.format(t.n)).innerHTML = smsg;
 | 
			
		||||
                    pvis.seth(t.n, 2, msg);
 | 
			
		||||
                    pvis.seth(t.n, 1, smsg);
 | 
			
		||||
                    pvis.move(t.n, smsg == '404' ? 'ng' : 'ok');
 | 
			
		||||
                    st.busy.handshake.splice(st.busy.handshake.indexOf(t), 1);
 | 
			
		||||
                    st.bytes.uploaded += t.size;
 | 
			
		||||
                    t.done = true;
 | 
			
		||||
@@ -833,7 +1053,15 @@ function up2k_init(have_crypto) {
 | 
			
		||||
                if (response.name !== t.name) {
 | 
			
		||||
                    // file exists; server renamed us
 | 
			
		||||
                    t.name = response.name;
 | 
			
		||||
                    ebi('f{0}n'.format(t.n)).innerHTML = linksplit(esc(t.purl + t.name)).join(' ');
 | 
			
		||||
                    pvis.seth(t.n, 0, linksplit(esc(t.purl + t.name)).join(' '));
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                var chunksize = get_chunksize(t.size);
 | 
			
		||||
                var cdr_idx = Math.ceil(t.size / chunksize) - 1;
 | 
			
		||||
                var cdr_sz = (t.size % chunksize) || chunksize;
 | 
			
		||||
                var cbd = [];
 | 
			
		||||
                for (var a = 0; a <= cdr_idx; a++) {
 | 
			
		||||
                    cbd.push(a == cdr_idx ? cdr_sz : chunksize);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                t.postlist = [];
 | 
			
		||||
@@ -846,10 +1074,11 @@ function up2k_init(have_crypto) {
 | 
			
		||||
                            missing[a], JSON.stringify(t)));
 | 
			
		||||
 | 
			
		||||
                    t.postlist.push(idx);
 | 
			
		||||
                    cbd[idx] = 0;
 | 
			
		||||
                }
 | 
			
		||||
                for (var a = 0; a < t.hash.length; a++)
 | 
			
		||||
                    prog(t.n, a, (t.postlist.indexOf(a) == -1)
 | 
			
		||||
                        ? col_uploaded : col_hashed);
 | 
			
		||||
 | 
			
		||||
                pvis.setat(t.n, cbd);
 | 
			
		||||
                pvis.prog(t, 0, cbd[0]);
 | 
			
		||||
 | 
			
		||||
                var done = true;
 | 
			
		||||
                var msg = '🎷🐛';
 | 
			
		||||
@@ -863,7 +1092,7 @@ function up2k_init(have_crypto) {
 | 
			
		||||
                    msg = 'uploading';
 | 
			
		||||
                    done = false;
 | 
			
		||||
                }
 | 
			
		||||
                ebi('f{0}t'.format(t.n)).innerHTML = msg;
 | 
			
		||||
                pvis.seth(t.n, 1, msg);
 | 
			
		||||
                st.busy.handshake.splice(st.busy.handshake.indexOf(t), 1);
 | 
			
		||||
 | 
			
		||||
                if (done) {
 | 
			
		||||
@@ -871,8 +1100,9 @@ function up2k_init(have_crypto) {
 | 
			
		||||
                    st.bytes.uploaded += t.size - t.bytes_uploaded;
 | 
			
		||||
                    var spd1 = (t.size / ((t.t2 - t.t1) / 1000.)) / (1024 * 1024.);
 | 
			
		||||
                    var spd2 = (t.size / ((t.t4 - t.t3) / 1000.)) / (1024 * 1024.);
 | 
			
		||||
                    ebi('f{0}p'.format(t.n)).innerHTML = 'hash {0}, up {1} MB/s'.format(
 | 
			
		||||
                        spd1.toFixed(2), spd2.toFixed(2));
 | 
			
		||||
                    pvis.seth(t.n, 2, 'hash {0}, up {1} MB/s'.format(
 | 
			
		||||
                        spd1.toFixed(2), spd2.toFixed(2)));
 | 
			
		||||
                    pvis.move(t.n, 'ok');
 | 
			
		||||
                }
 | 
			
		||||
                else t.t4 = undefined;
 | 
			
		||||
 | 
			
		||||
@@ -899,18 +1129,19 @@ function up2k_init(have_crypto) {
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                if (err != "") {
 | 
			
		||||
                    ebi('f{0}t'.format(t.n)).innerHTML = "ERROR";
 | 
			
		||||
                    ebi('f{0}p'.format(t.n)).innerHTML = err;
 | 
			
		||||
                    pvis.seth(t.n, 1, "ERROR");
 | 
			
		||||
                    pvis.seth(t.n, 2, err);
 | 
			
		||||
                    pvis.move(t.n, 'ng');
 | 
			
		||||
 | 
			
		||||
                    st.busy.handshake.splice(st.busy.handshake.indexOf(t), 1);
 | 
			
		||||
                    tasker();
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
                alert("server broke (error {0}):\n\"{1}\"\n".format(
 | 
			
		||||
                    xhr.status,
 | 
			
		||||
                    (xhr.response && xhr.response.err) ||
 | 
			
		||||
                    (xhr.responseText && xhr.responseText) ||
 | 
			
		||||
                    "no further information"));
 | 
			
		||||
                alert("server broke; hs-err {0} on file [{1}]:\n".format(
 | 
			
		||||
                    xhr.status, t.name) + (
 | 
			
		||||
                        (xhr.response && xhr.response.err) ||
 | 
			
		||||
                        (xhr.responseText && xhr.responseText) ||
 | 
			
		||||
                        "no further information"));
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
@@ -939,8 +1170,10 @@ function up2k_init(have_crypto) {
 | 
			
		||||
 | 
			
		||||
        var npart = upt.npart;
 | 
			
		||||
        var t = st.files[upt.nfile];
 | 
			
		||||
        if (!t.t3)
 | 
			
		||||
            t.t3 = new Date().getTime();
 | 
			
		||||
 | 
			
		||||
        prog(t.n, npart, col_uploading);
 | 
			
		||||
        pvis.seth(t.n, 1, "🚀 send");
 | 
			
		||||
 | 
			
		||||
        var chunksize = get_chunksize(t.size);
 | 
			
		||||
        var car = npart * chunksize;
 | 
			
		||||
@@ -948,73 +1181,40 @@ function up2k_init(have_crypto) {
 | 
			
		||||
        if (cdr >= t.size)
 | 
			
		||||
            cdr = t.size;
 | 
			
		||||
 | 
			
		||||
        var reader = new FileReader();
 | 
			
		||||
 | 
			
		||||
        reader.onerror = function () {
 | 
			
		||||
            alert('y o u   b r o k e    i t\n\n(was that a folder? just files please)');
 | 
			
		||||
        var xhr = new XMLHttpRequest();
 | 
			
		||||
        xhr.upload.onprogress = function (xev) {
 | 
			
		||||
            pvis.prog(t, npart, xev.loaded);
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        reader.onload = function (e) {
 | 
			
		||||
            var xhr = new XMLHttpRequest();
 | 
			
		||||
            xhr.upload.onprogress = function (xev) {
 | 
			
		||||
                var perc = xev.loaded / (cdr - car) * 100;
 | 
			
		||||
                prog(t.n, npart, '', perc);
 | 
			
		||||
            };
 | 
			
		||||
            xhr.onload = function (xev) {
 | 
			
		||||
                if (xhr.status == 200) {
 | 
			
		||||
                    prog(t.n, npart, col_uploaded);
 | 
			
		||||
                    st.bytes.uploaded += cdr - car;
 | 
			
		||||
                    t.bytes_uploaded += cdr - car;
 | 
			
		||||
                    st.busy.upload.splice(st.busy.upload.indexOf(upt), 1);
 | 
			
		||||
                    t.postlist.splice(t.postlist.indexOf(npart), 1);
 | 
			
		||||
                    if (t.postlist.length == 0) {
 | 
			
		||||
                        t.t4 = new Date().getTime();
 | 
			
		||||
                        ebi('f{0}t'.format(t.n)).innerHTML = 'verifying';
 | 
			
		||||
                        st.todo.handshake.unshift(t);
 | 
			
		||||
                    }
 | 
			
		||||
                    tasker();
 | 
			
		||||
        xhr.onload = function (xev) {
 | 
			
		||||
            if (xhr.status == 200) {
 | 
			
		||||
                pvis.prog(t, npart, cdr - car);
 | 
			
		||||
                st.bytes.uploaded += cdr - car;
 | 
			
		||||
                t.bytes_uploaded += cdr - car;
 | 
			
		||||
                st.busy.upload.splice(st.busy.upload.indexOf(upt), 1);
 | 
			
		||||
                t.postlist.splice(t.postlist.indexOf(npart), 1);
 | 
			
		||||
                if (t.postlist.length == 0) {
 | 
			
		||||
                    t.t4 = new Date().getTime();
 | 
			
		||||
                    pvis.seth(t.n, 1, 'verifying');
 | 
			
		||||
                    st.todo.handshake.unshift(t);
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                    alert("server broke (error {0}):\n\"{1}\"\n".format(
 | 
			
		||||
                        xhr.status,
 | 
			
		||||
                tasker();
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
                alert("server broke; cu-err {0} on file [{1}]:\n".format(
 | 
			
		||||
                    xhr.status, t.name) + (
 | 
			
		||||
                        (xhr.response && xhr.response.err) ||
 | 
			
		||||
                        (xhr.responseText && xhr.responseText) ||
 | 
			
		||||
                        "no further information"));
 | 
			
		||||
            };
 | 
			
		||||
            xhr.open('POST', t.purl + 'chunkpit.php', true);
 | 
			
		||||
            //xhr.setRequestHeader("X-Up2k-Hash", t.hash[npart].substr(1) + "x");
 | 
			
		||||
            xhr.setRequestHeader("X-Up2k-Hash", t.hash[npart]);
 | 
			
		||||
            xhr.setRequestHeader("X-Up2k-Wark", t.wark);
 | 
			
		||||
            xhr.setRequestHeader('Content-Type', 'application/octet-stream');
 | 
			
		||||
            if (xhr.overrideMimeType)
 | 
			
		||||
                xhr.overrideMimeType('Content-Type', 'application/octet-stream');
 | 
			
		||||
 | 
			
		||||
            xhr.responseType = 'text';
 | 
			
		||||
            xhr.send(e.target.result);
 | 
			
		||||
 | 
			
		||||
            if (!t.t3)
 | 
			
		||||
                t.t3 = new Date().getTime();
 | 
			
		||||
        };
 | 
			
		||||
        xhr.open('POST', t.purl + 'chunkpit.php', true);
 | 
			
		||||
        xhr.setRequestHeader("X-Up2k-Hash", t.hash[npart]);
 | 
			
		||||
        xhr.setRequestHeader("X-Up2k-Wark", t.wark);
 | 
			
		||||
        xhr.setRequestHeader('Content-Type', 'application/octet-stream');
 | 
			
		||||
        if (xhr.overrideMimeType)
 | 
			
		||||
            xhr.overrideMimeType('Content-Type', 'application/octet-stream');
 | 
			
		||||
 | 
			
		||||
        reader.readAsArrayBuffer(bobslice.call(t.fobj, car, cdr));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /////
 | 
			
		||||
    ////
 | 
			
		||||
    ///   progress bar
 | 
			
		||||
    //
 | 
			
		||||
 | 
			
		||||
    function prog(nfile, nchunk, color, percent) {
 | 
			
		||||
        var n1 = ebi('f{0}p{1}'.format(nfile, nchunk));
 | 
			
		||||
        var n2 = n1.getElementsByTagName('div')[0];
 | 
			
		||||
        if (percent === undefined) {
 | 
			
		||||
            n1.style.background = color;
 | 
			
		||||
            n2.style.display = 'none';
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            n2.style.width = percent + '%';
 | 
			
		||||
            n2.style.display = 'block';
 | 
			
		||||
        }
 | 
			
		||||
        xhr.responseType = 'text';
 | 
			
		||||
        xhr.send(bobslice.call(t.fobj, car, cdr));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /////
 | 
			
		||||
@@ -1035,6 +1235,7 @@ function up2k_init(have_crypto) {
 | 
			
		||||
        if (btn.parentNode !== parent) {
 | 
			
		||||
            parent.appendChild(btn);
 | 
			
		||||
            ebi('u2conf').setAttribute('class', wide ? 'has_btn' : '');
 | 
			
		||||
            ebi('u2cards').setAttribute('class', wide ? 'w' : '');
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    window.addEventListener('resize', onresize);
 | 
			
		||||
@@ -1070,14 +1271,14 @@ function up2k_init(have_crypto) {
 | 
			
		||||
 | 
			
		||||
        var obj = ebi('nthread');
 | 
			
		||||
        if (dir.target) {
 | 
			
		||||
            obj.style.background = '#922';
 | 
			
		||||
            clmod(obj, 'err', 1);
 | 
			
		||||
            var v = Math.floor(parseInt(obj.value));
 | 
			
		||||
            if (v < 1 || v > 8 || v !== v)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            parallel_uploads = v;
 | 
			
		||||
            swrite('nthread', v);
 | 
			
		||||
            obj.style.background = '#444';
 | 
			
		||||
            clmod(obj, 'err');
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -47,6 +47,11 @@
 | 
			
		||||
	margin: -1.5em 0;
 | 
			
		||||
	padding: .8em 0;
 | 
			
		||||
	width: 100%;
 | 
			
		||||
	max-width: 12em;
 | 
			
		||||
	display: inline-block;
 | 
			
		||||
}
 | 
			
		||||
#u2conf #u2btn_cw {
 | 
			
		||||
	text-align: right;
 | 
			
		||||
}
 | 
			
		||||
#u2notbtn {
 | 
			
		||||
	display: none;
 | 
			
		||||
@@ -72,6 +77,7 @@
 | 
			
		||||
}
 | 
			
		||||
#u2tab td:nth-child(2) {
 | 
			
		||||
	width: 5em;
 | 
			
		||||
	white-space: nowrap;
 | 
			
		||||
}
 | 
			
		||||
#u2tab td:nth-child(3) {
 | 
			
		||||
	width: 40%;
 | 
			
		||||
@@ -83,6 +89,35 @@
 | 
			
		||||
#u2tab tr+tr:hover td {
 | 
			
		||||
	background: #222;
 | 
			
		||||
}
 | 
			
		||||
#u2cards {
 | 
			
		||||
	margin: 2.5em auto -2.5em auto;
 | 
			
		||||
	text-align: center;
 | 
			
		||||
}
 | 
			
		||||
#u2cards.w {
 | 
			
		||||
	width: 45em;
 | 
			
		||||
	text-align: left;
 | 
			
		||||
}
 | 
			
		||||
#u2cards a {
 | 
			
		||||
	padding: .2em 1em;
 | 
			
		||||
	border: 1px solid #777;
 | 
			
		||||
	border-width: 0 0 1px 0;
 | 
			
		||||
	background: linear-gradient(to bottom, #333, #222);
 | 
			
		||||
}
 | 
			
		||||
#u2cards a:first-child {
 | 
			
		||||
	border-radius: .4em 0 0 0;
 | 
			
		||||
}
 | 
			
		||||
#u2cards a:last-child {
 | 
			
		||||
	border-radius: 0 .4em 0 0;
 | 
			
		||||
}
 | 
			
		||||
#u2cards a.act {
 | 
			
		||||
	border-width: 1px 1px 0 1px;
 | 
			
		||||
	border-radius: .3em .3em 0 0;
 | 
			
		||||
	margin-left: -1px;
 | 
			
		||||
	background: transparent;
 | 
			
		||||
}
 | 
			
		||||
#u2cards span {
 | 
			
		||||
	color: #fff;
 | 
			
		||||
}
 | 
			
		||||
#u2conf {
 | 
			
		||||
	margin: 1em auto;
 | 
			
		||||
	width: 30em;
 | 
			
		||||
@@ -106,6 +141,9 @@
 | 
			
		||||
	font-size: 1.2em;
 | 
			
		||||
	padding: .15em 0;
 | 
			
		||||
}
 | 
			
		||||
#u2conf .txtbox.err {
 | 
			
		||||
	background: #922;
 | 
			
		||||
}
 | 
			
		||||
#u2conf a {
 | 
			
		||||
	color: #fff;
 | 
			
		||||
	background: #c38;
 | 
			
		||||
@@ -193,24 +231,6 @@
 | 
			
		||||
.prog {
 | 
			
		||||
	font-family: monospace;
 | 
			
		||||
}
 | 
			
		||||
.prog>div {
 | 
			
		||||
	display: inline-block;
 | 
			
		||||
	position: relative;
 | 
			
		||||
	overflow: hidden;
 | 
			
		||||
	margin: 0;
 | 
			
		||||
	padding: 0;
 | 
			
		||||
	height: 1.1em;
 | 
			
		||||
	margin-bottom: -.15em;
 | 
			
		||||
	box-shadow: -1px -1px 0 inset rgba(255,255,255,0.1);
 | 
			
		||||
}
 | 
			
		||||
.prog>div>div {
 | 
			
		||||
	width: 0%;
 | 
			
		||||
	position: absolute;
 | 
			
		||||
	left: 0;
 | 
			
		||||
	top: 0;
 | 
			
		||||
	bottom: 0;
 | 
			
		||||
	background: #0a0;
 | 
			
		||||
}
 | 
			
		||||
#u2tab a>span {
 | 
			
		||||
	font-weight: bold;
 | 
			
		||||
	font-style: italic;
 | 
			
		||||
@@ -221,3 +241,35 @@
 | 
			
		||||
	float: right;
 | 
			
		||||
	margin-bottom: -.3em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
html.light #u2btn {
 | 
			
		||||
	box-shadow: .4em .4em 0 #ccc;
 | 
			
		||||
}
 | 
			
		||||
html.light #u2cards span {
 | 
			
		||||
	color: #000;
 | 
			
		||||
}
 | 
			
		||||
html.light #u2cards a {
 | 
			
		||||
	background: linear-gradient(to bottom, #eee, #fff);
 | 
			
		||||
}
 | 
			
		||||
html.light #u2cards a.act {
 | 
			
		||||
	background: inherit;
 | 
			
		||||
}
 | 
			
		||||
html.light #u2conf .txtbox {
 | 
			
		||||
	background: #fff;
 | 
			
		||||
	color: #444;
 | 
			
		||||
}
 | 
			
		||||
html.light #u2conf .txtbox.err {
 | 
			
		||||
	background: #f96;
 | 
			
		||||
	color: #300;
 | 
			
		||||
}
 | 
			
		||||
html.light #u2cdesc {
 | 
			
		||||
	background: #fff;
 | 
			
		||||
	border: none;
 | 
			
		||||
}
 | 
			
		||||
html.light #op_up2k.srch #u2btn {
 | 
			
		||||
	border-color: #a80;
 | 
			
		||||
}
 | 
			
		||||
@@ -79,12 +79,23 @@
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
            <div id="u2cards">
 | 
			
		||||
                <a href="#" act="ok">ok <span>0</span></a><a
 | 
			
		||||
                href="#" act="ng">ng <span>0</span></a><a
 | 
			
		||||
                href="#" act="done">done <span>0</span></a><a
 | 
			
		||||
                href="#" act="bz" class="act">busy <span>0</span></a><a
 | 
			
		||||
                href="#" act="q">que <span>0</span></a>
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
            <table id="u2tab">
 | 
			
		||||
                <tr>
 | 
			
		||||
                    <td>filename</td>
 | 
			
		||||
                    <td>status</td>
 | 
			
		||||
                    <td>progress<a href="#" id="u2cleanup">cleanup</a></td>
 | 
			
		||||
                </tr>
 | 
			
		||||
                <thead>
 | 
			
		||||
                    <tr>
 | 
			
		||||
                        <td>filename</td>
 | 
			
		||||
                        <td>status</td>
 | 
			
		||||
                        <td>progress<a href="#" id="u2cleanup">cleanup</a></td>
 | 
			
		||||
                    </tr>
 | 
			
		||||
                </thead>
 | 
			
		||||
                <tbody></tbody>
 | 
			
		||||
            </table>
 | 
			
		||||
 | 
			
		||||
            <p id="u2foot"></p>
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user