mirror of
https://github.com/9001/copyparty.git
synced 2025-10-28 02:23:33 +00:00
Compare commits
61 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
161d57bdda | ||
|
|
bae0d440bf | ||
|
|
fff052dde1 | ||
|
|
73b06eaa02 | ||
|
|
08a8ebed17 | ||
|
|
74d07426b3 | ||
|
|
69a2bba99a | ||
|
|
4d685d78ee | ||
|
|
5845ec3f49 | ||
|
|
13373426fe | ||
|
|
8e55551a06 | ||
|
|
12a3f0ac31 | ||
|
|
18e33edc88 | ||
|
|
c72c5ad4ee | ||
|
|
0fbc81ab2f | ||
|
|
af0a34cf82 | ||
|
|
b4590c5398 | ||
|
|
f787a66230 | ||
|
|
b21a99fd62 | ||
|
|
eb16306cde | ||
|
|
7bc23687e3 | ||
|
|
e1eaa057f2 | ||
|
|
97c264ca3e | ||
|
|
cf848ab1f7 | ||
|
|
cf83f9b0fd | ||
|
|
d98e361083 | ||
|
|
ce7f5309c7 | ||
|
|
75c485ced7 | ||
|
|
9c6e2ec012 | ||
|
|
1a02948a61 | ||
|
|
8b05ba4ba1 | ||
|
|
21e2874cb7 | ||
|
|
360ed5c46c | ||
|
|
5099bc365d | ||
|
|
12986da147 | ||
|
|
23e72797bc | ||
|
|
ac7b6f8f55 | ||
|
|
981b9ff11e | ||
|
|
4186906f4c | ||
|
|
0850d24e0c | ||
|
|
7ab8334c96 | ||
|
|
a4d7329ab7 | ||
|
|
3f4eae6bce | ||
|
|
518cf4be57 | ||
|
|
71096182be | ||
|
|
6452e927ea | ||
|
|
bc70cfa6f0 | ||
|
|
2b6e5ebd2d | ||
|
|
c761bd799a | ||
|
|
2f7c2fdee4 | ||
|
|
70a76ec343 | ||
|
|
7c3f64abf2 | ||
|
|
f5f38f195c | ||
|
|
7e84f4f015 | ||
|
|
4802f8cf07 | ||
|
|
cc05e67d8f | ||
|
|
2b6b174517 | ||
|
|
a1d05e6e12 | ||
|
|
f95ceb6a9b | ||
|
|
8f91b0726d | ||
|
|
97807f4383 |
172
README.md
172
README.md
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
## summary
|
## summary
|
||||||
|
|
||||||
turn your phone or raspi into a portable file server with resumable uploads/downloads using IE6 or any other browser
|
turn your phone or raspi into a portable file server with resumable uploads/downloads using *any* web browser
|
||||||
|
|
||||||
* server runs on anything with `py2.7` or `py3.3+`
|
* server runs on anything with `py2.7` or `py3.3+`
|
||||||
* browse/upload with IE4 / netscape4.0 on win3.11 (heh)
|
* browse/upload with IE4 / netscape4.0 on win3.11 (heh)
|
||||||
@@ -19,49 +19,53 @@ turn your phone or raspi into a portable file server with resumable uploads/down
|
|||||||
## readme toc
|
## readme toc
|
||||||
|
|
||||||
* top
|
* top
|
||||||
* [quickstart](#quickstart)
|
* [quickstart](#quickstart) - download [copyparty-sfx.py](https://github.com/9001/copyparty/releases/latest/download/copyparty-sfx.py) and you're all set!
|
||||||
* [on debian](#on-debian)
|
* [on debian](#on-debian) - recommended additional steps on debian
|
||||||
* [notes](#notes)
|
* [notes](#notes) - general notes
|
||||||
* [status](#status)
|
* [status](#status) - summary: all planned features work! now please enjoy the bloatening
|
||||||
* [testimonials](#testimonials)
|
* [testimonials](#testimonials) - small collection of user feedback
|
||||||
* [bugs](#bugs)
|
* [bugs](#bugs)
|
||||||
* [general bugs](#general-bugs)
|
* [general bugs](#general-bugs)
|
||||||
* [not my bugs](#not-my-bugs)
|
* [not my bugs](#not-my-bugs)
|
||||||
* [the browser](#the-browser)
|
* [accounts and volumes](#accounts-and-volumes) - per-folder, per-user permissions
|
||||||
* [tabs](#tabs)
|
* [the browser](#the-browser) - accessing a copyparty server using a web-browser
|
||||||
* [hotkeys](#hotkeys)
|
* [tabs](#tabs) - the main tabs in the ui
|
||||||
* [navpane](#navpane)
|
* [hotkeys](#hotkeys) - the browser has the following hotkeys (always qwerty)
|
||||||
* [thumbnails](#thumbnails)
|
* [navpane](#navpane) - switching between breadcrumbs or navpane
|
||||||
* [zip downloads](#zip-downloads)
|
* [thumbnails](#thumbnails) - press `g` to toggle image/video thumbnails instead of the file listing
|
||||||
* [uploading](#uploading)
|
* [zip downloads](#zip-downloads) - download folders (or file selections) as `zip` or `tar` files
|
||||||
* [file-search](#file-search)
|
* [uploading](#uploading) - web-browsers can upload using `bup` and `up2k`
|
||||||
* [file manager](#file-manager)
|
* [file-search](#file-search) - drop files/folders into up2k to see if they exist on the server
|
||||||
* [batch rename](#batch-rename)
|
* [unpost](#unpost) - undo/delete accidental uploads
|
||||||
* [markdown viewer](#markdown-viewer)
|
* [file manager](#file-manager) - cut/paste, rename, and delete files/folders (if you have permission)
|
||||||
|
* [batch rename](#batch-rename) - select some files and press F2 to bring up the rename UI
|
||||||
|
* [markdown viewer](#markdown-viewer) - and there are *two* editors
|
||||||
* [other tricks](#other-tricks)
|
* [other tricks](#other-tricks)
|
||||||
* [searching](#searching)
|
* [searching](#searching) - search by size, date, path/name, mp3-tags, ...
|
||||||
* [server config](#server-config)
|
* [server config](#server-config)
|
||||||
* [upload rules](#upload-rules)
|
* [file indexing](#file-indexing)
|
||||||
* [database location](#database-location)upload rules
|
* [upload rules](#upload-rules) - set upload rules using volume flags, some examples
|
||||||
* [metadata from audio files](#metadata-from-audio-files)
|
* [compress uploads](#compress-uploads) - files can be autocompressed on upload
|
||||||
* [file parser plugins](#file-parser-plugins)
|
* [database location](#database-location) - can be stored in-volume (default) or elsewhere
|
||||||
|
* [metadata from audio files](#metadata-from-audio-files) - set `-e2t` to index tags on upload
|
||||||
|
* [file parser plugins](#file-parser-plugins) - provide custom parsers to index additional tags
|
||||||
* [complete examples](#complete-examples)
|
* [complete examples](#complete-examples)
|
||||||
* [browser support](#browser-support)
|
* [browser support](#browser-support) - TLDR: yes
|
||||||
* [client examples](#client-examples)
|
* [client examples](#client-examples) - interact with copyparty using non-browser clients
|
||||||
* [up2k](#up2k)
|
* [up2k](#up2k) - quick outline of the up2k protocol, see [uploading](#uploading) for the web-client
|
||||||
* [performance](#performance)
|
* [performance](#performance) - defaults are good for most cases
|
||||||
* [dependencies](#dependencies)
|
* [dependencies](#dependencies) - mandatory deps
|
||||||
* [optional dependencies](#optional-dependencies)
|
* [optional dependencies](#optional-dependencies) - install these to enable bonus features
|
||||||
* [install recommended deps](#install-recommended-deps)
|
* [install recommended deps](#install-recommended-deps)
|
||||||
* [optional gpl stuff](#optional-gpl-stuff)
|
* [optional gpl stuff](#optional-gpl-stuff)
|
||||||
* [sfx](#sfx)
|
* [sfx](#sfx) - there are two self-contained "binaries"
|
||||||
* [sfx repack](#sfx-repack)
|
* [sfx repack](#sfx-repack) - reduce the size of an sfx by removing features
|
||||||
* [install on android](#install-on-android)
|
* [install on android](#install-on-android)
|
||||||
* [building](#building)
|
* [building](#building)
|
||||||
* [dev env setup](#dev-env-setup)
|
* [dev env setup](#dev-env-setup)
|
||||||
* [just the sfx](#just-the-sfx)
|
* [just the sfx](#just-the-sfx)
|
||||||
* [complete release](#complete-release)
|
* [complete release](#complete-release)
|
||||||
* [todo](#todo)
|
* [todo](#todo) - roughly sorted by priority
|
||||||
* [discarded ideas](#discarded-ideas)
|
* [discarded ideas](#discarded-ideas)
|
||||||
|
|
||||||
|
|
||||||
@@ -86,7 +90,9 @@ you may also want these, especially on servers:
|
|||||||
|
|
||||||
### on debian
|
### on debian
|
||||||
|
|
||||||
recommended steps to enable audio metadata and thumbnails (from images and videos):
|
recommended additional steps on debian
|
||||||
|
|
||||||
|
enable audio metadata and thumbnails (from images and videos):
|
||||||
|
|
||||||
* as root, run the following:
|
* as root, run the following:
|
||||||
`apt install python3 python3-pip python3-dev ffmpeg`
|
`apt install python3 python3-pip python3-dev ffmpeg`
|
||||||
@@ -99,7 +105,7 @@ recommended steps to enable audio metadata and thumbnails (from images and video
|
|||||||
|
|
||||||
## notes
|
## notes
|
||||||
|
|
||||||
general:
|
general notes:
|
||||||
* paper-printing is affected by dark/light-mode! use lightmode for color, darkmode for grayscale
|
* paper-printing is affected by dark/light-mode! use lightmode for color, darkmode for grayscale
|
||||||
* because no browsers currently implement the media-query to do this properly orz
|
* because no browsers currently implement the media-query to do this properly orz
|
||||||
|
|
||||||
@@ -124,7 +130,7 @@ summary: all planned features work! now please enjoy the bloatening
|
|||||||
* ☑ basic: plain multipart, ie6 support
|
* ☑ basic: plain multipart, ie6 support
|
||||||
* ☑ [up2k](#uploading): js, resumable, multithreaded
|
* ☑ [up2k](#uploading): js, resumable, multithreaded
|
||||||
* ☑ stash: simple PUT filedropper
|
* ☑ stash: simple PUT filedropper
|
||||||
* ☑ unpost: undo/delete accidental uploads
|
* ☑ [unpost](#unpost): undo/delete accidental uploads
|
||||||
* ☑ symlink/discard existing files (content-matching)
|
* ☑ symlink/discard existing files (content-matching)
|
||||||
* download
|
* download
|
||||||
* ☑ single files in browser
|
* ☑ single files in browser
|
||||||
@@ -184,6 +190,7 @@ small collection of user feedback
|
|||||||
|
|
||||||
# accounts and volumes
|
# accounts and volumes
|
||||||
|
|
||||||
|
per-folder, per-user permissions
|
||||||
* `-a usr:pwd` adds account `usr` with password `pwd`
|
* `-a usr:pwd` adds account `usr` with password `pwd`
|
||||||
* `-v .::r` adds current-folder `.` as the webroot, `r`eadable by anyone
|
* `-v .::r` adds current-folder `.` as the webroot, `r`eadable by anyone
|
||||||
* the syntax is `-v src:dst:perm:perm:...` so local-path, url-path, and one or more permissions to set
|
* the syntax is `-v src:dst:perm:perm:...` so local-path, url-path, and one or more permissions to set
|
||||||
@@ -208,14 +215,17 @@ example:
|
|||||||
|
|
||||||
# the browser
|
# the browser
|
||||||
|
|
||||||

|
accessing a copyparty server using a web-browser
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
## tabs
|
## tabs
|
||||||
|
|
||||||
* `[🔎]` search by size, date, path/name, mp3-tags ... see [searching](#searching)
|
the main tabs in the ui
|
||||||
* `[🧯]` unpost: undo/delete accidental uploads
|
* `[🔎]` [search](#searching) by size, date, path/name, mp3-tags ...
|
||||||
* `[🚀]` and `[🎈]` are the uploaders, see [uploading](#uploading)
|
* `[🧯]` [unpost](#unpost): undo/delete accidental uploads
|
||||||
|
* `[🚀]` and `[🎈]` are the [uploaders](#uploading)
|
||||||
* `[📂]` mkdir: create directories
|
* `[📂]` mkdir: create directories
|
||||||
* `[📝]` new-md: create a new markdown document
|
* `[📝]` new-md: create a new markdown document
|
||||||
* `[📟]` send-msg: either to server-log or into textfiles if `--urlform save`
|
* `[📟]` send-msg: either to server-log or into textfiles if `--urlform save`
|
||||||
@@ -225,7 +235,7 @@ example:
|
|||||||
|
|
||||||
## hotkeys
|
## hotkeys
|
||||||
|
|
||||||
the browser has the following hotkeys (assumes qwerty, ignores actual layout)
|
the browser has the following hotkeys (always qwerty)
|
||||||
* `B` toggle breadcrumbs / navpane
|
* `B` toggle breadcrumbs / navpane
|
||||||
* `I/K` prev/next folder
|
* `I/K` prev/next folder
|
||||||
* `M` parent folder (or unexpand current)
|
* `M` parent folder (or unexpand current)
|
||||||
@@ -274,14 +284,18 @@ the browser has the following hotkeys (assumes qwerty, ignores actual layout)
|
|||||||
|
|
||||||
## navpane
|
## navpane
|
||||||
|
|
||||||
by default there's a breadcrumbs path; you can replace this with a navpane (tree-browser sidebar thing) by clicking the `🌲` or pressing the `B` hotkey
|
switching between breadcrumbs or navpane
|
||||||
|
|
||||||
|
click the `🌲` or pressing the `B` hotkey to toggle between breadcrumbs path (default), or a navpane (tree-browser sidebar thing)
|
||||||
|
|
||||||
click `[-]` and `[+]` (or hotkeys `A`/`D`) to adjust the size, and the `[a]` toggles if the tree should widen dynamically as you go deeper or stay fixed-size
|
click `[-]` and `[+]` (or hotkeys `A`/`D`) to adjust the size, and the `[a]` toggles if the tree should widen dynamically as you go deeper or stay fixed-size
|
||||||
|
|
||||||
|
|
||||||
## thumbnails
|
## thumbnails
|
||||||
|
|
||||||

|
press `g` to toggle image/video thumbnails instead of the file listing
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
it does static images with Pillow and uses FFmpeg for video files, so you may want to `--no-thumb` or maybe just `--no-vthumb` depending on how dangerous your users are
|
it does static images with Pillow and uses FFmpeg for video files, so you may want to `--no-thumb` or maybe just `--no-vthumb` depending on how dangerous your users are
|
||||||
|
|
||||||
@@ -292,7 +306,9 @@ in the grid/thumbnail view, if the audio player panel is open, songs will start
|
|||||||
|
|
||||||
## zip downloads
|
## zip downloads
|
||||||
|
|
||||||
the `zip` link next to folders can produce various types of zip/tar files using these alternatives in the browser settings tab:
|
download folders (or file selections) as `zip` or `tar` files
|
||||||
|
|
||||||
|
select which type of archive you want in the browser settings tab:
|
||||||
|
|
||||||
| name | url-suffix | description |
|
| name | url-suffix | description |
|
||||||
|--|--|--|
|
|--|--|--|
|
||||||
@@ -309,15 +325,16 @@ the `zip` link next to folders can produce various types of zip/tar files using
|
|||||||
|
|
||||||
you can also zip a selection of files or folders by clicking them in the browser, that brings up a selection editor and zip button in the bottom right
|
you can also zip a selection of files or folders by clicking them in the browser, that brings up a selection editor and zip button in the bottom right
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
|
||||||
## uploading
|
## uploading
|
||||||
|
|
||||||
two upload methods are available in the html client:
|
web-browsers can upload using `bup` and `up2k`:
|
||||||
* `[🎈] bup`, the basic uploader, supports almost every browser since netscape 4.0
|
* `[🎈] bup`, the basic uploader, supports almost every browser since netscape 4.0
|
||||||
* `[🚀] up2k`, the fancy one
|
* `[🚀] up2k`, the fancy one
|
||||||
|
|
||||||
you can undo/delete uploads using `[🧯] unpost` if the server is running with `-e2d`
|
you can undo/delete uploads using `[🧯]` [unpost](#unpost)
|
||||||
|
|
||||||
up2k has several advantages:
|
up2k has several advantages:
|
||||||
* you can drop folders into the browser (files are added recursively)
|
* you can drop folders into the browser (files are added recursively)
|
||||||
@@ -331,7 +348,7 @@ up2k has several advantages:
|
|||||||
|
|
||||||
see [up2k](#up2k) for details on how it works
|
see [up2k](#up2k) for details on how it works
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
**protip:** you can avoid scaring away users with [docs/minimal-up2k.html](docs/minimal-up2k.html) which makes it look [much simpler](https://user-images.githubusercontent.com/241032/118311195-dd6ca380-b4ef-11eb-86f3-75a3ff2e1332.png)
|
**protip:** you can avoid scaring away users with [docs/minimal-up2k.html](docs/minimal-up2k.html) which makes it look [much simpler](https://user-images.githubusercontent.com/241032/118311195-dd6ca380-b4ef-11eb-86f3-75a3ff2e1332.png)
|
||||||
|
|
||||||
@@ -339,7 +356,7 @@ the up2k UI is the epitome of polished inutitive experiences:
|
|||||||
* "parallel uploads" specifies how many chunks to upload at the same time
|
* "parallel uploads" specifies how many chunks to upload at the same time
|
||||||
* `[🏃]` analysis of other files should continue while one is uploading
|
* `[🏃]` analysis of other files should continue while one is uploading
|
||||||
* `[💭]` ask for confirmation before files are added to the list
|
* `[💭]` ask for confirmation before files are added to the list
|
||||||
* `[💤]` sync uploading between other copyparty tabs so only one is active
|
* `[💤]` sync uploading between other copyparty browser-tabs so only one is active
|
||||||
* `[🔎]` switch between upload and file-search mode
|
* `[🔎]` switch between upload and file-search mode
|
||||||
|
|
||||||
and then theres the tabs below it,
|
and then theres the tabs below it,
|
||||||
@@ -350,11 +367,14 @@ and then theres the tabs below it,
|
|||||||
* plus up to 3 entries each from `[done]` and `[que]` for context
|
* plus up to 3 entries each from `[done]` and `[que]` for context
|
||||||
* `[que]` is all the files that are still queued
|
* `[que]` is all the files that are still queued
|
||||||
|
|
||||||
|
|
||||||
### file-search
|
### file-search
|
||||||
|
|
||||||

|
drop files/folders into up2k to see if they exist on the server
|
||||||
|
|
||||||
in the `[🚀 up2k]` tab, after toggling the `[🔎]` switch green, any files/folders you drop onto the dropzone will be hashed on the client-side. Each hash is sent to the server which checks if that file exists somewhere already
|

|
||||||
|
|
||||||
|
in the `[🚀 up2k]` tab, after toggling the `[🔎]` switch green, any files/folders you drop onto the dropzone will be hashed on the client-side. Each hash is sent to the server which checks if that file exists somewhere
|
||||||
|
|
||||||
files go into `[ok]` if they exist (and you get a link to where it is), otherwise they land in `[ng]`
|
files go into `[ok]` if they exist (and you get a link to where it is), otherwise they land in `[ng]`
|
||||||
* the main reason filesearch is combined with the uploader is cause the code was too spaghetti to separate it out somewhere else, this is no longer the case but now i've warmed up to the idea too much
|
* the main reason filesearch is combined with the uploader is cause the code was too spaghetti to separate it out somewhere else, this is no longer the case but now i've warmed up to the idea too much
|
||||||
@@ -366,19 +386,28 @@ note that since up2k has to read the file twice, `[🎈 bup]` can be up to 2x fa
|
|||||||
up2k has saved a few uploads from becoming corrupted in-transfer already; caught an android phone on wifi redhanded in wireshark with a bitflip, however bup with https would *probably* have noticed as well (thanks to tls also functioning as an integrity check)
|
up2k has saved a few uploads from becoming corrupted in-transfer already; caught an android phone on wifi redhanded in wireshark with a bitflip, however bup with https would *probably* have noticed as well (thanks to tls also functioning as an integrity check)
|
||||||
|
|
||||||
|
|
||||||
|
### unpost
|
||||||
|
|
||||||
|
undo/delete accidental uploads
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
you can unpost even if you don't have regular move/delete access, however only for files uploaded within the past `--unpost` seconds (default 12 hours) and the server must be running with `-e2d`
|
||||||
|
|
||||||
|
|
||||||
## file manager
|
## file manager
|
||||||
|
|
||||||
if you have the required permissions, you can cut/paste, rename, and delete files/folders
|
cut/paste, rename, and delete files/folders (if you have permission)
|
||||||
|
|
||||||
you can move files across browser tabs (cut in one tab, paste in another)
|
you can move files across browser tabs (cut in one tab, paste in another)
|
||||||
|
|
||||||
|
|
||||||
## batch rename
|
## batch rename
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
select some files and press F2 to bring up the rename UI
|
select some files and press F2 to bring up the rename UI
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
quick explanation of the buttons,
|
quick explanation of the buttons,
|
||||||
* `[✅ apply rename]` confirms and begins renaming
|
* `[✅ apply rename]` confirms and begins renaming
|
||||||
* `[❌ cancel]` aborts and closes the rename window
|
* `[❌ cancel]` aborts and closes the rename window
|
||||||
@@ -422,6 +451,8 @@ the metadata keys you can use in the format field are the ones in the file-brows
|
|||||||
|
|
||||||
## markdown viewer
|
## markdown viewer
|
||||||
|
|
||||||
|
and there are *two* editors
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
* the document preview has a max-width which is the same as an A4 paper when printed
|
* the document preview has a max-width which is the same as an A4 paper when printed
|
||||||
@@ -436,7 +467,9 @@ the metadata keys you can use in the format field are the ones in the file-brows
|
|||||||
|
|
||||||
## searching
|
## searching
|
||||||
|
|
||||||

|
search by size, date, path/name, mp3-tags, ...
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
when started with `-e2dsa` copyparty will scan/index all your files. This avoids duplicates on upload, and also makes the volumes searchable through the web-ui:
|
when started with `-e2dsa` copyparty will scan/index all your files. This avoids duplicates on upload, and also makes the volumes searchable through the web-ui:
|
||||||
* make search queries by `size`/`date`/`directory-path`/`filename`, or...
|
* make search queries by `size`/`date`/`directory-path`/`filename`, or...
|
||||||
@@ -451,6 +484,8 @@ add the argument `-e2ts` to also scan/index tags from music files, which brings
|
|||||||
|
|
||||||
# server config
|
# server config
|
||||||
|
|
||||||
|
## file indexing
|
||||||
|
|
||||||
file indexing relies on two databases, the up2k filetree (`-e2d`) and the metadata tags (`-e2t`). Configuration can be done through arguments, volume flags, or a mix of both.
|
file indexing relies on two databases, the up2k filetree (`-e2d`) and the metadata tags (`-e2t`). Configuration can be done through arguments, volume flags, or a mix of both.
|
||||||
|
|
||||||
through arguments:
|
through arguments:
|
||||||
@@ -480,7 +515,7 @@ if you set `--no-hash`, you can enable hashing for specific volumes using flag `
|
|||||||
|
|
||||||
## upload rules
|
## upload rules
|
||||||
|
|
||||||
you can set upload rules using volume flags, some examples:
|
set upload rules using volume flags, some examples:
|
||||||
|
|
||||||
* `:c,sz=1k-3m` sets allowed filesize between 1 KiB and 3 MiB inclusive (suffixes: b, k, m, g)
|
* `:c,sz=1k-3m` sets allowed filesize between 1 KiB and 3 MiB inclusive (suffixes: b, k, m, g)
|
||||||
* `:c,nosub` disallow uploading into subdirectories; goes well with `rotn` and `rotf`:
|
* `:c,nosub` disallow uploading into subdirectories; goes well with `rotn` and `rotf`:
|
||||||
@@ -499,7 +534,9 @@ you can also set transaction limits which apply per-IP and per-volume, but these
|
|||||||
|
|
||||||
## compress uploads
|
## compress uploads
|
||||||
|
|
||||||
files can be autocompressed on upload, either on user-request (if config allows) or forced by server-config
|
files can be autocompressed on upload
|
||||||
|
|
||||||
|
compression is either on user-request (if config allows) or forced by server-config
|
||||||
|
|
||||||
* volume flag `gz` allows gz compression
|
* volume flag `gz` allows gz compression
|
||||||
* volume flag `xz` allows lzma compression
|
* volume flag `xz` allows lzma compression
|
||||||
@@ -520,6 +557,8 @@ some examples,
|
|||||||
|
|
||||||
## database location
|
## database location
|
||||||
|
|
||||||
|
can be stored in-volume (default) or elsewhere
|
||||||
|
|
||||||
copyparty creates a subfolder named `.hist` inside each volume where it stores the database, thumbnails, and some other stuff
|
copyparty creates a subfolder named `.hist` inside each volume where it stores the database, thumbnails, and some other stuff
|
||||||
|
|
||||||
this can instead be kept in a single place using the `--hist` argument, or the `hist=` volume flag, or a mix of both:
|
this can instead be kept in a single place using the `--hist` argument, or the `hist=` volume flag, or a mix of both:
|
||||||
@@ -533,6 +572,8 @@ note:
|
|||||||
|
|
||||||
## metadata from audio files
|
## metadata from audio files
|
||||||
|
|
||||||
|
set `-e2t` to index tags on upload
|
||||||
|
|
||||||
`-mte` decides which tags to index and display in the browser (and also the display order), this can be changed per-volume:
|
`-mte` decides which tags to index and display in the browser (and also the display order), this can be changed per-volume:
|
||||||
* `-v ~/music::r:c,mte=title,artist` indexes and displays *title* followed by *artist*
|
* `-v ~/music::r:c,mte=title,artist` indexes and displays *title* followed by *artist*
|
||||||
|
|
||||||
@@ -556,6 +597,8 @@ see the beautiful mess of a dictionary in [mtag.py](https://github.com/9001/copy
|
|||||||
|
|
||||||
## file parser plugins
|
## file parser plugins
|
||||||
|
|
||||||
|
provide custom parsers to index additional tags
|
||||||
|
|
||||||
copyparty can invoke external programs to collect additional metadata for files using `mtp` (either as argument or volume flag), there is a default timeout of 30sec
|
copyparty can invoke external programs to collect additional metadata for files using `mtp` (either as argument or volume flag), there is a default timeout of 30sec
|
||||||
|
|
||||||
* `-mtp .bpm=~/bin/audio-bpm.py` will execute `~/bin/audio-bpm.py` with the audio file as argument 1 to provide the `.bpm` tag, if that does not exist in the audio metadata
|
* `-mtp .bpm=~/bin/audio-bpm.py` will execute `~/bin/audio-bpm.py` with the audio file as argument 1 to provide the `.bpm` tag, if that does not exist in the audio metadata
|
||||||
@@ -576,6 +619,8 @@ copyparty can invoke external programs to collect additional metadata for files
|
|||||||
|
|
||||||
# browser support
|
# browser support
|
||||||
|
|
||||||
|
TLDR: yes
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
`ie` = internet-explorer, `ff` = firefox, `c` = chrome, `iOS` = iPhone/iPad, `Andr` = Android
|
`ie` = internet-explorer, `ff` = firefox, `c` = chrome, `iOS` = iPhone/iPad, `Andr` = Android
|
||||||
@@ -624,6 +669,8 @@ quick summary of more eccentric web-browsers trying to view a directory index:
|
|||||||
|
|
||||||
# client examples
|
# client examples
|
||||||
|
|
||||||
|
interact with copyparty using non-browser clients
|
||||||
|
|
||||||
* javascript: dump some state into a file (two separate examples)
|
* javascript: dump some state into a file (two separate examples)
|
||||||
* `await fetch('https://127.0.0.1:3923/', {method:"PUT", body: JSON.stringify(foo)});`
|
* `await fetch('https://127.0.0.1:3923/', {method:"PUT", body: JSON.stringify(foo)});`
|
||||||
* `var xhr = new XMLHttpRequest(); xhr.open('POST', 'https://127.0.0.1:3923/msgs?raw'); xhr.send('foo');`
|
* `var xhr = new XMLHttpRequest(); xhr.open('POST', 'https://127.0.0.1:3923/msgs?raw'); xhr.send('foo');`
|
||||||
@@ -666,7 +713,9 @@ quick outline of the up2k protocol, see [uploading](#uploading) for the web-clie
|
|||||||
|
|
||||||
# performance
|
# performance
|
||||||
|
|
||||||
defaults are good for most cases, don't mind the `cannot efficiently use multiple CPU cores` message, it's very unlikely to be a problem
|
defaults are good for most cases
|
||||||
|
|
||||||
|
you can ignore the `cannot efficiently use multiple CPU cores` message, it's very unlikely to be a problem
|
||||||
|
|
||||||
below are some tweaks roughly ordered by usefulness:
|
below are some tweaks roughly ordered by usefulness:
|
||||||
|
|
||||||
@@ -683,11 +732,14 @@ below are some tweaks roughly ordered by usefulness:
|
|||||||
|
|
||||||
# dependencies
|
# dependencies
|
||||||
|
|
||||||
|
mandatory deps:
|
||||||
* `jinja2` (is built into the SFX)
|
* `jinja2` (is built into the SFX)
|
||||||
|
|
||||||
|
|
||||||
## optional dependencies
|
## optional dependencies
|
||||||
|
|
||||||
|
install these to enable bonus features
|
||||||
|
|
||||||
enable music tags:
|
enable music tags:
|
||||||
* either `mutagen` (fast, pure-python, skips a few tags, makes copyparty GPL? idk)
|
* either `mutagen` (fast, pure-python, skips a few tags, makes copyparty GPL? idk)
|
||||||
* or `ffprobe` (20x slower, more accurate, possibly dangerous depending on your distro and users)
|
* or `ffprobe` (20x slower, more accurate, possibly dangerous depending on your distro and users)
|
||||||
@@ -720,7 +772,7 @@ these are standalone programs and will never be imported / evaluated by copypart
|
|||||||
|
|
||||||
# sfx
|
# sfx
|
||||||
|
|
||||||
currently there are two self-contained "binaries":
|
there are two self-contained "binaries":
|
||||||
* [copyparty-sfx.py](https://github.com/9001/copyparty/releases/latest/download/copyparty-sfx.py) -- pure python, works everywhere, **recommended**
|
* [copyparty-sfx.py](https://github.com/9001/copyparty/releases/latest/download/copyparty-sfx.py) -- pure python, works everywhere, **recommended**
|
||||||
* [copyparty-sfx.sh](https://github.com/9001/copyparty/releases/latest/download/copyparty-sfx.sh) -- smaller, but only for linux and macos, kinda deprecated
|
* [copyparty-sfx.sh](https://github.com/9001/copyparty/releases/latest/download/copyparty-sfx.sh) -- smaller, but only for linux and macos, kinda deprecated
|
||||||
|
|
||||||
@@ -731,6 +783,8 @@ pls note that `copyparty-sfx.sh` will fail if you rename `copyparty-sfx.py` to `
|
|||||||
|
|
||||||
## sfx repack
|
## sfx repack
|
||||||
|
|
||||||
|
reduce the size of an sfx by removing features
|
||||||
|
|
||||||
if you don't need all the features, you can repack the sfx and save a bunch of space; all you need is an sfx and a copy of this repo (nothing else to download or build, except if you're on windows then you need msys2 or WSL)
|
if you don't need all the features, you can repack the sfx and save a bunch of space; all you need is an sfx and a copy of this repo (nothing else to download or build, except if you're on windows then you need msys2 or WSL)
|
||||||
* `525k` size of original sfx.py as of v0.11.30
|
* `525k` size of original sfx.py as of v0.11.30
|
||||||
* `315k` after `./scripts/make-sfx.sh re no-ogv`
|
* `315k` after `./scripts/make-sfx.sh re no-ogv`
|
||||||
@@ -774,7 +828,7 @@ pip install black bandit pylint flake8 # vscode tooling
|
|||||||
|
|
||||||
## just the sfx
|
## just the sfx
|
||||||
|
|
||||||
unless you need to modify something in the web-dependencies, it's faster to grab those from a previous release:
|
grab the web-dependencies from a previous sfx (unless you need to modify something in those):
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
rm -rf copyparty/web/deps
|
rm -rf copyparty/web/deps
|
||||||
@@ -794,7 +848,7 @@ then build the sfx using any of the following examples:
|
|||||||
|
|
||||||
## complete release
|
## complete release
|
||||||
|
|
||||||
also builds the sfx so disregard the sfx section above
|
also builds the sfx so skip the sfx section above
|
||||||
|
|
||||||
in the `scripts` folder:
|
in the `scripts` folder:
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
# coding: utf-8
|
# coding: utf-8
|
||||||
|
|
||||||
VERSION = (0, 13, 5)
|
VERSION = (0, 13, 8)
|
||||||
CODENAME = "future-proof"
|
CODENAME = "future-proof"
|
||||||
BUILD_DT = (2021, 8, 16)
|
BUILD_DT = (2021, 8, 29)
|
||||||
|
|
||||||
S_VERSION = ".".join(map(str, VERSION))
|
S_VERSION = ".".join(map(str, VERSION))
|
||||||
S_BUILD_DT = "{0:04d}-{1:02d}-{2:02d}".format(*BUILD_DT)
|
S_BUILD_DT = "{0:04d}-{1:02d}-{2:02d}".format(*BUILD_DT)
|
||||||
|
|||||||
@@ -1782,7 +1782,7 @@ class HttpCli(object):
|
|||||||
for fn in self.args.th_covers.split(","):
|
for fn in self.args.th_covers.split(","):
|
||||||
fp = os.path.join(abspath, fn)
|
fp = os.path.join(abspath, fn)
|
||||||
if bos.path.exists(fp):
|
if bos.path.exists(fp):
|
||||||
vrem = "{}/{}".format(vrem.rstrip("/"), fn)
|
vrem = "{}/{}".format(vrem.rstrip("/"), fn).strip("/")
|
||||||
is_dir = False
|
is_dir = False
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|||||||
@@ -1428,7 +1428,11 @@ class Up2k(object):
|
|||||||
ptop = vn.realpath
|
ptop = vn.realpath
|
||||||
atop = vn.canonical(rem, False)
|
atop = vn.canonical(rem, False)
|
||||||
adir, fn = os.path.split(atop)
|
adir, fn = os.path.split(atop)
|
||||||
st = bos.lstat(atop)
|
try:
|
||||||
|
st = bos.lstat(atop)
|
||||||
|
except:
|
||||||
|
raise Pebkac(400, "file not found on disk (already deleted?)")
|
||||||
|
|
||||||
scandir = not self.args.no_scandir
|
scandir = not self.args.no_scandir
|
||||||
if stat.S_ISLNK(st.st_mode) or stat.S_ISREG(st.st_mode):
|
if stat.S_ISLNK(st.st_mode) or stat.S_ISREG(st.st_mode):
|
||||||
dbv, vrem = self.asrv.vfs.get(vpath, uname, *permsets[0])
|
dbv, vrem = self.asrv.vfs.get(vpath, uname, *permsets[0])
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ import subprocess as sp # nosec
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from collections import Counter
|
from collections import Counter
|
||||||
|
|
||||||
from .__init__ import PY2, WINDOWS, ANYWIN
|
from .__init__ import PY2, WINDOWS, ANYWIN, VT100
|
||||||
from .stolen import surrogateescape
|
from .stolen import surrogateescape
|
||||||
|
|
||||||
FAKE_MP = False
|
FAKE_MP = False
|
||||||
@@ -58,7 +58,7 @@ except:
|
|||||||
return struct.unpack(f.decode("ascii"), *a, **ka)
|
return struct.unpack(f.decode("ascii"), *a, **ka)
|
||||||
|
|
||||||
|
|
||||||
ansi_re = re.compile("\033\\[[^m]*m")
|
ansi_re = re.compile("\033\\[[^mK]*[mK]")
|
||||||
|
|
||||||
|
|
||||||
surrogateescape.register_surrogateescape()
|
surrogateescape.register_surrogateescape()
|
||||||
@@ -207,17 +207,22 @@ class ProgressPrinter(threading.Thread):
|
|||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
msg = None
|
msg = None
|
||||||
|
fmt = " {}\033[K\r" if VT100 else " {} $\r"
|
||||||
while not self.end:
|
while not self.end:
|
||||||
time.sleep(0.1)
|
time.sleep(0.1)
|
||||||
if msg == self.msg or self.end:
|
if msg == self.msg or self.end:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
msg = self.msg
|
msg = self.msg
|
||||||
uprint(" {}\033[K\r".format(msg))
|
uprint(fmt.format(msg))
|
||||||
if PY2:
|
if PY2:
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
|
|
||||||
print("\033[K", end="")
|
if VT100:
|
||||||
|
print("\033[K", end="")
|
||||||
|
elif msg:
|
||||||
|
print("------------------------")
|
||||||
|
|
||||||
sys.stdout.flush() # necessary on win10 even w/ stderr btw
|
sys.stdout.flush() # necessary on win10 even w/ stderr btw
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
:root {
|
:root {
|
||||||
--grid-sz: 10em;
|
--grid-sz: 10em;
|
||||||
|
--grid-ln: 3;
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: 'scp';
|
||||||
|
src: local('Source Code Pro Regular'), local('SourceCodePro-Regular'), url(/.cpr/deps/scp.woff2) format('woff2');
|
||||||
}
|
}
|
||||||
* {
|
* {
|
||||||
line-height: 1.2em;
|
line-height: 1.2em;
|
||||||
@@ -23,7 +28,7 @@ html, body {
|
|||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
pre, code, tt {
|
pre, code, tt {
|
||||||
font-family: monospace, monospace;
|
font-family: 'scp', monospace, monospace;
|
||||||
}
|
}
|
||||||
#path,
|
#path,
|
||||||
#path * {
|
#path * {
|
||||||
@@ -113,7 +118,7 @@ a, #files tbody div a:last-child {
|
|||||||
border-top: 1px solid #383838;
|
border-top: 1px solid #383838;
|
||||||
}
|
}
|
||||||
#files tbody td:nth-child(3) {
|
#files tbody td:nth-child(3) {
|
||||||
font-family: monospace, monospace;
|
font-family: 'scp', monospace, monospace;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
padding-right: 1em;
|
padding-right: 1em;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
@@ -208,8 +213,8 @@ a, #files tbody div a:last-child {
|
|||||||
color: #720;
|
color: #720;
|
||||||
text-shadow: 0 0 .3em #b80;
|
text-shadow: 0 0 .3em #b80;
|
||||||
}
|
}
|
||||||
#ggrid a.play,
|
#ggrid>a.play,
|
||||||
html.light #ggrid a.play {
|
html.light #ggrid>a.play {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
background: #750;
|
background: #750;
|
||||||
border-color: #c90;
|
border-color: #c90;
|
||||||
@@ -217,36 +222,38 @@ html.light #ggrid a.play {
|
|||||||
box-shadow: 0 .1em 1.2em #b83;
|
box-shadow: 0 .1em 1.2em #b83;
|
||||||
}
|
}
|
||||||
#files tbody tr.sel td,
|
#files tbody tr.sel td,
|
||||||
#ggrid a.sel,
|
#ggrid>a.sel,
|
||||||
html.light #ggrid a.sel {
|
#ggrid>a[tt].sel,
|
||||||
|
html.light #ggrid>a.sel,
|
||||||
|
html.light #ggrid>a[tt].sel {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
background: #925;
|
background: #925;
|
||||||
border-color: #c37;
|
border-color: #c37;
|
||||||
}
|
}
|
||||||
#files tbody tr.sel:hover td,
|
#files tbody tr.sel:hover td,
|
||||||
#files tbody tr.sel:focus td,
|
#files tbody tr.sel:focus td,
|
||||||
#ggrid a.sel:hover,
|
#ggrid>a.sel:hover,
|
||||||
html.light #ggrid a.sel:hover {
|
html.light #ggrid>a.sel:hover {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
background: #d39;
|
background: #d39;
|
||||||
border-color: #d48;
|
border-color: #d48;
|
||||||
text-shadow: 1px 1px 0 #804;
|
text-shadow: 1px 1px 0 #804;
|
||||||
}
|
}
|
||||||
#ggrid a.sel,
|
#ggrid>a.sel,
|
||||||
html.light #ggrid a.sel {
|
html.light #ggrid>a.sel {
|
||||||
border-top: 1px solid #d48;
|
border-top: 1px solid #d48;
|
||||||
box-shadow: 0 .1em 1.2em #b36;
|
box-shadow: 0 .1em 1.2em #b36;
|
||||||
transition: all 0.2s cubic-bezier(.2, 2.2, .5, 1); /* https://cubic-bezier.com/#.4,2,.7,1 */
|
transition: all 0.2s cubic-bezier(.2, 2.2, .5, 1); /* https://cubic-bezier.com/#.4,2,.7,1 */
|
||||||
}
|
}
|
||||||
#ggrid a.sel img,
|
#ggrid>a.sel img,
|
||||||
#ggrid a.play img {
|
#ggrid>a.play img {
|
||||||
opacity: .7;
|
opacity: .7;
|
||||||
filter: contrast(130%) brightness(107%);
|
filter: contrast(130%) brightness(107%);
|
||||||
}
|
}
|
||||||
#ggrid a.sel img {
|
#ggrid>a.sel img {
|
||||||
box-shadow: 0 0 1em #b36;
|
box-shadow: 0 0 1em #b36;
|
||||||
}
|
}
|
||||||
#ggrid a.play img {
|
#ggrid>a.play img {
|
||||||
box-shadow: 0 0 1em #b83;
|
box-shadow: 0 0 1em #b83;
|
||||||
}
|
}
|
||||||
#files tr.sel a {
|
#files tr.sel a {
|
||||||
@@ -310,7 +317,7 @@ html.light #ggrid a.sel {
|
|||||||
}
|
}
|
||||||
#widget {
|
#widget {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
font-size: 1.5em;
|
font-size: 1.4em;
|
||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
bottom: -6em;
|
bottom: -6em;
|
||||||
@@ -336,10 +343,11 @@ html.light #ggrid a.sel {
|
|||||||
cursor: url(/.cpr/dd/4.png), pointer;
|
cursor: url(/.cpr/dd/4.png), pointer;
|
||||||
animation: cursor 500ms;
|
animation: cursor 500ms;
|
||||||
position: relative;
|
position: relative;
|
||||||
top: -.06em;
|
font-size: .9em;
|
||||||
|
top: -.04em;
|
||||||
}
|
}
|
||||||
#wtgrid {
|
#wtgrid {
|
||||||
font-size: .8em;
|
font-size: .75em;
|
||||||
top: -.12em;
|
top: -.12em;
|
||||||
}
|
}
|
||||||
#wtgrid:hover,
|
#wtgrid:hover,
|
||||||
@@ -359,7 +367,8 @@ html.light #ggrid a.sel {
|
|||||||
#wtoggle {
|
#wtoggle {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
top: -1.2em;
|
font-size: .8em;
|
||||||
|
top: -1em;
|
||||||
right: 0;
|
right: 0;
|
||||||
height: 1em;
|
height: 1em;
|
||||||
font-size: 2em;
|
font-size: 2em;
|
||||||
@@ -369,7 +378,7 @@ html.light #ggrid a.sel {
|
|||||||
background: #3c3c3c;
|
background: #3c3c3c;
|
||||||
box-shadow: 0 0 .5em #222;
|
box-shadow: 0 0 .5em #222;
|
||||||
border-radius: .3em 0 0 0;
|
border-radius: .3em 0 0 0;
|
||||||
padding: .2em .2em;
|
padding: 0;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
}
|
}
|
||||||
#wzip, #wnp {
|
#wzip, #wnp {
|
||||||
@@ -402,7 +411,7 @@ html.light #ggrid a.sel {
|
|||||||
#wzip a {
|
#wzip a {
|
||||||
font-size: .5em;
|
font-size: .5em;
|
||||||
padding: 0 .3em;
|
padding: 0 .3em;
|
||||||
margin: -.3em .2em;
|
margin: -.3em .1em;
|
||||||
position: relative;
|
position: relative;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
@@ -426,7 +435,7 @@ html.light #wfm a:not(.en) {
|
|||||||
}
|
}
|
||||||
#wzip a {
|
#wzip a {
|
||||||
font-size: .4em;
|
font-size: .4em;
|
||||||
margin: -.3em .3em;
|
margin: -.3em .1em;
|
||||||
}
|
}
|
||||||
#wtoggle.sel #wzip #selzip {
|
#wtoggle.sel #wzip #selzip {
|
||||||
top: -.6em;
|
top: -.6em;
|
||||||
@@ -526,24 +535,9 @@ html.light #wfm a:not(.en) {
|
|||||||
box-shadow: 0 -.15em .2em #000 inset;
|
box-shadow: 0 -.15em .2em #000 inset;
|
||||||
padding-bottom: .3em;
|
padding-bottom: .3em;
|
||||||
}
|
}
|
||||||
#ops i {
|
|
||||||
font-size: 1.5em;
|
|
||||||
}
|
|
||||||
#ops i:before {
|
|
||||||
content: 'x';
|
|
||||||
color: #282828;
|
|
||||||
text-shadow: 0 0 .08em #01a7e1;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
#ops i:after {
|
|
||||||
content: 'x';
|
|
||||||
color: #282828;
|
|
||||||
text-shadow: 0 0 .08em #ff3f1a;
|
|
||||||
margin-left: -.35em;
|
|
||||||
font-size: 1.05em;
|
|
||||||
}
|
|
||||||
#ops,
|
#ops,
|
||||||
.opbox {
|
.opbox,
|
||||||
|
#u2etas {
|
||||||
border: 1px solid #3a3a3a;
|
border: 1px solid #3a3a3a;
|
||||||
box-shadow: 0 0 1em #222 inset;
|
box-shadow: 0 0 1em #222 inset;
|
||||||
}
|
}
|
||||||
@@ -692,6 +686,7 @@ input.eq_gain {
|
|||||||
left: 0;
|
left: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
top: 7em;
|
top: 7em;
|
||||||
|
overflow-x: hidden;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
-ms-scroll-chaining: none;
|
-ms-scroll-chaining: none;
|
||||||
overscroll-behavior-y: none;
|
overscroll-behavior-y: none;
|
||||||
@@ -702,10 +697,10 @@ input.eq_gain {
|
|||||||
position: sticky;
|
position: sticky;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
top: 0;
|
top: 0;
|
||||||
height: 2.2em;
|
height: 2.2em;
|
||||||
line-height: 2.2em;
|
line-height: 2.2em;
|
||||||
border-bottom: 1px solid #555;
|
border-bottom: 1px solid #555;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
#thx_ff {
|
#thx_ff {
|
||||||
padding: 5em 0;
|
padding: 5em 0;
|
||||||
@@ -723,8 +718,8 @@ input.eq_gain {
|
|||||||
}
|
}
|
||||||
#treeul {
|
#treeul {
|
||||||
position: relative;
|
position: relative;
|
||||||
left: -1.7em;
|
left: -2em;
|
||||||
width: calc(100% + 1.3em);
|
width: calc(100% + 2em);
|
||||||
}
|
}
|
||||||
.btn {
|
.btn {
|
||||||
padding: .2em .4em;
|
padding: .2em .4em;
|
||||||
@@ -785,7 +780,9 @@ input.eq_gain {
|
|||||||
color: #fff;
|
color: #fff;
|
||||||
}
|
}
|
||||||
#treeul a:first-child {
|
#treeul a:first-child {
|
||||||
font-family: monospace, monospace;
|
font-family: 'scp', monospace, monospace;
|
||||||
|
font-size: 1.2em;
|
||||||
|
line-height: 0;
|
||||||
}
|
}
|
||||||
.dumb_loader_thing {
|
.dumb_loader_thing {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
@@ -875,10 +872,12 @@ input.eq_gain {
|
|||||||
background: #3c3c3c;
|
background: #3c3c3c;
|
||||||
border: 1px solid #444;
|
border: 1px solid #444;
|
||||||
border-radius: .3em;
|
border-radius: .3em;
|
||||||
padding: .5em;
|
padding: .2em .5em;
|
||||||
|
line-height: 2.3em;
|
||||||
margin: 0 1.5em 1em .4em;
|
margin: 0 1.5em 1em .4em;
|
||||||
position: sticky;
|
position: sticky;
|
||||||
top: -.3em;
|
top: -.3em;
|
||||||
|
z-index: 1;
|
||||||
}
|
}
|
||||||
html.light #ghead {
|
html.light #ghead {
|
||||||
background: #f7f7f7;
|
background: #f7f7f7;
|
||||||
@@ -888,10 +887,22 @@ html.light #ghead {
|
|||||||
position: relative;
|
position: relative;
|
||||||
top: 0;
|
top: 0;
|
||||||
}
|
}
|
||||||
|
#ghead>span {
|
||||||
|
white-space: pre;
|
||||||
|
padding-left: .3em;
|
||||||
|
}
|
||||||
#ggrid {
|
#ggrid {
|
||||||
padding-top: .5em;
|
padding-top: .5em;
|
||||||
}
|
}
|
||||||
#ggrid a {
|
#ggrid>a>span {
|
||||||
|
overflow: hidden;
|
||||||
|
display: block;
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-line-clamp: var(--grid-ln);
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
padding-top: .3em;
|
||||||
|
}
|
||||||
|
#ggrid>a {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: 10em;
|
width: 10em;
|
||||||
width: var(--grid-sz);
|
width: var(--grid-sz);
|
||||||
@@ -905,7 +916,10 @@ html.light #ghead {
|
|||||||
padding: .3em;
|
padding: .3em;
|
||||||
margin: .5em;
|
margin: .5em;
|
||||||
}
|
}
|
||||||
#ggrid a img {
|
#ggrid>a[tt] {
|
||||||
|
background: linear-gradient(135deg, #383838 95%, #555 95%);
|
||||||
|
}
|
||||||
|
#ggrid>a img {
|
||||||
border-radius: .2em;
|
border-radius: .2em;
|
||||||
max-width: 10em;
|
max-width: 10em;
|
||||||
max-width: var(--grid-sz);
|
max-width: var(--grid-sz);
|
||||||
@@ -914,27 +928,33 @@ html.light #ghead {
|
|||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
#ggrid a span {
|
#ggrid>a.dir:before {
|
||||||
padding: .2em .3em;
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
#ggrid span.dir:before {
|
|
||||||
content: '📂';
|
content: '📂';
|
||||||
line-height: 0;
|
|
||||||
font-size: 2em;
|
|
||||||
margin: -.7em .1em -.5em -.3em;
|
|
||||||
}
|
}
|
||||||
#ggrid a:hover {
|
#ggrid>a:before {
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
padding: .3em 0;
|
||||||
|
margin: -.4em;
|
||||||
|
text-shadow: 0 0 .1em #000;
|
||||||
|
background: linear-gradient(135deg,rgba(255,255,255,0) 50%,rgba(255,255,255,0.2));
|
||||||
|
border-radius: .3em;
|
||||||
|
font-size: 2em;
|
||||||
|
}
|
||||||
|
#ggrid>a:hover {
|
||||||
background: #444;
|
background: #444;
|
||||||
border-color: #555;
|
border-color: #555;
|
||||||
color: #fd9;
|
color: #fd9;
|
||||||
}
|
}
|
||||||
html.light #ggrid a {
|
html.light #ggrid>a {
|
||||||
background: #f7f7f7;
|
background: #f7f7f7;
|
||||||
border-color: #ddd;
|
border-color: #ddd;
|
||||||
box-shadow: 0 .1em .2em #ddd;
|
box-shadow: 0 .1em .2em #ddd;
|
||||||
}
|
}
|
||||||
html.light #ggrid a:hover {
|
html.light #ggrid>a[tt] {
|
||||||
|
background: linear-gradient(135deg, #f7f7f7 95%, #ccc 95%);
|
||||||
|
}
|
||||||
|
html.light #ggrid>a:hover {
|
||||||
background: #fff;
|
background: #fff;
|
||||||
border-color: #ccc;
|
border-color: #ccc;
|
||||||
color: #015;
|
color: #015;
|
||||||
@@ -978,7 +998,7 @@ html.light #rui {
|
|||||||
padding: .2em 0 .2em .5em;
|
padding: .2em 0 .2em .5em;
|
||||||
}
|
}
|
||||||
#rn_vadv input {
|
#rn_vadv input {
|
||||||
font-family: monospace, monospace;
|
font-family: 'scp', monospace, monospace;
|
||||||
}
|
}
|
||||||
#rui td+td,
|
#rui td+td,
|
||||||
#rui td input[type="text"] {
|
#rui td input[type="text"] {
|
||||||
@@ -1011,8 +1031,12 @@ html.light #rui {
|
|||||||
#pvol,
|
#pvol,
|
||||||
#barbuf,
|
#barbuf,
|
||||||
#barpos,
|
#barpos,
|
||||||
|
a.btn,
|
||||||
|
#u2btn,
|
||||||
#u2conf label,
|
#u2conf label,
|
||||||
#rui label,
|
#rui label,
|
||||||
|
#modal-ok,
|
||||||
|
#modal-ng,
|
||||||
#ops {
|
#ops {
|
||||||
-webkit-user-select: none;
|
-webkit-user-select: none;
|
||||||
-moz-user-select: none;
|
-moz-user-select: none;
|
||||||
@@ -1051,7 +1075,8 @@ html.light {
|
|||||||
}
|
}
|
||||||
html.light #ops,
|
html.light #ops,
|
||||||
html.light .opbox,
|
html.light .opbox,
|
||||||
html.light #srch_form {
|
html.light #srch_form,
|
||||||
|
html.light #u2etas {
|
||||||
background: #f7f7f7;
|
background: #f7f7f7;
|
||||||
box-shadow: 0 0 .3em #ddd;
|
box-shadow: 0 0 .3em #ddd;
|
||||||
border-color: #f7f7f7;
|
border-color: #f7f7f7;
|
||||||
@@ -1308,11 +1333,11 @@ html.light #tree::-webkit-scrollbar {
|
|||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
.full-image {
|
.full-image {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
.full-image figure {
|
.full-image figure {
|
||||||
display: inline;
|
display: inline;
|
||||||
@@ -1555,7 +1580,7 @@ html.light #bbox-overlay figcaption a {
|
|||||||
color: #333;
|
color: #333;
|
||||||
}
|
}
|
||||||
#u2conf #u2btn {
|
#u2conf #u2btn {
|
||||||
margin: -1.5em 0;
|
margin: -2.4em 0;
|
||||||
padding: .8em 0;
|
padding: .8em 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: 12em;
|
max-width: 12em;
|
||||||
@@ -1574,6 +1599,7 @@ html.light #bbox-overlay figcaption a {
|
|||||||
line-height: 1.3em;
|
line-height: 1.3em;
|
||||||
}
|
}
|
||||||
#u2tab {
|
#u2tab {
|
||||||
|
border-collapse: collapse;
|
||||||
margin: 3em auto;
|
margin: 3em auto;
|
||||||
width: calc(100% - 2em);
|
width: calc(100% - 2em);
|
||||||
max-width: 100em;
|
max-width: 100em;
|
||||||
@@ -1584,7 +1610,7 @@ html.light #bbox-overlay figcaption a {
|
|||||||
#u2tab td {
|
#u2tab td {
|
||||||
border: 1px solid #ccc;
|
border: 1px solid #ccc;
|
||||||
border-width: 0 0px 1px 0;
|
border-width: 0 0px 1px 0;
|
||||||
padding: .1em .3em;
|
padding: .2em .3em;
|
||||||
}
|
}
|
||||||
#u2tab td:nth-child(2) {
|
#u2tab td:nth-child(2) {
|
||||||
width: 5em;
|
width: 5em;
|
||||||
@@ -1601,17 +1627,51 @@ html.light #bbox-overlay figcaption a {
|
|||||||
#u2tab tbody tr:hover td {
|
#u2tab tbody tr:hover td {
|
||||||
background: #222;
|
background: #222;
|
||||||
}
|
}
|
||||||
|
#u2etas {
|
||||||
|
background: #333;
|
||||||
|
padding: .2em .5em;
|
||||||
|
border-radius: .5em;
|
||||||
|
border-width: .25em 0;
|
||||||
|
width: 17em;
|
||||||
|
text-align: center;
|
||||||
|
white-space: nowrap;
|
||||||
|
display: inline-block;
|
||||||
|
font-family: 'scp', monospace, monospace;
|
||||||
|
}
|
||||||
|
#u2etas.o {
|
||||||
|
width: 20em;
|
||||||
|
}
|
||||||
|
#u2etas .o {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
#u2etas.o .o {
|
||||||
|
display: unset;
|
||||||
|
}
|
||||||
|
#u2etaw {
|
||||||
|
width: 18em;
|
||||||
|
font-size: .94em;
|
||||||
|
margin: 1.8em auto .5em auto;
|
||||||
|
}
|
||||||
|
#u2etas.o #u2etaw {
|
||||||
|
width: 21em;
|
||||||
|
}
|
||||||
#u2cards {
|
#u2cards {
|
||||||
padding: 1em 0 .3em 1em;
|
padding: 1em 1em .3em 1em;
|
||||||
margin: 1.5em auto -2.5em auto;
|
margin: 0 auto -1.5em auto;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
min-width: 24em;
|
||||||
}
|
}
|
||||||
#u2cards.w {
|
#u2cards.w {
|
||||||
width: 45em;
|
width: 44em;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
#u2etaw.w {
|
||||||
|
width: 52em;
|
||||||
|
text-align: right;
|
||||||
|
margin: 3em auto -2.7em auto;
|
||||||
|
}
|
||||||
#u2cards a {
|
#u2cards a {
|
||||||
padding: .2em 1em;
|
padding: .2em 1em;
|
||||||
border: 1px solid #777;
|
border: 1px solid #777;
|
||||||
@@ -1718,6 +1778,14 @@ html.light #bbox-overlay figcaption a {
|
|||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
opacity: .2;
|
opacity: .2;
|
||||||
}
|
}
|
||||||
|
#u2flagblock {
|
||||||
|
display: none;
|
||||||
|
margin: 2em auto 4em auto;
|
||||||
|
padding: .5em;
|
||||||
|
max-width: 27em;
|
||||||
|
text-align: center;
|
||||||
|
border: .2em dashed rgba(128, 128, 128, 0.3);
|
||||||
|
}
|
||||||
#u2foot {
|
#u2foot {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
@@ -1752,7 +1820,27 @@ html.light #u2foot .warn span {
|
|||||||
margin-bottom: -1em;
|
margin-bottom: -1em;
|
||||||
}
|
}
|
||||||
.prog {
|
.prog {
|
||||||
font-family: monospace, monospace;
|
font-family: 'scp', monospace, monospace;
|
||||||
|
}
|
||||||
|
#u2tab span.inf,
|
||||||
|
#u2tab span.ok,
|
||||||
|
#u2tab span.err {
|
||||||
|
color: #fff;
|
||||||
|
padding: .22em;
|
||||||
|
border-radius: .2em;
|
||||||
|
border: 2px solid #f0f;
|
||||||
|
}
|
||||||
|
#u2tab span.inf {
|
||||||
|
background: #07a;
|
||||||
|
border-color: #0be;
|
||||||
|
}
|
||||||
|
#u2tab span.ok {
|
||||||
|
background: #380;
|
||||||
|
border-color: #8e4;
|
||||||
|
}
|
||||||
|
#u2tab span.err {
|
||||||
|
background: #900;
|
||||||
|
border-color: #d06;
|
||||||
}
|
}
|
||||||
#u2tab a>span {
|
#u2tab a>span {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ ebi('widget').innerHTML = (
|
|||||||
'<div id="wtoggle">' +
|
'<div id="wtoggle">' +
|
||||||
'<span id="wfm"><a' +
|
'<span id="wfm"><a' +
|
||||||
' href="#" id="fren" tt="rename selected item$NHotkey: F2">✎<span>name</span></a><a' +
|
' href="#" id="fren" tt="rename selected item$NHotkey: F2">✎<span>name</span></a><a' +
|
||||||
' href="#" id="fdel" tt="delete selected items$NHotkey: ctrl-K">⌫<span>delete</span></a><a' +
|
' href="#" id="fdel" tt="delete selected items$NHotkey: ctrl-K">⌫<span>del.</span></a><a' +
|
||||||
' href="#" id="fcut" tt="cut selected items <small>(then paste somewhere else)</small>$NHotkey: ctrl-X">✂<span>cut</span></a><a' +
|
' href="#" id="fcut" tt="cut selected items <small>(then paste somewhere else)</small>$NHotkey: ctrl-X">✂<span>cut</span></a><a' +
|
||||||
' href="#" id="fpst" tt="paste a previously cut/copied selection$NHotkey: ctrl-V">📋<span>paste</span></a>' +
|
' href="#" id="fpst" tt="paste a previously cut/copied selection$NHotkey: ctrl-V">📋<span>paste</span></a>' +
|
||||||
'</span><span id="wzip"><a' +
|
'</span><span id="wzip"><a' +
|
||||||
@@ -43,7 +43,7 @@ ebi('widget').innerHTML = (
|
|||||||
' href="#" id="npirc" tt="copy irc-formatted track info">📋irc</a><a' +
|
' href="#" id="npirc" tt="copy irc-formatted track info">📋irc</a><a' +
|
||||||
' href="#" id="nptxt" tt="copy plaintext track info">📋txt</a>' +
|
' href="#" id="nptxt" tt="copy plaintext track info">📋txt</a>' +
|
||||||
'</span><a' +
|
'</span><a' +
|
||||||
' href="#" id="wtgrid" tt="toggle grid/list view">田</a><a' +
|
' href="#" id="wtgrid" tt="toggle grid/list view$NHotkey: G">田</a><a' +
|
||||||
' href="#" id="wtico">♫</a>' +
|
' href="#" id="wtico">♫</a>' +
|
||||||
'</div>' +
|
'</div>' +
|
||||||
'<div id="widgeti">' +
|
'<div id="widgeti">' +
|
||||||
@@ -102,6 +102,12 @@ ebi('op_up2k').innerHTML = (
|
|||||||
' </div>\n' +
|
' </div>\n' +
|
||||||
'</div>\n' +
|
'</div>\n' +
|
||||||
|
|
||||||
|
'<div id="u2etaw"><div id="u2etas"><div class="o">\n' +
|
||||||
|
' hash: <span id="u2etah" tt="average <em>hashing</em> speed, and estimated time until finish">(no uploads are queued yet)</span><br />\n' +
|
||||||
|
' send: <span id="u2etau" tt="average <em>upload</em> speed and estimated time until finish">(no uploads are queued yet)</span><br />\n' +
|
||||||
|
' </div><span class="o">done: </span><span id="u2etat" tt="average <em>total</em> speed and estimated time until finish">(no uploads are queued yet)</span>\n' +
|
||||||
|
'</div></div>\n' +
|
||||||
|
|
||||||
'<div id="u2cards">\n' +
|
'<div id="u2cards">\n' +
|
||||||
' <a href="#" act="ok" tt="completed successfully">ok <span>0</span></a><a\n' +
|
' <a href="#" act="ok" tt="completed successfully">ok <span>0</span></a><a\n' +
|
||||||
' href="#" act="ng" tt="failed / rejected / not-found">ng <span>0</span></a><a\n' +
|
' href="#" act="ng" tt="failed / rejected / not-found">ng <span>0</span></a><a\n' +
|
||||||
@@ -121,6 +127,7 @@ ebi('op_up2k').innerHTML = (
|
|||||||
' <tbody></tbody>\n' +
|
' <tbody></tbody>\n' +
|
||||||
'</table>\n' +
|
'</table>\n' +
|
||||||
|
|
||||||
|
'<p id="u2flagblock"><b>the files were added to the queue</b><br />however there is a busy up2k in another browser tab,<br />so waiting for that to finish first</p>\n' +
|
||||||
'<p id="u2foot"></p>\n' +
|
'<p id="u2foot"></p>\n' +
|
||||||
'<p id="u2footfoot" data-perm="write">( you can use the <a href="#" id="u2nope">basic uploader</a> if you don\'t need lastmod timestamps, resumable uploads, or progress bars )</p>'
|
'<p id="u2footfoot" data-perm="write">( you can use the <a href="#" id="u2nope">basic uploader</a> if you don\'t need lastmod timestamps, resumable uploads, or progress bars )</p>'
|
||||||
);
|
);
|
||||||
@@ -392,6 +399,7 @@ function MPlayer() {
|
|||||||
r.au_native2 = null;
|
r.au_native2 = null;
|
||||||
r.au_ogvjs = null;
|
r.au_ogvjs = null;
|
||||||
r.au_ogvjs2 = null;
|
r.au_ogvjs2 = null;
|
||||||
|
r.loading = false;
|
||||||
r.tracks = {};
|
r.tracks = {};
|
||||||
r.order = [];
|
r.order = [];
|
||||||
|
|
||||||
@@ -415,18 +423,14 @@ function MPlayer() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
r.vol = sread('vol');
|
r.vol = clamp(fcfg_get('vol', 0.5), 0, 1);
|
||||||
if (r.vol !== null)
|
|
||||||
r.vol = parseFloat(r.vol);
|
|
||||||
else
|
|
||||||
r.vol = 0.5;
|
|
||||||
|
|
||||||
r.expvol = function (v) {
|
r.expvol = function (v) {
|
||||||
return 0.5 * v + 0.5 * v * v;
|
return 0.5 * v + 0.5 * v * v;
|
||||||
};
|
};
|
||||||
|
|
||||||
r.setvol = function (vol) {
|
r.setvol = function (vol) {
|
||||||
r.vol = Math.max(Math.min(vol, 1), 0);
|
r.vol = clamp(vol, 0, 1);
|
||||||
swrite('vol', vol);
|
swrite('vol', vol);
|
||||||
r.stopfade(true);
|
r.stopfade(true);
|
||||||
|
|
||||||
@@ -673,7 +677,7 @@ var pbar = (function () {
|
|||||||
|
|
||||||
bctx.clearRect(0, 0, bc.w, bc.h);
|
bctx.clearRect(0, 0, bc.w, bc.h);
|
||||||
|
|
||||||
if (!mp.au)
|
if (!mp.au || mp.loading)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var sm = bc.w * 1.0 / mp.au.duration,
|
var sm = bc.w * 1.0 / mp.au.duration,
|
||||||
@@ -695,25 +699,26 @@ var pbar = (function () {
|
|||||||
r.drawpos = function () {
|
r.drawpos = function () {
|
||||||
var bc = r.buf,
|
var bc = r.buf,
|
||||||
pc = r.pos,
|
pc = r.pos,
|
||||||
pctx = pc.ctx;
|
pctx = pc.ctx,
|
||||||
|
apos, adur;
|
||||||
|
|
||||||
pctx.clearRect(0, 0, pc.w, pc.h);
|
pctx.clearRect(0, 0, pc.w, pc.h);
|
||||||
|
|
||||||
if (!mp.au || isNaN(mp.au.duration) || isNaN(mp.au.currentTime))
|
if (!mp.au || mp.loading || isNaN(adur = mp.au.duration) || isNaN(apos = mp.au.currentTime))
|
||||||
return; // not-init || unsupp-codec
|
return; // not-init || unsupp-codec
|
||||||
|
|
||||||
var sm = bc.w * 1.0 / mp.au.duration;
|
var sm = bc.w * 1.0 / adur;
|
||||||
|
|
||||||
pctx.fillStyle = light ? 'rgba(0,64,0,0.15)' : 'rgba(204,255,128,0.15)';
|
pctx.fillStyle = light ? 'rgba(0,64,0,0.15)' : 'rgba(204,255,128,0.15)';
|
||||||
for (var p = 1, mins = mp.au.duration / 10; p <= mins; p++)
|
for (var p = 1, mins = adur / 10; p <= mins; p++)
|
||||||
pctx.fillRect(Math.floor(sm * p * 10), 0, 2, pc.h);
|
pctx.fillRect(Math.floor(sm * p * 10), 0, 2, pc.h);
|
||||||
|
|
||||||
pctx.fillStyle = light ? 'rgba(0,64,0,0.5)' : 'rgba(192,255,96,0.5)';
|
pctx.fillStyle = light ? 'rgba(0,64,0,0.5)' : 'rgba(192,255,96,0.5)';
|
||||||
for (var p = 1, mins = mp.au.duration / 60; p <= mins; p++)
|
for (var p = 1, mins = adur / 60; p <= mins; p++)
|
||||||
pctx.fillRect(Math.floor(sm * p * 60), 0, 2, pc.h);
|
pctx.fillRect(Math.floor(sm * p * 60), 0, 2, pc.h);
|
||||||
|
|
||||||
var w = 8,
|
var w = 8,
|
||||||
x = sm * mp.au.currentTime;
|
x = sm * apos;
|
||||||
|
|
||||||
pctx.fillStyle = '#573'; pctx.fillRect((x - w / 2) - 1, 0, w + 2, pc.h);
|
pctx.fillStyle = '#573'; pctx.fillRect((x - w / 2) - 1, 0, w + 2, pc.h);
|
||||||
pctx.fillStyle = '#dfc'; pctx.fillRect((x - w / 2), 0, 8, pc.h);
|
pctx.fillStyle = '#dfc'; pctx.fillRect((x - w / 2), 0, 8, pc.h);
|
||||||
@@ -724,8 +729,8 @@ var pbar = (function () {
|
|||||||
pctx.font = '1em sans-serif';
|
pctx.font = '1em sans-serif';
|
||||||
|
|
||||||
var m = pctx.measureText.bind(pctx),
|
var m = pctx.measureText.bind(pctx),
|
||||||
t1 = s2ms(mp.au.duration),
|
t1 = s2ms(adur),
|
||||||
t2 = s2ms(mp.au.currentTime),
|
t2 = s2ms(apos),
|
||||||
yt = pc.h / 3 * 2.1,
|
yt = pc.h / 3 * 2.1,
|
||||||
xt1 = pc.w - (m(t1).width + 12),
|
xt1 = pc.w - (m(t1).width + 12),
|
||||||
xt2 = x < pc.w / 2 ? (x + 12) : (Math.min(pc.w - m(t1 + ":88").width, x - 12) - m(t2).width);
|
xt2 = x < pc.w / 2 ? (x + 12) : (Math.min(pc.w - m(t1 + ":88").width, x - 12) - m(t2).width);
|
||||||
@@ -958,7 +963,7 @@ var mpui = (function () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// preload next song
|
// preload next song
|
||||||
if (mpl.preload && preloaded != mp.au.src) {
|
if (mpl.preload && !mp.loading && preloaded != mp.au.src) {
|
||||||
var pos = mp.au.currentTime,
|
var pos = mp.au.currentTime,
|
||||||
len = mp.au.duration;
|
len = mp.au.duration;
|
||||||
|
|
||||||
@@ -1014,6 +1019,21 @@ function need_ogv_for(url) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function start_sinegen() {
|
||||||
|
var af = 'data:audio/wav;base64,UklGRlaxAgBXQVZFZm10IBAAAAABAAEARKwAAIhYAQACABAATElTVBoAAABJTkZPSVNGVA4AAABMYXZmNTguNzYuMTAwAGRhdGEQsQIAAAB',
|
||||||
|
body = 'iArcE8AYCCeEKggzaDeQOmA/0D/QPmQ/kDtsNggzhCgMJ8Qa4BGMCAQCe/Un7EPn+9h/1fvMm8hzxaPAM8AzwZ/Ac8SXyfvMf9f32D/lI+539//9';
|
||||||
|
|
||||||
|
while (af.length < 235304)
|
||||||
|
af += body;
|
||||||
|
|
||||||
|
var au = new Audio(af.slice(0, 235304));
|
||||||
|
au.onplay = au.pause.bind(au);
|
||||||
|
au.volume = 0.5;
|
||||||
|
au.play();
|
||||||
|
return au;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
var audio_eq = (function () {
|
var audio_eq = (function () {
|
||||||
var r = {
|
var r = {
|
||||||
"en": false,
|
"en": false,
|
||||||
@@ -1277,11 +1297,15 @@ function play(tid, is_ev, seek, call_depth) {
|
|||||||
mp.au = mp.au_ogvjs;
|
mp.au = mp.au_ogvjs;
|
||||||
}
|
}
|
||||||
else if (window['OGVPlayer']) {
|
else if (window['OGVPlayer']) {
|
||||||
|
mp.loading = true;
|
||||||
mp.au = mp.au_ogvjs = new OGVPlayer();
|
mp.au = mp.au_ogvjs = new OGVPlayer();
|
||||||
attempt_play = is_ev;
|
attempt_play = is_ev;
|
||||||
mp.au.addEventListener('error', evau_error, true);
|
mp.au.onerror = evau_error;
|
||||||
mp.au.addEventListener('progress', pbar.drawpos);
|
mp.au.onprogress = pbar.drawpos;
|
||||||
mp.au.addEventListener('ended', next_song);
|
mp.au.onended = next_song;
|
||||||
|
mp.au.onloadedmetadata = mp.au.onloadeddata = function () {
|
||||||
|
mp.loading = false;
|
||||||
|
};
|
||||||
widget.open();
|
widget.open();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -1293,6 +1317,10 @@ function play(tid, is_ev, seek, call_depth) {
|
|||||||
import_js('/.cpr/deps/ogv.js', function () {
|
import_js('/.cpr/deps/ogv.js', function () {
|
||||||
toast.hide();
|
toast.hide();
|
||||||
play(tid, false, seek, 1);
|
play(tid, false, seek, 1);
|
||||||
|
|
||||||
|
var m = /.* Version\/([0-9]+)\.[0-9\.]+ Mobile\/[^ ]+ Safari\/[0-9\.]+$/.exec(navigator.userAgent);
|
||||||
|
if (m && parseInt(m[1]) < 14)
|
||||||
|
toast.err(0, 'because this is an apple device,\nsafari 14 or newer is required\n\nyou are using safari version ' + m[1] + ', so playback of ogg/vorbis/opus files will be buggy\n\nnote: every iOS browser is safari');
|
||||||
});
|
});
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@@ -1301,18 +1329,26 @@ function play(tid, is_ev, seek, call_depth) {
|
|||||||
else {
|
else {
|
||||||
if (!mp.au_native) {
|
if (!mp.au_native) {
|
||||||
mp.au = mp.au_native = new Audio();
|
mp.au = mp.au_native = new Audio();
|
||||||
mp.au.addEventListener('error', evau_error, true);
|
mp.au.onerror = evau_error;
|
||||||
mp.au.addEventListener('progress', pbar.drawpos);
|
mp.au.onprogress = pbar.drawpos;
|
||||||
mp.au.addEventListener('ended', next_song);
|
mp.au.onended = next_song;
|
||||||
widget.open();
|
widget.open();
|
||||||
}
|
}
|
||||||
mp.au = mp.au_native;
|
mp.au = mp.au_native;
|
||||||
|
mp.loading = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
audio_eq.apply();
|
audio_eq.apply();
|
||||||
|
|
||||||
|
url += (url.indexOf('?') < 0 ? '?cache' : '&cache');
|
||||||
|
if (mp.au.src == url)
|
||||||
|
mp.au.currentTime = 0;
|
||||||
|
else {
|
||||||
|
mp.loading = mp.au == mp.au_ogvjs;
|
||||||
|
mp.au.src = url;
|
||||||
|
}
|
||||||
|
|
||||||
mp.au.tid = tid;
|
mp.au.tid = tid;
|
||||||
mp.au.src = url + (url.indexOf('?') < 0 ? '?cache' : '&cache');
|
|
||||||
mp.au.volume = mp.expvol(mp.vol);
|
mp.au.volume = mp.expvol(mp.vol);
|
||||||
var oid = 'a' + tid;
|
var oid = 'a' + tid;
|
||||||
setclass(oid, 'play act');
|
setclass(oid, 'play act');
|
||||||
@@ -1353,7 +1389,7 @@ function play(tid, is_ev, seek, call_depth) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
catch (ex) {
|
catch (ex) {
|
||||||
toast.err(0, 'playback failed: ' + ex);
|
toast.err(0, esc('playback failed: ' + ex));
|
||||||
}
|
}
|
||||||
setclass(oid, 'play');
|
setclass(oid, 'play');
|
||||||
setTimeout(next_song, 500);
|
setTimeout(next_song, 500);
|
||||||
@@ -1387,7 +1423,7 @@ function evau_error(e) {
|
|||||||
|
|
||||||
err += '\n\nFile: «' + uricom_dec(eplaya.src.split('/').slice(-1)[0])[0] + '»';
|
err += '\n\nFile: «' + uricom_dec(eplaya.src.split('/').slice(-1)[0])[0] + '»';
|
||||||
|
|
||||||
toast.warn(15, err);
|
toast.warn(15, esc(err + ''));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1428,9 +1464,16 @@ function autoplay_blocked(seek) {
|
|||||||
go.textContent = 'Play "' + fn + '"';
|
go.textContent = 'Play "' + fn + '"';
|
||||||
go.onclick = function (e) {
|
go.onclick = function (e) {
|
||||||
unblocked(e);
|
unblocked(e);
|
||||||
// chrome 91 may permanently taint on a failed play()
|
if (mp.au !== mp.au_ogvjs)
|
||||||
// depending on win10 settings or something? idk
|
// chrome 91 may permanently taint on a failed play()
|
||||||
mp.au_native = mp.au_ogvjs = null;
|
// depending on win10 settings or something? idk
|
||||||
|
mp.au_native = null;
|
||||||
|
else
|
||||||
|
// iOS browsers allow playing ogg/vorbis/opus in the background
|
||||||
|
// if there is an <audio> tag which at some point played audio
|
||||||
|
if (!mp.sinegen)
|
||||||
|
mp.sinegen = start_sinegen();
|
||||||
|
|
||||||
play(tid, true, seek);
|
play(tid, true, seek);
|
||||||
mp.fade_in();
|
mp.fade_in();
|
||||||
};
|
};
|
||||||
@@ -1690,7 +1733,7 @@ var fileman = (function () {
|
|||||||
|
|
||||||
var vsp = vsplit(vp);
|
var vsp = vsplit(vp);
|
||||||
if (base != vsp[0])
|
if (base != vsp[0])
|
||||||
return toast.err(0, 'bug:\n' + base + '\n' + vsp[0]);
|
return toast.err(0, esc('bug:\n' + base + '\n' + vsp[0]));
|
||||||
|
|
||||||
var vars = ft2dict(ebi(sel[a].id).closest('tr'));
|
var vars = ft2dict(ebi(sel[a].id).closest('tr'));
|
||||||
mkeys = vars[1].concat(vars[2]);
|
mkeys = vars[1].concat(vars[2]);
|
||||||
@@ -1906,7 +1949,7 @@ var fileman = (function () {
|
|||||||
re = new RegExp(ptn, cs ? 'i' : '');
|
re = new RegExp(ptn, cs ? 'i' : '');
|
||||||
}
|
}
|
||||||
catch (ex) {
|
catch (ex) {
|
||||||
return toast.err(5, 'invalid regex:\n' + ex);
|
return toast.err(5, esc('invalid regex:\n' + ex));
|
||||||
}
|
}
|
||||||
toast.hide();
|
toast.hide();
|
||||||
|
|
||||||
@@ -1938,7 +1981,7 @@ var fileman = (function () {
|
|||||||
return rn_cancel();
|
return rn_cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
toast.inf(0, 'renaming ' + f.length + ' items\n\n' + f[0].ofn);
|
toast.inf(0, esc('renaming ' + f.length + ' items\n\n' + f[0].ofn));
|
||||||
var dst = base + uricom_enc(f[0].inew.value, false);
|
var dst = base + uricom_enc(f[0].inew.value, false);
|
||||||
|
|
||||||
function rename_cb() {
|
function rename_cb() {
|
||||||
@@ -1985,7 +2028,7 @@ var fileman = (function () {
|
|||||||
treectl.goto(get_evpath());
|
treectl.goto(get_evpath());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
toast.inf(0, 'deleting ' + (vps.length + 1) + ' items\n\n' + vp);
|
toast.inf(0, esc('deleting ' + (vps.length + 1) + ' items\n\n' + vp));
|
||||||
|
|
||||||
xhr.open('GET', vp + '?delete', true);
|
xhr.open('GET', vp + '?delete', true);
|
||||||
xhr.onreadystatechange = delete_cb;
|
xhr.onreadystatechange = delete_cb;
|
||||||
@@ -2003,8 +2046,8 @@ var fileman = (function () {
|
|||||||
deleter();
|
deleter();
|
||||||
}
|
}
|
||||||
|
|
||||||
modal.confirm('===== DANGER =====\nDELETE these ' + vps.length + ' items?\n\n' + uricom_adec(vps).join('\n'), function () {
|
modal.confirm('<h6 style="color:#900">DANGER</h6>\n<b>DELETE these ' + vps.length + ' items?</b><ul>' + uricom_adec(vps, true).join('') + '</ul>', function () {
|
||||||
modal.confirm('Last chance! Delete?', deleter, null);
|
modal.confirm('<b>Last chance!</b> Delete?', deleter, null);
|
||||||
}, null);
|
}, null);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -2068,7 +2111,7 @@ var fileman = (function () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (exists.length)
|
if (exists.length)
|
||||||
toast.warn(30, 'these ' + exists.length + ' items cannot be pasted here (names already exist):\n\n' + uricom_adec(exists).join('\n'));
|
toast.warn(30, 'these ' + exists.length + ' items cannot be pasted here (names already exist):<ul>' + uricom_adec(exists, true).join('') + '</ul>');
|
||||||
|
|
||||||
if (!req.length)
|
if (!req.length)
|
||||||
return;
|
return;
|
||||||
@@ -2083,7 +2126,7 @@ var fileman = (function () {
|
|||||||
r.tx(srcdir);
|
r.tx(srcdir);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
toast.inf(0, 'pasting ' + (req.length + 1) + ' items\n\n' + uricom_dec(vp)[0]);
|
toast.inf(0, esc('pasting ' + (req.length + 1) + ' items\n\n' + uricom_dec(vp)[0]));
|
||||||
|
|
||||||
var dst = get_evpath() + vp.split('/').slice(-1)[0];
|
var dst = get_evpath() + vp.split('/').slice(-1)[0];
|
||||||
|
|
||||||
@@ -2103,7 +2146,7 @@ var fileman = (function () {
|
|||||||
paster();
|
paster();
|
||||||
}
|
}
|
||||||
|
|
||||||
modal.confirm('paste these ' + req.length + ' items here?\n\n' + uricom_adec(req).join('\n'), function () {
|
modal.confirm('paste these ' + req.length + ' items here?<ul>' + uricom_adec(req, true).join('') + '</ul>', function () {
|
||||||
paster();
|
paster();
|
||||||
jwrite('fman_clip', []);
|
jwrite('fman_clip', []);
|
||||||
}, null);
|
}, null);
|
||||||
@@ -2146,14 +2189,16 @@ var thegrid = (function () {
|
|||||||
gfiles.style.display = 'none';
|
gfiles.style.display = 'none';
|
||||||
gfiles.innerHTML = (
|
gfiles.innerHTML = (
|
||||||
'<div id="ghead">' +
|
'<div id="ghead">' +
|
||||||
'<a href="#" class="tgl btn" id="gridsel" tt="enable file selection; ctrl-click a file to override$NHotkey: S">multiselect</a> zoom ' +
|
'<a href="#" class="tgl btn" id="gridsel" tt="enable file selection; ctrl-click a file to override$NHotkey: S">multiselect</a> <span>zoom: ' +
|
||||||
'<a href="#" class="btn" z="-1.2" tt="Hotkey: shift-A">–</a> ' +
|
'<a href="#" class="btn" z="-1.2" tt="Hotkey: shift-A">–</a> ' +
|
||||||
'<a href="#" class="btn" z="1.2" tt="Hotkey: shift-D">+</a> sort by: ' +
|
'<a href="#" class="btn" z="1.2" tt="Hotkey: shift-D">+</a></span> <span>chop: ' +
|
||||||
|
'<a href="#" class="btn" l="-1" tt="truncate filenames more (show less)">–</a> ' +
|
||||||
|
'<a href="#" class="btn" l="1" tt="truncate filenames less (show more)">+</a></span> <span>sort by: ' +
|
||||||
'<a href="#" s="href">name</a>, ' +
|
'<a href="#" s="href">name</a>, ' +
|
||||||
'<a href="#" s="sz">size</a>, ' +
|
'<a href="#" s="sz">size</a>, ' +
|
||||||
'<a href="#" s="ts">date</a>, ' +
|
'<a href="#" s="ts">date</a>, ' +
|
||||||
'<a href="#" s="ext">type</a>' +
|
'<a href="#" s="ext">type</a>' +
|
||||||
'</div>' +
|
'</span></div>' +
|
||||||
'<div id="ggrid"></div>'
|
'<div id="ggrid"></div>'
|
||||||
);
|
);
|
||||||
lfiles.parentNode.insertBefore(gfiles, lfiles);
|
lfiles.parentNode.insertBefore(gfiles, lfiles);
|
||||||
@@ -2162,7 +2207,8 @@ var thegrid = (function () {
|
|||||||
'thumbs': bcfg_get('thumbs', true),
|
'thumbs': bcfg_get('thumbs', true),
|
||||||
'en': bcfg_get('griden', false),
|
'en': bcfg_get('griden', false),
|
||||||
'sel': bcfg_get('gridsel', false),
|
'sel': bcfg_get('gridsel', false),
|
||||||
'sz': fcfg_get('gridsz', 10),
|
'sz': clamp(fcfg_get('gridsz', 10), 4, 40),
|
||||||
|
'ln': clamp(icfg_get('gridln', 3), 1, 7),
|
||||||
'isdirty': true,
|
'isdirty': true,
|
||||||
'bbox': null
|
'bbox': null
|
||||||
};
|
};
|
||||||
@@ -2182,8 +2228,7 @@ var thegrid = (function () {
|
|||||||
loadgrid();
|
loadgrid();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
lfiles.style.display = '';
|
ungrid();
|
||||||
gfiles.style.display = 'none';
|
|
||||||
}
|
}
|
||||||
pbar.onresize();
|
pbar.onresize();
|
||||||
vbar.onresize();
|
vbar.onresize();
|
||||||
@@ -2192,11 +2237,15 @@ var thegrid = (function () {
|
|||||||
var btnclick = function (e) {
|
var btnclick = function (e) {
|
||||||
ev(e);
|
ev(e);
|
||||||
var s = this.getAttribute('s'),
|
var s = this.getAttribute('s'),
|
||||||
z = this.getAttribute('z');
|
z = this.getAttribute('z'),
|
||||||
|
l = this.getAttribute('l');
|
||||||
|
|
||||||
if (z)
|
if (z)
|
||||||
return setsz(z > 0 ? r.sz * z : r.sz / (-z));
|
return setsz(z > 0 ? r.sz * z : r.sz / (-z));
|
||||||
|
|
||||||
|
if (l)
|
||||||
|
return setln(parseInt(l));
|
||||||
|
|
||||||
var t = lfiles.tHead.rows[0].cells;
|
var t = lfiles.tHead.rows[0].cells;
|
||||||
for (var a = 0; a < t.length; a++)
|
for (var a = 0; a < t.length; a++)
|
||||||
if (t[a].getAttribute('name') == s) {
|
if (t[a].getAttribute('name') == s) {
|
||||||
@@ -2207,7 +2256,7 @@ var thegrid = (function () {
|
|||||||
r.setdirty();
|
r.setdirty();
|
||||||
};
|
};
|
||||||
|
|
||||||
var links = QSA('#ghead>a');
|
var links = QSA('#ghead a');
|
||||||
for (var a = 0; a < links.length; a++)
|
for (var a = 0; a < links.length; a++)
|
||||||
links[a].onclick = btnclick;
|
links[a].onclick = btnclick;
|
||||||
|
|
||||||
@@ -2220,19 +2269,35 @@ var thegrid = (function () {
|
|||||||
|
|
||||||
r.setvis = function (vis) {
|
r.setvis = function (vis) {
|
||||||
(r.en ? gfiles : lfiles).style.display = vis ? '' : 'none';
|
(r.en ? gfiles : lfiles).style.display = vis ? '' : 'none';
|
||||||
}
|
};
|
||||||
|
|
||||||
r.setdirty = function () {
|
r.setdirty = function () {
|
||||||
r.dirty = true;
|
r.dirty = true;
|
||||||
if (r.en) {
|
if (r.en) {
|
||||||
loadgrid();
|
loadgrid();
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function setln(v) {
|
||||||
|
if (v) {
|
||||||
|
r.ln += v;
|
||||||
|
if (r.ln < 1) r.ln = 1;
|
||||||
|
if (r.ln > 7) r.ln = v < 0 ? 7 : 99;
|
||||||
|
swrite('gridln', r.ln);
|
||||||
|
setTimeout(r.tippen, 20);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
document.documentElement.style.setProperty('--grid-ln', r.ln);
|
||||||
|
}
|
||||||
|
catch (ex) { }
|
||||||
}
|
}
|
||||||
|
setln();
|
||||||
|
|
||||||
function setsz(v) {
|
function setsz(v) {
|
||||||
if (v !== undefined) {
|
if (v !== undefined) {
|
||||||
r.sz = v;
|
r.sz = clamp(v, 4, 40);
|
||||||
swrite('gridsz', r.sz);
|
swrite('gridsz', r.sz);
|
||||||
|
setTimeout(r.tippen, 20);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
document.documentElement.style.setProperty('--grid-sz', r.sz + 'em');
|
document.documentElement.style.setProperty('--grid-sz', r.sz + 'em');
|
||||||
@@ -2290,14 +2355,56 @@ var thegrid = (function () {
|
|||||||
var ths = QSA('#ggrid>a');
|
var ths = QSA('#ggrid>a');
|
||||||
|
|
||||||
for (var a = 0, aa = ths.length; a < aa; a++) {
|
for (var a = 0, aa = ths.length; a < aa; a++) {
|
||||||
var tr = ebi(ths[a].getAttribute('ref')).closest('tr');
|
var tr = ebi(ths[a].getAttribute('ref')).closest('tr'),
|
||||||
ths[a].setAttribute('class', tr.getAttribute('class'));
|
cl = tr.getAttribute('class') || '';
|
||||||
|
|
||||||
|
if (ths[a].getAttribute('href').endsWith('/'))
|
||||||
|
cl += ' dir';
|
||||||
|
|
||||||
|
ths[a].setAttribute('class', cl);
|
||||||
}
|
}
|
||||||
var uns = QS('#ggrid a[ref="unsearch"]');
|
var uns = QS('#ggrid a[ref="unsearch"]');
|
||||||
if (uns)
|
if (uns)
|
||||||
uns.onclick = function () {
|
uns.onclick = function () {
|
||||||
ebi('unsearch').click();
|
ebi('unsearch').click();
|
||||||
};
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
r.tippen = function () {
|
||||||
|
var els = QSA('#ggrid>a>span'),
|
||||||
|
aa = els.length;
|
||||||
|
|
||||||
|
if (!aa)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var cs = window.getComputedStyle(els[0]),
|
||||||
|
fs = parseFloat(cs.lineHeight),
|
||||||
|
pad = parseFloat(cs.paddingTop),
|
||||||
|
pels = [],
|
||||||
|
todo = [];
|
||||||
|
|
||||||
|
for (var a = 0; a < aa; a++) {
|
||||||
|
var vis = Math.round((els[a].offsetHeight - pad) / fs),
|
||||||
|
all = Math.round((els[a].scrollHeight - pad) / fs),
|
||||||
|
par = els[a].parentNode;
|
||||||
|
|
||||||
|
pels.push(par);
|
||||||
|
todo.push(vis < all ? par.getAttribute('ttt') : null);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var a = 0; a < todo.length; a++) {
|
||||||
|
if (todo[a])
|
||||||
|
pels[a].setAttribute('tt', todo[a]);
|
||||||
|
else
|
||||||
|
pels[a].removeAttribute('tt');
|
||||||
|
}
|
||||||
|
|
||||||
|
tt.att(ebi('ggrid'));
|
||||||
|
};
|
||||||
|
|
||||||
|
function ungrid() {
|
||||||
|
lfiles.style.display = '';
|
||||||
|
gfiles.style.display = 'none';
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadgrid() {
|
function loadgrid() {
|
||||||
@@ -2315,6 +2422,7 @@ var thegrid = (function () {
|
|||||||
for (var a = 0, aa = files.length; a < aa; a++) {
|
for (var a = 0, aa = files.length; a < aa; a++) {
|
||||||
var ao = files[a],
|
var ao = files[a],
|
||||||
href = esc(ao.getAttribute('href')),
|
href = esc(ao.getAttribute('href')),
|
||||||
|
name = uricom_dec(vsplit(href)[1])[0],
|
||||||
ref = ao.getAttribute('id'),
|
ref = ao.getAttribute('id'),
|
||||||
isdir = href.split('?')[0].slice(-1)[0] == '/',
|
isdir = href.split('?')[0].slice(-1)[0] == '/',
|
||||||
ac = isdir ? ' class="dir"' : '',
|
ac = isdir ? ' class="dir"' : '',
|
||||||
@@ -2347,7 +2455,8 @@ var thegrid = (function () {
|
|||||||
ihref = '/.cpr/ico/' + ihref.slice(0, -1);
|
ihref = '/.cpr/ico/' + ihref.slice(0, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
html.push('<a href="' + href + '" ref="' + ref + '"><img src="' +
|
html.push('<a href="' + href + '" ref="' + ref +
|
||||||
|
'"' + ac + ' ttt="' + esc(name) + '"><img src="' +
|
||||||
ihref + '" /><span' + ac + '>' + ao.innerHTML + '</span></a>');
|
ihref + '" /><span' + ac + '>' + ao.innerHTML + '</span></a>');
|
||||||
}
|
}
|
||||||
ebi('ggrid').innerHTML = html.join('\n');
|
ebi('ggrid').innerHTML = html.join('\n');
|
||||||
@@ -2359,6 +2468,7 @@ var thegrid = (function () {
|
|||||||
r.dirty = false;
|
r.dirty = false;
|
||||||
r.bagit();
|
r.bagit();
|
||||||
r.loadsel();
|
r.loadsel();
|
||||||
|
setTimeout(r.tippen, 20);
|
||||||
}
|
}
|
||||||
|
|
||||||
r.bagit = function () {
|
r.bagit = function () {
|
||||||
@@ -2865,9 +2975,7 @@ var treectl = (function () {
|
|||||||
prev_winh = null,
|
prev_winh = null,
|
||||||
dyn = bcfg_get('dyntree', true),
|
dyn = bcfg_get('dyntree', true),
|
||||||
dots = bcfg_get('dotfiles', false),
|
dots = bcfg_get('dotfiles', false),
|
||||||
treesz = icfg_get('treesz', 16);
|
treesz = clamp(icfg_get('treesz', 16), 4, 50);
|
||||||
|
|
||||||
treesz = Math.min(Math.max(treesz, 4), 50);
|
|
||||||
|
|
||||||
treectl.entree = function (e) {
|
treectl.entree = function (e) {
|
||||||
ev(e);
|
ev(e);
|
||||||
|
|||||||
@@ -185,7 +185,7 @@ function md_plug_err(ex, js) {
|
|||||||
errbox.style.cssText = 'position:absolute;top:0;left:0;padding:1em .5em;background:#2b2b2b;color:#fc5'
|
errbox.style.cssText = 'position:absolute;top:0;left:0;padding:1em .5em;background:#2b2b2b;color:#fc5'
|
||||||
errbox.textContent = msg;
|
errbox.textContent = msg;
|
||||||
errbox.onclick = function () {
|
errbox.onclick = function () {
|
||||||
modal.alert('<pre>' + ex.stack + '</pre>');
|
modal.alert('<pre>' + esc(ex.stack) + '</pre>');
|
||||||
};
|
};
|
||||||
if (o) {
|
if (o) {
|
||||||
errbox.appendChild(o);
|
errbox.appendChild(o);
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ html {
|
|||||||
background: #333;
|
background: #333;
|
||||||
font-family: sans-serif;
|
font-family: sans-serif;
|
||||||
text-shadow: 1px 1px 0px #000;
|
text-shadow: 1px 1px 0px #000;
|
||||||
|
touch-action: manipulation;
|
||||||
}
|
}
|
||||||
html, body {
|
html, body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
@@ -25,4 +26,4 @@ pre {
|
|||||||
}
|
}
|
||||||
a {
|
a {
|
||||||
color: #fc5;
|
color: #fc5;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,9 @@ html, body, #wrap {
|
|||||||
background: #f7f7f7;
|
background: #f7f7f7;
|
||||||
font-family: sans-serif;
|
font-family: sans-serif;
|
||||||
}
|
}
|
||||||
|
html {
|
||||||
|
touch-action: manipulation;
|
||||||
|
}
|
||||||
#wrap {
|
#wrap {
|
||||||
max-width: 40em;
|
max-width: 40em;
|
||||||
margin: 2em auto;
|
margin: 2em auto;
|
||||||
@@ -73,4 +76,4 @@ html.dark input {
|
|||||||
}
|
}
|
||||||
html.dark .num {
|
html.dark .num {
|
||||||
border-color: #777;
|
border-color: #777;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,11 @@
|
|||||||
|
html {
|
||||||
|
touch-action: manipulation;
|
||||||
|
}
|
||||||
#tt, #toast {
|
#tt, #toast {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
max-width: 34em;
|
max-width: 34em;
|
||||||
|
max-width: min(34em, 90%);
|
||||||
|
max-width: min(34em, calc(100% - 7em));
|
||||||
background: #222;
|
background: #222;
|
||||||
border: 0 solid #777;
|
border: 0 solid #777;
|
||||||
box-shadow: 0 .2em .5em #222;
|
box-shadow: 0 .2em .5em #222;
|
||||||
@@ -8,8 +13,9 @@
|
|||||||
z-index: 9001;
|
z-index: 9001;
|
||||||
}
|
}
|
||||||
#tt {
|
#tt {
|
||||||
|
max-width: min(34em, calc(100% - 3.3em));
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
margin-top: 1em;
|
margin: .7em 0;
|
||||||
padding: 0 1.3em;
|
padding: 0 1.3em;
|
||||||
height: 0;
|
height: 0;
|
||||||
opacity: .1;
|
opacity: .1;
|
||||||
@@ -73,7 +79,7 @@
|
|||||||
background: #8e4;
|
background: #8e4;
|
||||||
}
|
}
|
||||||
#toast.warn {
|
#toast.warn {
|
||||||
background: #970;
|
background: #960;
|
||||||
border-color: #fc0;
|
border-color: #fc0;
|
||||||
}
|
}
|
||||||
#toast.warn #toastc {
|
#toast.warn #toastc {
|
||||||
@@ -165,6 +171,16 @@ html.light #tt em {
|
|||||||
min-width: 30em;
|
min-width: 30em;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#modalc li {
|
||||||
|
margin: 1em 0;
|
||||||
|
}
|
||||||
|
#modalc h6 {
|
||||||
|
font-size: 1.3em;
|
||||||
|
border-bottom: 1px solid #999;
|
||||||
|
margin: 0;
|
||||||
|
padding: .3em;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
#modalb {
|
#modalb {
|
||||||
position: sticky;
|
position: sticky;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
@@ -200,4 +216,4 @@ html.light #tt em {
|
|||||||
}
|
}
|
||||||
#modali:focus {
|
#modali:focus {
|
||||||
border-color: #06d;
|
border-color: #06d;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -141,6 +141,15 @@ function U2pvis(act, btns) {
|
|||||||
r.tail = -1;
|
r.tail = -1;
|
||||||
r.wsz = 3;
|
r.wsz = 3;
|
||||||
|
|
||||||
|
var markup = {
|
||||||
|
'404': '<span class="err">404</span>',
|
||||||
|
'ERROR': '<span class="err">ERROR</span>',
|
||||||
|
'OS-error': '<span class="err">OS-error</span>',
|
||||||
|
'found': '<span class="inf">found</span>',
|
||||||
|
'YOLO': '<span class="inf">YOLO</span>',
|
||||||
|
'done': '<span class="ok">done</span>',
|
||||||
|
};
|
||||||
|
|
||||||
r.addfile = function (entry, sz, draw) {
|
r.addfile = function (entry, sz, draw) {
|
||||||
r.tab.push({
|
r.tab.push({
|
||||||
"hn": entry[0],
|
"hn": entry[0],
|
||||||
@@ -185,7 +194,7 @@ function U2pvis(act, btns) {
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
var obj = ebi('f{0}{1}'.format(nfile, field.slice(1)));
|
var obj = ebi('f{0}{1}'.format(nfile, field.slice(1)));
|
||||||
obj.innerHTML = html;
|
obj.innerHTML = field == 'ht' ? (markup[html] || html) : html;
|
||||||
if (field == 'hp') {
|
if (field == 'hp') {
|
||||||
obj.style.color = '';
|
obj.style.color = '';
|
||||||
obj.style.background = '';
|
obj.style.background = '';
|
||||||
@@ -227,7 +236,7 @@ function U2pvis(act, btns) {
|
|||||||
p = r.perc(nb, 0, fobj.size, fobj.t_hashing);
|
p = r.perc(nb, 0, fobj.size, fobj.t_hashing);
|
||||||
|
|
||||||
fo.hp = '{0}%, {1}, {2} MB/s'.format(
|
fo.hp = '{0}%, {1}, {2} MB/s'.format(
|
||||||
p[0].toFixed(2), p[1], p[2].toFixed(2)
|
f2f(p[0], 2), p[1], f2f(p[2], 2)
|
||||||
);
|
);
|
||||||
if (!r.is_act(fo.in))
|
if (!r.is_act(fo.in))
|
||||||
return;
|
return;
|
||||||
@@ -249,7 +258,7 @@ function U2pvis(act, btns) {
|
|||||||
|
|
||||||
var p = r.perc(fo.bd, fo.bd0, fo.bt, fobj.t_uploading);
|
var p = r.perc(fo.bd, fo.bd0, fo.bt, fobj.t_uploading);
|
||||||
fo.hp = '{0}%, {1}, {2} MB/s'.format(
|
fo.hp = '{0}%, {1}, {2} MB/s'.format(
|
||||||
p[0].toFixed(2), p[1], p[2].toFixed(2)
|
f2f(p[0], 2), p[1], f2f(p[2], 2)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!r.is_act(fo.in))
|
if (!r.is_act(fo.in))
|
||||||
@@ -424,7 +433,7 @@ function U2pvis(act, btns) {
|
|||||||
td1 = '<td id="f' + nfile,
|
td1 = '<td id="f' + nfile,
|
||||||
td = '</td>' + td1,
|
td = '</td>' + td1,
|
||||||
ret = td1 + 'n">' + row.hn +
|
ret = td1 + 'n">' + row.hn +
|
||||||
td + 't">' + row.ht +
|
td + 't">' + (markup[row.ht] || row.ht) +
|
||||||
td + 'p" class="prog">' + row.hp + '</td>';
|
td + 'p" class="prog">' + row.hp + '</td>';
|
||||||
|
|
||||||
if (as_html)
|
if (as_html)
|
||||||
@@ -587,8 +596,15 @@ function up2k_init(subtle) {
|
|||||||
"upload": []
|
"upload": []
|
||||||
},
|
},
|
||||||
"bytes": {
|
"bytes": {
|
||||||
|
"total": 0,
|
||||||
"hashed": 0,
|
"hashed": 0,
|
||||||
"uploaded": 0
|
"uploaded": 0,
|
||||||
|
"finished": 0
|
||||||
|
},
|
||||||
|
"time": {
|
||||||
|
"hashing": 0,
|
||||||
|
"uploading": 0,
|
||||||
|
"busy": 0
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -709,11 +725,11 @@ function up2k_init(subtle) {
|
|||||||
match = false;
|
match = false;
|
||||||
|
|
||||||
if (match) {
|
if (match) {
|
||||||
var msg = ['directory iterator got stuck on the following {0} items; good chance your browser is about to spinlock:'.format(missing.length)];
|
var msg = ['directory iterator got stuck on the following {0} items; good chance your browser is about to spinlock:<ul>'.format(missing.length)];
|
||||||
for (var a = 0; a < Math.min(20, missing.length); a++)
|
for (var a = 0; a < Math.min(20, missing.length); a++)
|
||||||
msg.push(missing[a]);
|
msg.push('<li>' + esc(missing[a]) + '</li>');
|
||||||
|
|
||||||
return modal.alert(msg.join('\n-- '), function () {
|
return modal.alert(msg.join('') + '</ul>', function () {
|
||||||
read_dirs(rd, [], [], good, bad, spins);
|
read_dirs(rd, [], [], good, bad, spins);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -784,12 +800,12 @@ function up2k_init(subtle) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
var msg = ['upload these ' + good_files.length + ' files?'];
|
var msg = ['{0} these {1} files?<ul>'.format(fsearch ? 'search' : 'upload', good_files.length)];
|
||||||
for (var a = 0, aa = Math.min(20, good_files.length); a < aa; a++)
|
for (var a = 0, aa = Math.min(20, good_files.length); a < aa; a++)
|
||||||
msg.push(good_files[a][1]);
|
msg.push('<li>' + esc(good_files[a][1]) + '</li>');
|
||||||
|
|
||||||
if (ask_up && !fsearch)
|
if (ask_up && !fsearch)
|
||||||
return modal.confirm(msg.join('\n'), function () { up_them(good_files); }, null);
|
return modal.confirm(msg.join('') + '</ul>', function () { up_them(good_files); }, null);
|
||||||
|
|
||||||
up_them(good_files);
|
up_them(good_files);
|
||||||
}
|
}
|
||||||
@@ -805,7 +821,7 @@ function up2k_init(subtle) {
|
|||||||
for (var a = 0; a < good_files.length; a++) {
|
for (var a = 0; a < good_files.length; a++) {
|
||||||
var fobj = good_files[a][0],
|
var fobj = good_files[a][0],
|
||||||
name = good_files[a][1],
|
name = good_files[a][1],
|
||||||
fdir = get_evpath(),
|
fdir = evpath,
|
||||||
now = Date.now(),
|
now = Date.now(),
|
||||||
lmod = fobj.lastModified || now,
|
lmod = fobj.lastModified || now,
|
||||||
ofs = name.lastIndexOf('/') + 1;
|
ofs = name.lastIndexOf('/') + 1;
|
||||||
@@ -828,6 +844,9 @@ function up2k_init(subtle) {
|
|||||||
},
|
},
|
||||||
key = entry.name + '\n' + entry.size;
|
key = entry.name + '\n' + entry.size;
|
||||||
|
|
||||||
|
if (fsearch)
|
||||||
|
entry.srch = 1;
|
||||||
|
|
||||||
if (seen[key])
|
if (seen[key])
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@@ -840,6 +859,7 @@ function up2k_init(subtle) {
|
|||||||
''
|
''
|
||||||
], fobj.size, draw_each);
|
], fobj.size, draw_each);
|
||||||
|
|
||||||
|
st.bytes.total += fobj.size;
|
||||||
st.files.push(entry);
|
st.files.push(entry);
|
||||||
if (turbo)
|
if (turbo)
|
||||||
push_t(st.todo.head, entry);
|
push_t(st.todo.head, entry);
|
||||||
@@ -878,6 +898,75 @@ function up2k_init(subtle) {
|
|||||||
}
|
}
|
||||||
ebi('u2cleanup').onclick = u2cleanup;
|
ebi('u2cleanup').onclick = u2cleanup;
|
||||||
|
|
||||||
|
var etaref = 0, etaskip = 0;
|
||||||
|
function etafun() {
|
||||||
|
var nhash = st.busy.head.length + st.busy.hash.length + st.todo.head.length + st.todo.hash.length,
|
||||||
|
nsend = st.busy.upload.length + st.todo.upload.length,
|
||||||
|
now = Date.now(),
|
||||||
|
td = (now - (etaref || now)) / 1000.0;
|
||||||
|
|
||||||
|
etaref = now;
|
||||||
|
//ebi('acc_info').innerHTML = f2f(st.time.busy, 1) + ' ' + f2f(now / 1000, 1);
|
||||||
|
|
||||||
|
if (!nhash)
|
||||||
|
ebi('u2etah').innerHTML = 'Done ({0}, {1} files)'.format(humansize(st.bytes.hashed), pvis.ctr["ok"] + pvis.ctr["ng"]);
|
||||||
|
|
||||||
|
if (!nsend && !nhash)
|
||||||
|
ebi('u2etau').innerHTML = ebi('u2etat').innerHTML = (
|
||||||
|
'Done ({0}, {1} files)'.format(humansize(st.bytes.uploaded), pvis.ctr["ok"] + pvis.ctr["ng"]));
|
||||||
|
|
||||||
|
if (!st.busy.hash.length && !hashing_permitted())
|
||||||
|
nhash = 0;
|
||||||
|
|
||||||
|
if (!parallel_uploads || !(nhash + nsend) || (flag && flag.owner && !flag.ours))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var t = [];
|
||||||
|
if (nhash) {
|
||||||
|
st.time.hashing += td;
|
||||||
|
t.push(['u2etah', st.bytes.hashed, st.bytes.hashed, st.time.hashing]);
|
||||||
|
if (fsearch)
|
||||||
|
t.push(['u2etat', st.bytes.hashed, st.bytes.hashed, st.time.hashing]);
|
||||||
|
}
|
||||||
|
if (nsend) {
|
||||||
|
st.time.uploading += td;
|
||||||
|
t.push(['u2etau', st.bytes.uploaded, st.bytes.finished, st.time.uploading]);
|
||||||
|
}
|
||||||
|
if ((nhash || nsend) && !fsearch) {
|
||||||
|
if (!st.bytes.finished) {
|
||||||
|
ebi('u2etat').innerHTML = '(preparing to upload)';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
st.time.busy += td;
|
||||||
|
t.push(['u2etat', st.bytes.finished, st.bytes.finished, st.time.busy]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (var a = 0; a < t.length; a++) {
|
||||||
|
var rem = st.bytes.total - t[a][2],
|
||||||
|
bps = t[a][1] / t[a][3],
|
||||||
|
eta = Math.floor(rem / bps);
|
||||||
|
|
||||||
|
if (t[a][1] < 1024 || t[a][3] < 0.1) {
|
||||||
|
ebi(t[a][0]).innerHTML = '(preparing to upload)';
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (etaskip)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (eta < 60 * 60 * 24)
|
||||||
|
try {
|
||||||
|
eta = /.*(..:..:..).*/.exec(new Date(eta * 1000).toUTCString())[1];
|
||||||
|
}
|
||||||
|
catch (ex) { }
|
||||||
|
|
||||||
|
ebi(t[a][0]).innerHTML = '{0}, {1}/s, {2}'.format(
|
||||||
|
humansize(rem), humansize(bps, 1), eta);
|
||||||
|
}
|
||||||
|
if (++etaskip > 2)
|
||||||
|
etaskip = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/////
|
/////
|
||||||
////
|
////
|
||||||
/// actuator
|
/// actuator
|
||||||
@@ -916,8 +1005,11 @@ function up2k_init(subtle) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function hashing_permitted() {
|
function hashing_permitted() {
|
||||||
|
if (!parallel_uploads)
|
||||||
|
return false;
|
||||||
|
|
||||||
if (multitask) {
|
if (multitask) {
|
||||||
var ahead = st.bytes.hashed - st.bytes.uploaded;
|
var ahead = st.bytes.hashed - st.bytes.finished;
|
||||||
return ahead < 1024 * 1024 * 1024 * 4 &&
|
return ahead < 1024 * 1024 * 1024 * 4 &&
|
||||||
st.todo.handshake.length + st.busy.handshake.length < 16;
|
st.todo.handshake.length + st.busy.handshake.length < 16;
|
||||||
}
|
}
|
||||||
@@ -961,11 +1053,40 @@ function up2k_init(subtle) {
|
|||||||
|
|
||||||
window[(is_busy ? "add" : "remove") +
|
window[(is_busy ? "add" : "remove") +
|
||||||
"EventListener"]("beforeunload", warn_uploader_busy);
|
"EventListener"]("beforeunload", warn_uploader_busy);
|
||||||
|
|
||||||
|
if (!is_busy) {
|
||||||
|
var k = fsearch ? 'searches' : 'uploads',
|
||||||
|
ks = fsearch ? 'Search' : 'Upload',
|
||||||
|
tok = fsearch ? 'successful (found on server)' : 'completed successfully',
|
||||||
|
tng = fsearch ? 'failed (NOT found on server)' : 'failed, sorry',
|
||||||
|
ok = pvis.ctr["ok"],
|
||||||
|
ng = pvis.ctr["ng"],
|
||||||
|
t = ask_up ? 0 : 10;
|
||||||
|
|
||||||
|
if (ok && ng)
|
||||||
|
toast.warn(t, 'Finished, but some {0} failed:\n{1} {2},\n{3} {4}'.format(k, ok, tok, ng, tng));
|
||||||
|
else if (ok > 1)
|
||||||
|
toast.ok(t, 'All {1} {0} {2}'.format(k, ok, tok));
|
||||||
|
else if (ok)
|
||||||
|
toast.ok(t, '{0} {1}'.format(ks, tok));
|
||||||
|
else if (ng > 1)
|
||||||
|
toast.err(t, 'All {1} {0} {2}'.format(k, ng, tng));
|
||||||
|
else if (ng)
|
||||||
|
toast.err(t, '{0} {1}'.format(ks, tng));
|
||||||
|
|
||||||
|
timer.rm(etafun);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
timer.add(etafun, false);
|
||||||
|
ebi('u2etas').style.textAlign = 'left';
|
||||||
|
}
|
||||||
|
etafun();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flag) {
|
if (flag) {
|
||||||
if (is_busy) {
|
if (is_busy) {
|
||||||
flag.take(now);
|
flag.take(now);
|
||||||
|
ebi('u2flagblock').style.display = flag.ours ? '' : 'block';
|
||||||
if (!flag.ours)
|
if (!flag.ours)
|
||||||
return defer();
|
return defer();
|
||||||
}
|
}
|
||||||
@@ -1101,7 +1222,6 @@ function up2k_init(subtle) {
|
|||||||
function exec_hash() {
|
function exec_hash() {
|
||||||
var t = st.todo.hash.shift();
|
var t = st.todo.hash.shift();
|
||||||
st.busy.hash.push(t);
|
st.busy.hash.push(t);
|
||||||
st.bytes.hashed += t.size;
|
|
||||||
t.bytes_uploaded = 0;
|
t.bytes_uploaded = 0;
|
||||||
|
|
||||||
var bpend = 0,
|
var bpend = 0,
|
||||||
@@ -1127,6 +1247,7 @@ function up2k_init(subtle) {
|
|||||||
cdr = t.size;
|
cdr = t.size;
|
||||||
|
|
||||||
bpend += cdr - car;
|
bpend += cdr - car;
|
||||||
|
st.bytes.hashed += cdr - car;
|
||||||
|
|
||||||
function orz(e) {
|
function orz(e) {
|
||||||
if (!min_filebuf && nch == 1) {
|
if (!min_filebuf && nch == 1) {
|
||||||
@@ -1157,11 +1278,11 @@ function up2k_init(subtle) {
|
|||||||
if (handled) {
|
if (handled) {
|
||||||
pvis.move(t.n, 'ng');
|
pvis.move(t.n, 'ng');
|
||||||
apop(st.busy.hash, t);
|
apop(st.busy.hash, t);
|
||||||
st.bytes.uploaded += t.size;
|
st.bytes.finished += t.size;
|
||||||
return tasker();
|
return tasker();
|
||||||
}
|
}
|
||||||
|
|
||||||
toast.err(0, 'y o u b r o k e i t\nfile: ' + t.name + '\nerror: ' + err);
|
toast.err(0, 'y o u b r o k e i t\nfile: ' + esc(t.name + '') + '\nerror: ' + err);
|
||||||
};
|
};
|
||||||
reader.readAsArrayBuffer(
|
reader.readAsArrayBuffer(
|
||||||
bobslice.call(t.fobj, car, cdr));
|
bobslice.call(t.fobj, car, cdr));
|
||||||
@@ -1249,21 +1370,22 @@ function up2k_init(subtle) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
apop(st.busy.head, t);
|
apop(st.busy.head, t);
|
||||||
if (!ok)
|
if (!ok && !t.srch)
|
||||||
return push_t(st.todo.hash, t);
|
return push_t(st.todo.hash, t);
|
||||||
|
|
||||||
t.done = true;
|
t.done = true;
|
||||||
st.bytes.hashed += t.size;
|
st.bytes.hashed += t.size;
|
||||||
st.bytes.uploaded += t.size;
|
st.bytes.finished += t.size;
|
||||||
pvis.seth(t.n, 1, 'YOLO');
|
pvis.move(t.n, 'bz');
|
||||||
|
pvis.seth(t.n, 1, ok ? 'YOLO' : '404');
|
||||||
pvis.seth(t.n, 2, "turbo'd");
|
pvis.seth(t.n, 2, "turbo'd");
|
||||||
pvis.move(t.n, 'ok');
|
pvis.move(t.n, ok ? 'ok' : 'ng');
|
||||||
};
|
};
|
||||||
xhr.onload = function (e) {
|
xhr.onload = function (e) {
|
||||||
try { orz(e); } catch (ex) { vis_exh(ex + '', '', '', '', ex); }
|
try { orz(e); } catch (ex) { vis_exh(ex + '', '', '', '', ex); }
|
||||||
};
|
};
|
||||||
|
|
||||||
xhr.open('HEAD', t.purl + uricom_enc(t.name), true);
|
xhr.open('HEAD', t.purl + uricom_enc(t.name) + '?raw', true);
|
||||||
xhr.send();
|
xhr.send();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1334,7 +1456,7 @@ function up2k_init(subtle) {
|
|||||||
pvis.seth(t.n, 1, smsg);
|
pvis.seth(t.n, 1, smsg);
|
||||||
pvis.move(t.n, smsg == '404' ? 'ng' : 'ok');
|
pvis.move(t.n, smsg == '404' ? 'ng' : 'ok');
|
||||||
apop(st.busy.handshake, t);
|
apop(st.busy.handshake, t);
|
||||||
st.bytes.uploaded += t.size;
|
st.bytes.finished += t.size;
|
||||||
t.done = true;
|
t.done = true;
|
||||||
tasker();
|
tasker();
|
||||||
return;
|
return;
|
||||||
@@ -1375,7 +1497,7 @@ function up2k_init(subtle) {
|
|||||||
pvis.prog(t, 0, cbd[0]);
|
pvis.prog(t, 0, cbd[0]);
|
||||||
|
|
||||||
var done = true,
|
var done = true,
|
||||||
msg = '🎷🐛';
|
msg = 'done';
|
||||||
|
|
||||||
if (t.postlist.length) {
|
if (t.postlist.length) {
|
||||||
var arr = st.todo.upload,
|
var arr = st.todo.upload,
|
||||||
@@ -1402,12 +1524,12 @@ function up2k_init(subtle) {
|
|||||||
|
|
||||||
if (done) {
|
if (done) {
|
||||||
t.done = true;
|
t.done = true;
|
||||||
st.bytes.uploaded += t.size - t.bytes_uploaded;
|
st.bytes.finished += t.size - t.bytes_uploaded;
|
||||||
var spd1 = (t.size / ((t.t_hashed - t.t_hashing) / 1000.)) / (1024 * 1024.),
|
var spd1 = (t.size / ((t.t_hashed - t.t_hashing) / 1000.)) / (1024 * 1024.),
|
||||||
spd2 = (t.size / ((t.t_uploaded - t.t_uploading) / 1000.)) / (1024 * 1024.);
|
spd2 = (t.size / ((t.t_uploaded - t.t_uploading) / 1000.)) / (1024 * 1024.);
|
||||||
|
|
||||||
pvis.seth(t.n, 2, 'hash {0}, up {1} MB/s'.format(
|
pvis.seth(t.n, 2, 'hash {0}, up {1} MB/s'.format(
|
||||||
spd1.toFixed(2), spd2.toFixed(2)));
|
f2f(spd1, 2), isNaN(spd2) ? '--' : f2f(spd2, 2)));
|
||||||
|
|
||||||
pvis.move(t.n, 'ok');
|
pvis.move(t.n, 'ok');
|
||||||
}
|
}
|
||||||
@@ -1435,7 +1557,7 @@ function up2k_init(subtle) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
st.bytes.uploaded += t.size;
|
st.bytes.finished += t.size;
|
||||||
if (rsp.indexOf('partial upload exists') !== -1 ||
|
if (rsp.indexOf('partial upload exists') !== -1 ||
|
||||||
rsp.indexOf('file already exists') !== -1) {
|
rsp.indexOf('file already exists') !== -1) {
|
||||||
err = rsp;
|
err = rsp;
|
||||||
@@ -1470,7 +1592,7 @@ function up2k_init(subtle) {
|
|||||||
"lmod": t.lmod,
|
"lmod": t.lmod,
|
||||||
"hash": t.hash
|
"hash": t.hash
|
||||||
};
|
};
|
||||||
if (fsearch)
|
if (t.srch)
|
||||||
req.srch = 1;
|
req.srch = 1;
|
||||||
|
|
||||||
xhr.open('POST', t.purl, true);
|
xhr.open('POST', t.purl, true);
|
||||||
@@ -1506,6 +1628,7 @@ function up2k_init(subtle) {
|
|||||||
var txt = ((xhr.response && xhr.response.err) || xhr.responseText) + '';
|
var txt = ((xhr.response && xhr.response.err) || xhr.responseText) + '';
|
||||||
if (xhr.status == 200) {
|
if (xhr.status == 200) {
|
||||||
pvis.prog(t, npart, cdr - car);
|
pvis.prog(t, npart, cdr - car);
|
||||||
|
st.bytes.finished += cdr - car;
|
||||||
st.bytes.uploaded += cdr - car;
|
st.bytes.uploaded += cdr - car;
|
||||||
t.bytes_uploaded += cdr - car;
|
t.bytes_uploaded += cdr - car;
|
||||||
}
|
}
|
||||||
@@ -1573,6 +1696,7 @@ function up2k_init(subtle) {
|
|||||||
parent.appendChild(btn);
|
parent.appendChild(btn);
|
||||||
ebi('u2conf').setAttribute('class', wide ? 'has_btn' : '');
|
ebi('u2conf').setAttribute('class', wide ? 'has_btn' : '');
|
||||||
ebi('u2cards').setAttribute('class', wide ? 'w' : '');
|
ebi('u2cards').setAttribute('class', wide ? 'w' : '');
|
||||||
|
ebi('u2etaw').setAttribute('class', wide ? 'w' : '');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
window.addEventListener('resize', onresize);
|
window.addEventListener('resize', onresize);
|
||||||
@@ -1660,7 +1784,7 @@ function up2k_init(subtle) {
|
|||||||
|
|
||||||
function draw_turbo() {
|
function draw_turbo() {
|
||||||
var msgu = '<p class="warn">WARNING: turbo enabled, <span> client may not detect and resume incomplete uploads; see turbo-button tooltip</span></p>',
|
var msgu = '<p class="warn">WARNING: turbo enabled, <span> client may not detect and resume incomplete uploads; see turbo-button tooltip</span></p>',
|
||||||
msgs = '<p class="warn">WARNING: turbo enabled, <span> search may give false-positives; see turbo-button tooltip</span></p>',
|
msgs = '<p class="warn">WARNING: turbo enabled, <span> search results can be incorrect; see turbo-button tooltip</span></p>',
|
||||||
msg = fsearch ? msgs : msgu,
|
msg = fsearch ? msgs : msgu,
|
||||||
omsg = fsearch ? msgu : msgs,
|
omsg = fsearch ? msgu : msgs,
|
||||||
html = ebi('u2foot').innerHTML,
|
html = ebi('u2foot').innerHTML,
|
||||||
@@ -1733,6 +1857,9 @@ function up2k_init(subtle) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (!flag_en && flag) {
|
else if (!flag_en && flag) {
|
||||||
|
if (flag.ours)
|
||||||
|
flag.give();
|
||||||
|
|
||||||
flag.ch.close();
|
flag.ch.close();
|
||||||
flag = false;
|
flag = false;
|
||||||
}
|
}
|
||||||
@@ -1763,9 +1890,9 @@ function up2k_init(subtle) {
|
|||||||
if (o)
|
if (o)
|
||||||
o.addEventListener('click', tgl_fsearch, false);
|
o.addEventListener('click', tgl_fsearch, false);
|
||||||
|
|
||||||
var nodes = ebi('u2conf').getElementsByTagName('a');
|
ebi('u2etas').onclick = function () {
|
||||||
for (var a = nodes.length - 1; a >= 0; a--)
|
clmod(ebi('u2etas'), 'o', 't');
|
||||||
nodes[a].addEventListener('touchend', nop, false);
|
};
|
||||||
|
|
||||||
set_fsearch();
|
set_fsearch();
|
||||||
bumpthread({ "target": 1 });
|
bumpthread({ "target": 1 });
|
||||||
|
|||||||
@@ -179,17 +179,26 @@ function crc32(str) {
|
|||||||
|
|
||||||
function clmod(el, cls, add) {
|
function clmod(el, cls, add) {
|
||||||
if (el.classList) {
|
if (el.classList) {
|
||||||
|
var have = el.classList.contains(cls);
|
||||||
if (add == 't')
|
if (add == 't')
|
||||||
add = el.classList.contains(cls) ? 0 : 1;
|
add = !have;
|
||||||
|
|
||||||
return el.classList[add ? 'add' : 'remove'](cls);
|
if (add != have)
|
||||||
|
el.classList[add ? 'add' : 'remove'](cls);
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var re = new RegExp('\\s*\\b' + cls + '\\s*\\b', 'g');
|
var re = new RegExp('\\s*\\b' + cls + '\\s*\\b', 'g'),
|
||||||
if (add == 't')
|
n1 = el.className;
|
||||||
add = !re.test(el.className);
|
|
||||||
|
|
||||||
el.className = el.className.replace(re, ' ') + (add ? ' ' + cls : '');
|
if (add == 't')
|
||||||
|
add = !re.test(n1);
|
||||||
|
|
||||||
|
var n2 = n1.replace(re, ' ') + (add ? ' ' + cls : '');
|
||||||
|
|
||||||
|
if (n1 != n2)
|
||||||
|
el.className = n2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -353,10 +362,12 @@ function uricom_dec(txt) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function uricom_adec(arr) {
|
function uricom_adec(arr, li) {
|
||||||
var ret = [];
|
var ret = [];
|
||||||
for (var a = 0; a < arr.length; a++)
|
for (var a = 0; a < arr.length; a++) {
|
||||||
ret.push(uricom_dec(arr[a])[0]);
|
var txt = uricom_dec(arr[a])[0];
|
||||||
|
ret.push(li ? '<li>' + esc(txt) + '</li>' : txt);
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -401,6 +412,28 @@ function s2ms(s) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function f2f(val, nd) {
|
||||||
|
// 10.toFixed(1) returns 10.00 for certain values of 10
|
||||||
|
val = (val * Math.pow(10, nd)).toFixed(0).split('.')[0];
|
||||||
|
return nd ? (val.slice(0, -nd) || '0') + '.' + val.slice(-nd) : val;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function humansize(b, terse) {
|
||||||
|
var i = 0, u = terse ? ['B', 'K', 'M', 'G'] : ['B', 'KB', 'MB', 'GB'];
|
||||||
|
while (b >= 1000 && i < u.length) {
|
||||||
|
b /= 1024;
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
return f2f(b, b >= 100 ? 0 : b >= 10 ? 1 : 2) + ' ' + u[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function clamp(v, a, b) {
|
||||||
|
return Math.min(Math.max(v, a), b);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function has(haystack, needle) {
|
function has(haystack, needle) {
|
||||||
for (var a = 0; a < haystack.length; a++)
|
for (var a = 0; a < haystack.length; a++)
|
||||||
if (haystack[a] == needle)
|
if (haystack[a] == needle)
|
||||||
@@ -559,6 +592,8 @@ var tt = (function () {
|
|||||||
r.skip = false;
|
r.skip = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (QS('body.bbox-open'))
|
||||||
|
return;
|
||||||
|
|
||||||
var cfg = sread('tooltips');
|
var cfg = sread('tooltips');
|
||||||
if (cfg !== null && cfg != '1')
|
if (cfg !== null && cfg != '1')
|
||||||
@@ -571,28 +606,39 @@ var tt = (function () {
|
|||||||
r.el = this;
|
r.el = this;
|
||||||
var pos = this.getBoundingClientRect(),
|
var pos = this.getBoundingClientRect(),
|
||||||
dir = this.getAttribute('ttd') || '',
|
dir = this.getAttribute('ttd') || '',
|
||||||
left = pos.left < window.innerWidth / 2,
|
|
||||||
top = pos.top < window.innerHeight / 2,
|
top = pos.top < window.innerHeight / 2,
|
||||||
big = this.className.indexOf(' ttb') !== -1;
|
big = this.className.indexOf(' ttb') !== -1;
|
||||||
|
|
||||||
if (dir.indexOf('u') + 1) top = false;
|
if (dir.indexOf('u') + 1) top = false;
|
||||||
if (dir.indexOf('d') + 1) top = true;
|
if (dir.indexOf('d') + 1) top = true;
|
||||||
if (dir.indexOf('l') + 1) left = false;
|
|
||||||
if (dir.indexOf('r') + 1) left = true;
|
|
||||||
|
|
||||||
clmod(r.tt, 'b', big);
|
clmod(r.tt, 'b', big);
|
||||||
r.tt.style.top = top ? pos.bottom + 'px' : 'auto';
|
r.tt.style.left = '0';
|
||||||
r.tt.style.bottom = top ? 'auto' : (window.innerHeight - pos.top) + 'px';
|
r.tt.style.top = '0';
|
||||||
r.tt.style.left = left ? pos.left + 'px' : 'auto';
|
|
||||||
r.tt.style.right = left ? 'auto' : (window.innerWidth - pos.right) + 'px';
|
|
||||||
|
|
||||||
r.tt.innerHTML = msg.replace(/\$N/g, "<br />");
|
r.tt.innerHTML = msg.replace(/\$N/g, "<br />");
|
||||||
|
var tw = r.tt.offsetWidth,
|
||||||
|
x = pos.left + (pos.right - pos.left) / 2 - tw / 2;
|
||||||
|
|
||||||
|
if (x < 0)
|
||||||
|
x = 8;
|
||||||
|
|
||||||
|
if (x + tw >= window.innerWidth - 8) {
|
||||||
|
x = window.innerWidth - tw - 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
r.tt.style.left = x + 'px';
|
||||||
|
r.tt.style.top = top ? pos.bottom + 'px' : 'auto';
|
||||||
|
r.tt.style.bottom = top ? 'auto' : (window.innerHeight - pos.top) + 'px';
|
||||||
|
|
||||||
r.el.addEventListener('mouseleave', r.hide);
|
r.el.addEventListener('mouseleave', r.hide);
|
||||||
|
window.addEventListener('scroll', r.hide);
|
||||||
clmod(r.tt, 'show', 1);
|
clmod(r.tt, 'show', 1);
|
||||||
};
|
};
|
||||||
|
|
||||||
r.hide = function (e) {
|
r.hide = function (e) {
|
||||||
ev(e);
|
ev(e);
|
||||||
|
window.removeEventListener('scroll', r.hide);
|
||||||
clmod(r.tt, 'show');
|
clmod(r.tt, 'show');
|
||||||
if (r.el)
|
if (r.el)
|
||||||
r.el.removeEventListener('mouseleave', r.hide);
|
r.el.removeEventListener('mouseleave', r.hide);
|
||||||
@@ -600,13 +646,23 @@ var tt = (function () {
|
|||||||
|
|
||||||
if (is_touch && IPHONE) {
|
if (is_touch && IPHONE) {
|
||||||
var f1 = r.show,
|
var f1 = r.show,
|
||||||
f2 = r.hide;
|
f2 = r.hide,
|
||||||
|
q = [];
|
||||||
|
|
||||||
|
// if an onclick-handler creates a new timer,
|
||||||
|
// iOS 13.1.2 delays the entire handler by up to 401ms,
|
||||||
|
// win by using a shared timer instead
|
||||||
|
|
||||||
|
timer.add(function () {
|
||||||
|
while (q.length && Date.now() >= q[0][0])
|
||||||
|
q.shift()[1]();
|
||||||
|
});
|
||||||
|
|
||||||
r.show = function () {
|
r.show = function () {
|
||||||
setTimeout(f1.bind(this), 301);
|
q.push([Date.now() + 100, f1.bind(this)]);
|
||||||
};
|
};
|
||||||
r.hide = function () {
|
r.hide = function () {
|
||||||
setTimeout(f2.bind(this), 301);
|
q.push([Date.now() + 100, f2.bind(this)]);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -662,6 +718,7 @@ var toast = (function () {
|
|||||||
obj.setAttribute('id', 'toast');
|
obj.setAttribute('id', 'toast');
|
||||||
document.body.appendChild(obj);
|
document.body.appendChild(obj);
|
||||||
r.visible = false;
|
r.visible = false;
|
||||||
|
r.txt = null;
|
||||||
|
|
||||||
r.hide = function (e) {
|
r.hide = function (e) {
|
||||||
ev(e);
|
ev(e);
|
||||||
@@ -681,6 +738,7 @@ var toast = (function () {
|
|||||||
obj.className += ' vis';
|
obj.className += ' vis';
|
||||||
ebi('toastc').onclick = r.hide;
|
ebi('toastc').onclick = r.hide;
|
||||||
r.visible = true;
|
r.visible = true;
|
||||||
|
r.txt = txt;
|
||||||
};
|
};
|
||||||
|
|
||||||
r.ok = function (ms, txt) {
|
r.ok = function (ms, txt) {
|
||||||
@@ -725,11 +783,15 @@ var modal = (function () {
|
|||||||
a.onclick = ok;
|
a.onclick = ok;
|
||||||
|
|
||||||
(ebi('modali') || a).focus();
|
(ebi('modali') || a).focus();
|
||||||
|
document.addEventListener('focus', onfocus);
|
||||||
|
timer.add(onfocus);
|
||||||
};
|
};
|
||||||
|
|
||||||
r.hide = function () {
|
r.hide = function () {
|
||||||
o.parentNode.removeChild(o);
|
timer.rm(onfocus);
|
||||||
|
document.removeEventListener('focus', onfocus);
|
||||||
document.removeEventListener('keydown', onkey);
|
document.removeEventListener('keydown', onkey);
|
||||||
|
o.parentNode.removeChild(o);
|
||||||
r.busy = false;
|
r.busy = false;
|
||||||
setTimeout(next, 50);
|
setTimeout(next, 50);
|
||||||
};
|
};
|
||||||
@@ -748,6 +810,17 @@ var modal = (function () {
|
|||||||
cb_ng(null);
|
cb_ng(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onfocus(e) {
|
||||||
|
var ctr = ebi('modalc');
|
||||||
|
if (!ctr || !ctr.contains || !document.activeElement || ctr.contains(document.activeElement))
|
||||||
|
return;
|
||||||
|
|
||||||
|
setTimeout(function () {
|
||||||
|
ebi('modal-ok').focus();
|
||||||
|
}, 20);
|
||||||
|
ev(e);
|
||||||
|
}
|
||||||
|
|
||||||
function onkey(e) {
|
function onkey(e) {
|
||||||
if (e.code == 'Enter') {
|
if (e.code == 'Enter') {
|
||||||
var a = ebi('modal-ng');
|
var a = ebi('modal-ng');
|
||||||
|
|||||||
@@ -1,36 +1,3 @@
|
|||||||
/* put filetype icons inline with text
|
|
||||||
#ggrid>a>span:before,
|
|
||||||
#ggrid>a>span.dir:before {
|
|
||||||
display: inline;
|
|
||||||
line-height: 0;
|
|
||||||
font-size: 1.7em;
|
|
||||||
margin: -.7em .1em -.5em -.6em;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
/* move folder icons top-left */
|
|
||||||
#ggrid>a>span.dir:before {
|
|
||||||
content: initial;
|
|
||||||
}
|
|
||||||
#ggrid>a[href$="/"]:before {
|
|
||||||
content: '📂';
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* put filetype icons top-left */
|
|
||||||
#ggrid>a:before {
|
|
||||||
display: block;
|
|
||||||
position: absolute;
|
|
||||||
padding: .3em 0;
|
|
||||||
margin: -.4em;
|
|
||||||
text-shadow: 0 0 .1em #000;
|
|
||||||
background: linear-gradient(135deg,rgba(255,255,255,0) 50%,rgba(255,255,255,0.2));
|
|
||||||
border-radius: .3em;
|
|
||||||
font-size: 2em;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* video */
|
/* video */
|
||||||
#ggrid>a:is(
|
#ggrid>a:is(
|
||||||
[href$=".mkv"i],
|
[href$=".mkv"i],
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
#u2cleanup, #u2conf tr:first-child>td[rowspan]:not(#u2btn_cw), /* most of the config options */
|
#u2cleanup, #u2conf tr:first-child>td[rowspan]:not(#u2btn_cw), /* most of the config options */
|
||||||
|
|
||||||
#u2cards /* and the upload progress tabs */
|
#u2cards, #u2etaw /* and the upload progress tabs */
|
||||||
|
|
||||||
{display: none !important} /* do it! */
|
{display: none !important} /* do it! */
|
||||||
|
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
/* add some margins because now it's weird */
|
/* add some margins because now it's weird */
|
||||||
.opview {margin-top: 2.5em}
|
.opview {margin-top: 2.5em}
|
||||||
#op_up2k {margin-top: 3em}
|
#op_up2k {margin-top: 6em}
|
||||||
|
|
||||||
/* and embiggen the upload button */
|
/* and embiggen the upload button */
|
||||||
#u2conf #u2btn, #u2btn {padding:1.5em 0}
|
#u2conf #u2btn, #u2btn {padding:1.5em 0}
|
||||||
|
|||||||
@@ -126,6 +126,10 @@ e=6; s=10; d=~/dev/copyparty/srv/aus; n=1; p=0; e=$((e*60)); rm -rf $d; mkdir $d
|
|||||||
-v srv/aus:aus:r:ce2dsa:ce2ts:cmtp=fgsfds=bin/mtag/sleep.py
|
-v srv/aus:aus:r:ce2dsa:ce2ts:cmtp=fgsfds=bin/mtag/sleep.py
|
||||||
sqlite3 .hist/up2k.db 'select * from mt where k="fgsfds" or k="t:mtp"' | tee /dev/stderr | wc -l
|
sqlite3 .hist/up2k.db 'select * from mt where k="fgsfds" or k="t:mtp"' | tee /dev/stderr | wc -l
|
||||||
|
|
||||||
|
# generate the sine meme
|
||||||
|
for ((f=420;f<1200;f++)); do sz=$(ffmpeg -y -f lavfi -i sine=frequency=$f:duration=2 -vf volume=0.1 -ac 1 -ar 44100 -f s16le /dev/shm/a.wav 2>/dev/null; base64 -w0 </dev/shm/a.wav | gzip -c | wc -c); printf '%d %d\n' $f $sz; done | tee /dev/stderr | sort -nrk2,2
|
||||||
|
ffmpeg -y -f lavfi -i sine=frequency=1050:duration=2 -vf volume=0.1 -ac 1 -ar 44100 /dev/shm/a.wav
|
||||||
|
|
||||||
|
|
||||||
##
|
##
|
||||||
## vscode
|
## vscode
|
||||||
@@ -157,7 +161,7 @@ brew install python@2
|
|||||||
pip install virtualenv
|
pip install virtualenv
|
||||||
|
|
||||||
# readme toc
|
# readme toc
|
||||||
cat README.md | awk '!/^#/{next} {lv=length($1);sub(/[^ ]+ /,"");bab=$0;gsub(/ /,"-",bab)} {printf "%" ((lv-1)*4+1) "s [%s](#%s)\n", "*",$0,bab}'
|
cat README.md | awk 'function pr() { if (!h) {return}; if (/^ *[*!#]/||!s) {printf "%s\n",h;h=0;return}; if (/.../) {printf "%s - %s\n",h,$0;h=0}; }; /^#/{s=1;pr()} /^#* *(file indexing|install on android|dev env setup|just the sfx|complete release|optional gpl stuff)|`$/{s=0} /^#/{lv=length($1);sub(/[^ ]+ /,"");bab=$0;gsub(/ /,"-",bab); h=sprintf("%" ((lv-1)*4+1) "s [%s](#%s)", "*",$0,bab);next} !h{next} {sub(/:$/,"")} {pr()}' > toc; grep -E '^## readme toc' -B1000 -A2 <README.md >p1; grep -E '^## quickstart' -B2 -A999999 <README.md >p2; (cat p1; grep quickstart -A1000 <toc; cat p2) >README.md
|
||||||
|
|
||||||
# fix firefox phantom breakpoints,
|
# fix firefox phantom breakpoints,
|
||||||
# suggestions from bugtracker, doesnt work (debugger is not attachable)
|
# suggestions from bugtracker, doesnt work (debugger is not attachable)
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ WORKDIR /z
|
|||||||
ENV ver_asmcrypto=5b994303a9d3e27e0915f72a10b6c2c51535a4dc \
|
ENV ver_asmcrypto=5b994303a9d3e27e0915f72a10b6c2c51535a4dc \
|
||||||
ver_hashwasm=4.7.0 \
|
ver_hashwasm=4.7.0 \
|
||||||
ver_marked=1.1.0 \
|
ver_marked=1.1.0 \
|
||||||
ver_ogvjs=1.8.0 \
|
ver_ogvjs=1.8.4 \
|
||||||
ver_mde=2.14.0 \
|
ver_mde=2.14.0 \
|
||||||
ver_codemirror=5.59.3 \
|
ver_codemirror=5.59.3 \
|
||||||
ver_fontawesome=5.13.0 \
|
ver_fontawesome=5.13.0 \
|
||||||
@@ -74,23 +74,16 @@ RUN cd hash-wasm \
|
|||||||
# build ogvjs
|
# build ogvjs
|
||||||
RUN cd ogvjs-$ver_ogvjs \
|
RUN cd ogvjs-$ver_ogvjs \
|
||||||
&& cp -pv \
|
&& cp -pv \
|
||||||
ogv.js \
|
|
||||||
ogv-worker-audio.js \
|
ogv-worker-audio.js \
|
||||||
ogv-demuxer-ogg-wasm.js \
|
ogv-demuxer-ogg-wasm.js \
|
||||||
ogv-demuxer-ogg-wasm.wasm \
|
ogv-demuxer-ogg-wasm.wasm \
|
||||||
ogv-demuxer-webm-wasm.js \
|
|
||||||
ogv-demuxer-webm-wasm.wasm \
|
|
||||||
ogv-decoder-audio-opus-wasm.js \
|
ogv-decoder-audio-opus-wasm.js \
|
||||||
ogv-decoder-audio-opus-wasm.wasm \
|
ogv-decoder-audio-opus-wasm.wasm \
|
||||||
ogv-decoder-audio-vorbis-wasm.js \
|
ogv-decoder-audio-vorbis-wasm.js \
|
||||||
ogv-decoder-audio-vorbis-wasm.wasm \
|
ogv-decoder-audio-vorbis-wasm.wasm \
|
||||||
/z/dist
|
/z/dist \
|
||||||
|
&& cp -pv \
|
||||||
# ogv-demuxer-ogg.js \
|
ogv-es2017.js /z/dist/ogv.js
|
||||||
# ogv-demuxer-webm.js \
|
|
||||||
# ogv-decoder-audio-opus.js \
|
|
||||||
# ogv-decoder-audio-vorbis.js \
|
|
||||||
# dynamicaudio.swf \
|
|
||||||
|
|
||||||
|
|
||||||
# build marked
|
# build marked
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ all: $(addsuffix .gz, $(wildcard *.*))
|
|||||||
|
|
||||||
%.gz: %
|
%.gz: %
|
||||||
#brotli -q 11 $<
|
#brotli -q 11 $<
|
||||||
pigz -11 -J 34 -I 573 $<
|
pigz -11 -I 573 $<
|
||||||
|
|
||||||
# pigz -11 -J 34 -I 100 -F < $< > $@.first
|
# pigz -11 -J 34 -I 100 -F < $< > $@.first
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user