167 Commits

Author SHA1 Message Date
ba283e9221 Version 4.2.4 2019-10-28 11:28:16 +01:00
e549886532 Do not mess up queue when sorting in select
Closes #181
2019-10-28 11:13:19 +01:00
d3b7032229 Version 4.2.3 2019-10-13 13:44:38 +02:00
5586bcb671 Update changelog 2019-10-13 13:44:05 +02:00
bd72c417d2 Remove sounds on Opera
See #125
2019-10-13 13:44:05 +02:00
52643e0bec Update feature_request.md 2019-10-11 17:38:14 +02:00
af59fb60ff Improve bug report template. 2019-10-11 17:37:04 +02:00
ac2bc8cdfd Add privacy notice 2019-10-11 17:26:17 +02:00
c5309a8923 Always import links in the right context
Closes #163
2019-10-11 15:47:16 +02:00
1370723e6d Push raw indexes 2019-10-11 15:47:16 +02:00
4ba827fc15 Make sure we're on background 2019-10-11 15:47:16 +02:00
b2e20b9875 Update zh_CN translation (#161) 2019-10-11 13:39:36 +02:00
ef9cff003d Update ru translation
Closes #160
2019-10-11 13:37:21 +02:00
74b3ce7eb1 Dark mode: improve display of disabled menu items 2019-10-11 13:28:41 +02:00
6528e2118e Show context when no selection
Closes #162
2019-10-11 13:28:18 +02:00
c901438216 Link landing from changelog 2019-10-09 20:56:02 +02:00
7a0718d9cc Version 4.2.2 2019-10-09 19:13:13 +02:00
a7cc3c7fff Fix landing title 2019-10-09 18:59:45 +02:00
9d313f319d Use the correct full path in tooltips 2019-10-09 18:32:22 +02:00
856044c88c Open landing page on installs 2019-10-09 18:26:36 +02:00
de1b13a50f Add landing page 2019-10-09 18:10:40 +02:00
a981b7b8c7 Update nl locale
Closes #157
2019-10-08 22:24:32 +02:00
abe9d82d03 Always notify all observers 2019-10-08 22:24:32 +02:00
49a3f08a9a Update Arabic translation (#158) 2019-10-08 15:12:38 +02:00
afaa75fcdc Update Bulgarian localization (#156) 2019-10-08 15:12:14 +02:00
a5c749412a Work around Firefox window.create({left, top}) issues 2019-10-07 14:55:01 +02:00
e64da40355 Track window state of manager windows
Closes #154
2019-10-07 14:55:00 +02:00
05e7283f9f Update messages.json (#155) 2019-10-07 14:27:19 +02:00
bea8e230fb Update pl translation
Closes #151
2019-10-06 23:04:53 +02:00
23c1ece807 4 more French strings (#152) 2019-10-06 23:02:11 +02:00
539d340f1a Make prefwatcher not stop event chain
See #148
2019-10-06 22:33:23 +02:00
876486bbf5 Update hungarian translation (#149) 2019-10-06 19:34:58 +02:00
9179851c85 Update zh_TW translation (#147) 2019-10-06 08:44:31 +02:00
1e96d7e787 Version 4.2.1 Beta
For translators
2019-10-06 08:12:27 +02:00
612478bcc7 Add license to changelog 2019-10-06 08:12:00 +02:00
23f84fbde0 Use both .currentSrc and .src for image gathering
Works around some lazy-loader issues and make it at least as compatible as v3

Closes #145
2019-10-06 08:00:50 +02:00
b7b4c57034 Update de 2019-10-06 08:00:50 +02:00
872b058d4c Update et (#146) 2019-10-06 07:56:38 +02:00
93ad3e71db Update of lt locale (#144) 2019-10-05 22:39:52 +02:00
7d824bf61e Update Japanese translation 5th (#143) 2019-10-05 22:39:25 +02:00
06228d9ec9 Update messages.json (#141) 2019-10-03 17:04:27 +02:00
f9232ffd96 Update messages.json (#140) 2019-10-03 14:30:31 +02:00
ab3c335bf1 Polish pref window a bit 2019-10-03 09:04:00 +02:00
9142cc023f Add a basic editorconfig 2019-10-03 08:30:45 +02:00
3133a8d8ad Dark theme modals 2019-10-03 08:26:22 +02:00
312f39f7f6 Dark mode scrollbar colors 2019-10-02 22:09:04 +02:00
4ba7bb530d Close unhandled ports 2019-10-02 21:47:38 +02:00
9caad6b3a5 Detect browser theme on Firefox (#139) 2019-10-02 14:54:51 +02:00
5e323db2f0 Make theme configurable (#139) 2019-10-02 14:24:36 +02:00
18daa28cea Initial dark theme (#139) 2019-10-02 13:57:27 +02:00
65c358c01b Update Readme.md 2019-10-02 10:49:09 +02:00
2d14432efe Update TODO.md 2019-10-02 04:43:45 +02:00
19b1cc8856 Add Character batches
Closes #118
2019-10-02 04:37:19 +02:00
883f9a6f0b Add Changelog 2019-10-02 04:05:32 +02:00
e969ba237a Update packages 2019-10-02 04:04:39 +02:00
207248e706 Update ar translation (#90) 2019-10-02 01:55:26 +02:00
9925dec0f4 Use onDeterminingFilename when supported
Closes #132
2019-09-26 08:46:57 +02:00
09b2b4be10 4.1.2 2019-09-26 07:19:43 +02:00
f331de4134 Add Cmd+F shortcut to focus filter box 2019-09-26 07:08:26 +02:00
7760072e8e Avoid the filter box getting an outline in chrome 2019-09-26 07:02:12 +02:00
626bf592de List da locale in all.json 2019-09-26 06:38:49 +02:00
d550de0e27 Add Danish locale
Close #133
2019-09-26 06:37:49 +02:00
367efb4b53 Fix domain parsing in particular IPs
Closes #135
2019-09-26 06:34:23 +02:00
4a82c62958 Update zh_TW translation (#129) 2019-09-23 07:27:39 +02:00
891aa66bff Update zh_CN translation (#126) 2019-09-23 07:24:50 +02:00
2513b60c1b Update ko locale
Closes #127
2019-09-22 17:22:40 +02:00
31cca481f9 Update nl locale
Closes #128
2019-09-22 17:17:24 +02:00
31999bba9f Version 4.1.1 2019-09-21 09:48:56 +02:00
73d90662e3 Remove debug statement 2019-09-21 09:44:38 +02:00
5f5deb09f3 Add audios to DOM to avoid some playback errors 2019-09-21 09:41:40 +02:00
b68245f4f0 Do not treat CRASH as recoverable 2019-09-21 09:34:27 +02:00
34c8537cb5 Update locale list 2019-09-21 09:26:59 +02:00
6b7c9d461d Update ru translation 2019-09-21 09:26:01 +02:00
d2f09ca592 Added Bulgarian localization (#124) 2019-09-21 09:20:55 +02:00
919c6a8f10 more French strings (#120) 2019-09-19 01:52:30 +02:00
dcd7e7cd0e Update pl translation 2019-09-17 13:46:45 +02:00
c545bbab1d Update de locale 2019-09-17 13:46:45 +02:00
dc6e64e690 Add language specific donate URLs 2019-09-17 13:46:45 +02:00
578762db27 Update of lt locale (#117) 2019-09-17 13:39:41 +02:00
e996a2b41a Indonesia translation update (#115) 2019-09-17 03:43:56 +02:00
38496d9161 Hungarian translation update (#114) 2019-09-17 01:17:14 +02:00
4a0756aa26 Updated Spanish translation (#113) 2019-09-16 19:24:57 +02:00
63d0ff22fa Update Italian translation (#112)
Revised and updated translation, which contains work from me and @harbons
2019-09-16 18:31:17 +02:00
5390642978 Update Estonian translation (#111) 2019-09-16 18:20:11 +02:00
2e59dedda3 Japanese translation 4th (#110) 2019-09-16 18:19:33 +02:00
ee649717a2 Update Portuguese translation (#108) 2019-09-16 18:18:41 +02:00
078ce277ce Fix default subfolder suggestion.
Closes #109
2019-09-16 08:12:34 +02:00
7a3cad83b0 Japanese Translation 3rd (#107) 2019-09-15 19:12:53 +02:00
4d953c373f Basic import/export
Closes #64
2019-09-15 12:28:31 +02:00
da9832552f Update Greek translation
Closes #103
2019-09-15 09:51:14 +02:00
5909633a04 Updated Spanish translation (#101) 2019-09-15 09:45:19 +02:00
750fd987bd Update French translation
Closes #102
2019-09-15 09:43:01 +02:00
b87e0d6138 Japanese Translation 2nd (#100) 2019-09-14 21:33:40 +02:00
31cb23923a Add a subfolders dropdown
The dropdown will help users switch between folders easier than using the mask.
Also, the dropdown is more discoverable than masked folders.

See #2
2019-09-14 01:07:29 +02:00
71d98bc603 Use correct rows for tooltip ETA/status 2019-09-14 00:00:20 +02:00
4b09a0db67 Retries
Closes #95
2019-09-14 00:00:11 +02:00
da6c6bcf68 User Canceled error message 2019-09-13 23:09:44 +02:00
84fea3ba35 Allow to open Manager in a popup
Closes #47
2019-09-13 23:09:44 +02:00
33de1cbce9 Allow setting the referrer in select
Closes #78
2019-09-13 23:09:43 +02:00
04b8a981ef Allow to choose button action
Closes #51
2019-09-13 23:09:43 +02:00
58c7955c64 Add Delete Files action
Closes #92
2019-09-13 23:09:43 +02:00
dcf9603da8 Play done sound
Cloes #81
2019-09-13 23:09:43 +02:00
c2b9664b4b Version 4.0.12 2019-09-13 22:31:55 +02:00
e760d2b022 Handle Chrome state changes correct. 2019-09-12 20:54:16 +02:00
1a836d914b Preroll-nope 401, 402
Closes #89
2019-09-12 13:30:06 +02:00
1b0e6eb6c4 Send referrer with prerolls
See #89
2019-09-12 13:26:24 +02:00
39827ad485 Update TODO 2019-09-12 11:22:55 +02:00
79c4d4e98f typos in the de-locale 2019-09-12 10:00:36 +02:00
427bd2f348 Actually add Italian translation 2019-09-11 23:04:39 +02:00
4fefd0e128 Arabic translation
Closes #90
2019-09-11 23:03:25 +02:00
d79060237d Silence window-type errors 2019-09-10 14:43:49 +02:00
2df7a1c592 do not force ascii in addlocale 2019-09-10 14:43:48 +02:00
8c4ceb3e4b Privetize downloads 2019-09-10 12:44:56 +02:00
bf725ece72 Open links in the correct window context 2019-09-10 12:43:47 +02:00
76992bd4f4 Version 4.0.11 2019-09-10 09:37:00 +02:00
dccd530475 Typo 2019-09-10 09:33:32 +02:00
f1fa01a0eb Add ja to locale list 2019-09-10 09:30:59 +02:00
7949142ef6 Japanese translation (#83) 2019-09-10 09:29:12 +02:00
af1da8fc0a Fix maximized state being refused with dims
Closes #84
2019-09-10 09:23:43 +02:00
39f4237cde Update Indonesian translation (#80) 2019-09-09 18:07:07 +02:00
b676ed74cd Update locale list 2019-09-08 21:30:21 +02:00
bf474877ca Add Italian translation (#49) 2019-09-08 21:27:42 +02:00
7ee13af238 Version 4.0.10 2019-09-07 22:51:06 +02:00
d488e5874a Correct license header 2019-09-07 22:51:06 +02:00
b1a7c22452 Dismiss tooltip when the selection changes 2019-09-07 22:46:24 +02:00
e928d202ee Use the same base font size on all platforms 2019-09-07 20:13:37 +02:00
c39961d253 Make sure application/octet-stream is not mime-able 2019-09-07 19:39:43 +02:00
c6d11fcd7f Give MimeDB a class name 2019-09-07 19:34:12 +02:00
eb96103478 Sanitiy check detected names if we got a mime 2019-09-07 19:32:51 +02:00
583ccfc7b1 Detect name from query string 2019-09-07 19:27:28 +02:00
e0437718a0 Do not register remove-complete twice 2019-09-07 18:58:27 +02:00
2126ae022b Move preroller to it's own class 2019-09-07 18:27:31 +02:00
2ef39dcb19 Add some minor tests for mime 2019-09-07 17:54:12 +02:00
047c865e76 The things you see only after yu push... 2019-09-07 10:27:01 +02:00
c586cd00cc Switch to @Rob--W's CD parser
I "cleaned" up the library according to my personal preferences.
I tend to do this because in the process I need to develop a deeper
understanding of the code, and not because there was nothing wrong
with it.
I deeply appreciate the work that went into creating this library
and releasing it open source 👍

Closes #72
2019-09-07 10:22:09 +02:00
ee7f470269 Use ranges in preroll to avoid large downloads
This will effectively request the first 2 bytes from a server?
Why 2 bytes? Because a lot of servers are broken when bytes=0-0

Related to #70
2019-09-06 21:56:00 +02:00
f04dda308b Adding Hungarian locale, translation (#69) 2019-09-06 20:55:46 +02:00
071458e262 Switch preroll to GET
Fixes #70
2019-09-06 20:42:00 +02:00
9ffc96de4d Purge ourselves from history and sessions
Closes #66
2019-09-06 09:57:24 +02:00
AC
26e9a5404a Add Shift-Delete keyboard shortcut 2019-09-06 04:38:04 +02:00
f44fe59054 Polishing of some lt locale translations (#67) 2019-09-05 10:35:30 +02:00
e4b0629dee Version 4.0.9 2019-09-05 09:18:08 +02:00
5c2700ca36 Tooltip improvements 2019-09-05 09:03:50 +02:00
639a582804 Add small animation when opening files 2019-09-05 08:55:11 +02:00
2d1f185fcd Disable shelf in chrome
We cannot just disable it for our downloads (reliably)
so disable it completely while we're running.
2019-09-05 07:40:17 +02:00
38735ed0ae Make progress bar a little round 2019-09-05 07:39:19 +02:00
216bc590da Do not forget about 405 - Method not allowed 2019-09-04 21:34:52 +02:00
1c10d8005a Improve PREROLL based on user feedback 2019-09-04 21:27:03 +02:00
1fcfbe5360 Adjust default widths a bit 2019-09-04 21:15:32 +02:00
8d3dda1cec Bold buttons 2019-09-04 14:56:37 +02:00
be18f667d9 Trigger the saveQueue before reload 2019-09-04 14:48:35 +02:00
027b2c4fb1 Saving after preroll may have cause dupes 2019-09-04 14:48:35 +02:00
4ed92878be Update of zh_CN locale (#56) 2019-09-04 14:20:13 +02:00
a6930f309e Update ru locale 2019-09-04 14:15:06 +02:00
fdcdae0412 Use promises in content scripts 2019-09-04 14:15:06 +02:00
2c18ddaaa8 Increase shelf timeout 2019-09-04 14:15:06 +02:00
994e7ad0a6 Do not wait on downloads to finish prerollling 2019-09-04 14:15:06 +02:00
95536b36be Do not attempt to restart bg complete 2019-09-04 14:15:06 +02:00
9c159d5d24 Do not wait for the scheduler on startup 2019-09-04 14:15:06 +02:00
42ccfd5dc5 Do not abuse serverName to store browserName 2019-09-04 14:15:05 +02:00
dabf7f8a28 Prerolling and mime detection for some downloads
Only attempt this for a limited subset of downloads for now.
Related #45
2019-09-04 14:15:05 +02:00
9cac48f439 Make all tabs work again 2019-09-04 14:15:05 +02:00
ef6bc840d8 Do not trace 2019-09-04 14:15:00 +02:00
1c38ec1357 Add zh_TW locale (#62) 2019-09-04 12:03:50 +02:00
a4436bd6c8 Force Start should apply to Queued downloads
Closes #57
2019-09-03 18:18:07 +02:00
5a4b8143b2 Remove some any-types 2019-09-03 18:18:07 +02:00
00a5712427 Update of lt locale (#55) 2019-09-03 15:08:24 +02:00
131 changed files with 20439 additions and 5130 deletions

View File

@ -1,6 +1,6 @@
---
name: Bug report
about: Create a report to help us improve
about: Create a report to help us improve DownThemAll!
title: ''
labels: ''
assignees: ''
@ -8,9 +8,9 @@ assignees: ''
---
**Desktop (please complete the following information):**
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
- OS: [e.g. Windows 10, macOS, Linux (distribution, desktop environment)]
- Browser and version: [e.g. Firefox 42, Chrome 70, Opera 15, Seamonkey 2.16]
- DownThemAll! version: [e.g. 4.2, 3.0, latest]
**Describe the bug**
A clear and concise description of what the bug is.

View File

@ -1,6 +1,6 @@
---
name: Feature request
about: Suggest an idea for this project
about: Suggest a feature or an idea for DownThemAll!
title: ''
labels: ''
assignees: ''

View File

@ -77,3 +77,13 @@ Licensed under the Mozilla Public License 2.0.
The list itself is licensed under the Mozilla Public License 2.0.
The javascript library accessing it is licensed under the MIT license.
## whatwg-mimetype
Licensed under MIT
## CDHeaderParser
Licensed under MPL-2
(c) 2017 Rob Wu <rob@robwu.nl> (https://robwu.nl)

View File

@ -1,3 +1,7 @@
![DownThemAll!](https://raw.githubusercontent.com/downthemall/downthemall/master/style/icon96.png)
# DownThemAll! WE
The DownThemAll! WebExtension.

12
TODO.md
View File

@ -1,19 +1,13 @@
TODO
---
aka a lot
P2
===
Planned for later.
* Soft errors and retry logic
* Big caveat: When the server still responds, like 50x errors which would be recoverable, we actually have no way of knowing it did in respond in such a way. See P4 - Handle Errors remarks.
* Delete files (well, as far as the browser allows)
* Inter-addon API (basic)
* Add downloads
* Chrome support
* vtable perf: cache column widths
* Download options
* This is a bit more limited, as we cannot modify options of downloads that have been started (and paused) or that are done.
@ -30,11 +24,7 @@ Nice-to-haves.
* Manipulate downloads (e.g. rewrite URLs)
* Native context menus?
* Would require massive reworks incl the need for new icon formats, but potentially feasible.
* Import/Export
* Download priorities (manual scheduling overrides)
* Dark Theme support
* os/browser define be default
* overwritable
* Remove `any` types as possible, and generally improve typescript (new language to me)
P4
@ -46,8 +36,6 @@ Stuff that probably cannot be implemented due to WeberEension limitations.
* Firefox helpfully keeps different lists of downloads. One for newly added downloads, and other ones for "previous" downloads. Turns out the WebExtension API only ever queries the "new" list.
* Segmented downloads
* Cannot be done with WebExtensions - downloads API has no support and manually downloading, storing in temporary add-on storage and reassmbling the downloaded parts later is not only efficient but does not reliabliy work due to storage limitations.
* Handle errors, 404 and such
* The Firefox download manager is too stupid and webRequest does not see Downloads, so cannot be done right now.
* Conflicts: ask when a file exists
* Not supported by Firefox
* Speed limiter

View File

@ -1,17 +1,24 @@
{
"ar": "العربية [ar]",
"bg": "Български [bg]",
"cs": "Čeština (CZ) [cs]",
"da": "Dansk [da]",
"de": "Deutsch [de]",
"el": "Ελληνικά [el]",
"en": "English (US) [en]",
"es": "Español (España) [es]",
"et": "Eesti Keel [et]",
"fr": "Français (FR) [fr]",
"et": "Eesti keel [et]",
"fr": "Français [fr]",
"hu": "Magyar (HU) [hu]",
"id": "Bahasa Indonesia [id]",
"it": "Italiano [it]",
"ja": "日本語 (JP) [ja]",
"ko": "한국어 [ko]",
"lt": "Lietuvių [lt]",
"nl": "Nederlands [nl]",
"pl": "Polski (PL) [pl]",
"pl": "Polski [pl]",
"pt": "Português (Brasil) [pt]",
"ru": "Русский [ru]",
"zh_CN": "简体中文 [zh_CN]"
}
"zh_CN": "简体中文 [zh_CN]",
"zh_TW": "正體中文 [zh_TW]"
}

1300
_locales/ar/messages.json Normal file

File diff suppressed because it is too large Load Diff

1300
_locales/bg/messages.json Normal file

File diff suppressed because it is too large Load Diff

1284
_locales/da/messages.json Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -191,6 +191,22 @@
"message": "Διαγραφή",
"description": "button text"
},
"deletefiles": {
"message": "Διαγραφή Αρχείων",
"description": "menu action"
},
"deletefiles_button": {
"message": "Διαγραφή",
"description": "button text"
},
"deletefiles_text": {
"message": "Θέλετε σίγουρα να διαγράψετε τα ακόλουθα αρχεία;",
"description": "messagebox text"
},
"deletefiles_title": {
"message": "Διαγραφή Αρχείων",
"description": "messagebox title"
},
"description": {
"message": "Περιγραφή",
"description": "Description (keep it short); e.g. the description column in select"
@ -275,6 +291,14 @@
"message": "Μη έγκυρο URL",
"description": "Error message; single window"
},
"error_noabsolutepath": {
"message": "Οι πλήρεις διαδρομές υποφακέλων δεν υποστηρίζονται από τους φυλλομετρητές",
"description": "Error Message; select/single window"
},
"error_nodotsinpath": {
"message": "Οι τελείες (.) στους υποφακέλους δεν υποστηρίζονται από τους φυλλομετρητές",
"description": "Error Message; select/single window"
},
"error_noItemsSelected": {
"message": "Δεν επιλέχθηκαν αντικείμενα",
"description": "Error Message; select window"
@ -529,6 +553,26 @@
"message": "Προσθήκη νέων λήψεων σε παύση, αντί για άμεση εκκίνησή τους",
"description": "Preferences/General"
},
"pref_button_type": {
"message": "Κουμπί Λήψης Όλων",
"description": "label"
},
"pref_button_type_dta": {
"message": "Επιλογή Λήψης Όλων",
"description": "label"
},
"pref_button_type_manager": {
"message": "Άνοιγμα Διαχειριστή",
"description": "label"
},
"pref_button_type_popup": {
"message": "Αναδυόμενο μενού",
"description": "label"
},
"pref_button_type_turbo": {
"message": "ΜονόΚλικ!",
"description": "label"
},
"pref_concurrent_downloads": {
"message": "Ταυτόχρονες λήψεις",
"description": "Preferences/Network"
@ -537,10 +581,6 @@
"message": "Προβολή ειδοποίησης με την ολοκλήρωση της ουράς λήψεων",
"description": "Preferences/General"
},
"pref_global_turbo": {
"message": "Το κουμπί φυλλομετρητή πρέπει να είναι το ΜονόΚλικ!",
"description": "Preferences/General"
},
"pref_hide_context": {
"message": "Απόκρυψη αντικειμένων μενού γενικού περιεχομένου",
"description": "Preferences/General"
@ -549,6 +589,10 @@
"message": "Διαχειριστής",
"description": "Preferences/General; group text"
},
"pref_manager_in_popup": {
"message": "Άνοιγμα διαχειριστή σε νέο αναδυόμενο παράθυρο",
"description": "checkbox text"
},
"pref_manager_tooltip": {
"message": "Προβολή επεξηγήσεων στις καρτέλες Διαχειριστή",
"description": "Preferences/General"
@ -573,10 +617,22 @@
"message": "Απομάκρυνση αγνοημένων λήψεων μετά την επανεκκίνηση",
"description": "Preferences/General"
},
"pref_retries": {
"message": "Αριθμός επαναλήψεων λήψεων με προσωρινά σφάλματα",
"description": "pref text"
},
"pref_retry_time": {
"message": "Επανάληψη κάθε (σε λεπτά)",
"description": "pref text"
},
"pref_show_urls": {
"message": "Προβολή URLs αντί για Ονόματα",
"description": "Preferences/General"
},
"pref_sounds": {
"message": "Αναπαραγωγή ήχων",
"description": "checkbox text"
},
"pref_text_links": {
"message": "Δοκιμή εύρεσης συνδέσμων στο κείμενο της ιστοσελίδας (αργό)",
"description": "Preferences/General"
@ -895,6 +951,20 @@
"message": "Συνέχιση",
"description": "Action for resuming a download"
},
"retrying": {
"message": "Επανάληψη",
"description": "Status text"
},
"retrying_error": {
"message": "Επανάληψη - $ERROR$",
"description": "status text",
"placeholders": {
"error": {
"content": "$1",
"example": "Server Error"
}
}
},
"running": {
"message": "Σε λειτουργία",
"description": "Status text"
@ -943,6 +1013,18 @@
"message": "Ορισμός Μάσκας Μετονομασίας",
"description": "Menu text; select window"
},
"set_mask_text": {
"message": "Ορισμός μιας νέας μάσκας μετονομασίας",
"description": "dialog text"
},
"set_referrer": {
"message": "Ορισμός Αναφορέα",
"description": "menu text"
},
"set_referrer_text": {
"message": "Ορισμός νέου αναφορέα",
"description": "dialog text"
},
"single_batchexamples": {
"message": "Οι δέσμες υποστηρίζονται, π.χ.:",
"description": "Header text; single window"
@ -1123,6 +1205,14 @@
"message": "Καμία νέα Λήψη δεν θα εκκινηθεί",
"description": "Status bar tooltip; manager network icon"
},
"subfolder": {
"message": "Υποφάκελος:",
"description": "label text"
},
"subfolder_placeholder": {
"message": "Τοποθέτηση αρχείων σε αυτό τον υποφάκελο μέσα στον φάκελο λήψεών σας",
"description": "placeholder text within an input box"
},
"title": {
"message": "Τίτλος",
"description": "Column text; Title label (short)"
@ -1166,5 +1256,9 @@
"useonlyonce": {
"message": "Χρήση μόνο μια φορά",
"description": "Label for Use-Once checkboxes"
},
"USER_CANCELED": {
"message": "Ακύρωση του χρήστη",
"description": "Error message"
}
}

View File

@ -27,18 +27,90 @@
"description": "Error message",
"message": "Unauthorized"
},
"USER_CANCELED": {
"description": "Error message",
"message": "User Canceled"
},
"add_download": {
"description": "Action for adding a download",
"message": "Add Download"
},
"add_new": {
"description": "Button text (adding filters, limits and such)",
"message": "Add New"
},
"add_paused_once": {
"description": "Checkbox label",
"message": "Only add paused this time"
},
"add_paused_question": {
"description": "Messagebox text",
"message": "Do you want to remember this decision and always add new downloads paused from now on?"
},
"add_paused_title": {
"description": "Title for the add-paused dialog",
"message": "Always add paused?"
},
"addpaused": {
"description": "Action: Add paused",
"message": "Add paused"
},
"ask_again_later": {
"description": "Button text",
"message": "Ask me again later"
},
"batch_batch": {
"description": "Button text",
"message": "Batch Download"
},
"batch_desc": {
"description": "",
"message": "The current URL seems to contain instructions for a batch download."
},
"batch_items": {
"description": "Messagebox info text for batch confirmations",
"message": "Number of items:"
},
"batch_preview": {
"description": "Messagebox info text for batch confirmations",
"message": "Preview:"
},
"batch_question": {
"description": "Messagebox info text for batch confirmations",
"message": "Do you want to add this as a batch or as a single download?"
},
"batch_single": {
"description": "Button text for batch confirmation",
"message": "Single Download"
},
"batch_title": {
"description": "Messagebox title for batch confirmations",
"message": "Batch Download"
},
"cancel": {
"description": "Button text: Cancel",
"message": "Cancel"
},
"cancel_download": {
"description": "Action to cancel downloads, e.g. from the context menu",
"message": "Cancel"
},
"canceled": {
"description": "Download status text",
"message": "Canceled"
},
"cannot_be_empty": {
"description": "Error message when an input field is empty but has to have a value",
"message": "This field cannot be empty"
},
"change_later_reminder": {
"description": "Checkbox label text for decision confirmations",
"message": "You can later change this decision in the Preferences"
},
"check_selected_items": {
"description": "Menu text",
"message": "Check Selected Items"
},
"colConnections": {
"description": "Table column in prefs/network",
"message": "Concurrent Connections"
@ -75,276 +147,6 @@
"description": "Table column in manager",
"message": "Speed"
},
"delete": {
"description": "button text",
"message": "Delete"
},
"description": {
"description": "Description (keep it short); e.g. the description column in select",
"message": "Description"
},
"donate": {
"description": "Donate button",
"message": "Donate!"
},
"done": {
"description": "Status text",
"message": "Done"
},
"download": {
"description": "Download (noun); e.g. Download column in select",
"message": "Download"
},
"extensionDescription": {
"description": "DownThemAll! tagline, displayed in about:addons; Please do NOT refer to a specific browser such as firefox, as we will probably support more than one",
"message": "The Mass Downloader for your browser"
},
"fastfiltering": {
"description": "Label for Fast Filtering input",
"message": "Fast Filtering"
},
"finishing": {
"description": "Status text",
"message": "Finishing"
},
"language": {
"description": "Lanuage Name in your language",
"message": "English (US)"
},
"language_code": {
"description": "Language code the locale will use, e.g. de or en-GB or pt-BR",
"message": "en"
},
"links": {
"description": "Links tab label (short); select window",
"message": "Links"
},
"mask": {
"description": "Renaming mask (short); used in e.g. select",
"message": "Mask"
},
"media": {
"description": "Media label (short)",
"message": "Media"
},
"missing": {
"description": "Status text in manager",
"message": "Missing"
},
"ok": {
"description": "Button text; Used in message boxes",
"message": "OK"
},
"paused": {
"description": "Status text; manager",
"message": "Paused"
},
"queued": {
"description": "Status text",
"message": "Queued"
},
"referrer": {
"description": "Label for \"Referrer\"",
"message": "Referrer"
},
"remember": {
"description": "Checkbox text for confirmation, e.g. when removing a download in manager",
"message": "Remember this decision"
},
"rename": {
"description": "UI for renaming; currently unused",
"message": "Rename"
},
"renmask": {
"description": "Renaming mask (long)",
"message": "Renaming mask"
},
"reset": {
"description": "Button text; pref window",
"message": "Reset"
},
"running": {
"description": "Status text",
"message": "Running"
},
"save": {
"description": "Button text; e.g. prefs/Network",
"message": "Save"
},
"search": {
"description": "Placeholder text; manager status search field",
"message": "Search…"
},
"sizeB": {
"description": "Size formatting; bytes",
"message": "$S$B",
"placeholders": {
"s": {
"content": "$1",
"example": "100b"
}
}
},
"sizeGB": {
"description": "Size formatting; giga bytes",
"message": "$S$GB",
"placeholders": {
"s": {
"content": "$1",
"example": "100.200GB"
}
}
},
"sizeKB": {
"description": "Size formatting; kilo bytes",
"message": "$S$KB",
"placeholders": {
"s": {
"content": "$1",
"example": "100.2KB"
}
}
},
"sizeMB": {
"description": "Size formatting; mega bytes",
"message": "$S$MB",
"placeholders": {
"s": {
"content": "$1",
"example": "100.22MB"
}
}
},
"sizePB": {
"description": "Size formatting; peta bytes (you never know)",
"message": "$S$PB",
"placeholders": {
"s": {
"content": "$1",
"example": "100.212PB"
}
}
},
"sizeTB": {
"description": "Size formatting; tera bytes (you never know)",
"message": "$S$TB",
"placeholders": {
"s": {
"content": "$1",
"example": "100.002TB"
}
}
},
"speedB": {
"description": "Speed formatting; bytes",
"message": "$SPEED$b/s",
"placeholders": {
"speed": {
"content": "$1",
"example": "100b/s"
}
}
},
"speedKB": {
"description": "Speed formatting; kilo bytes",
"message": "$SPEED$KB/s",
"placeholders": {
"speed": {
"content": "$1",
"example": "100.1KB/s"
}
}
},
"speedMB": {
"description": "Speed formatting; mega bytes",
"message": "$SPEED$MB/s",
"placeholders": {
"speed": {
"content": "$1",
"example": "100.20MB/s"
}
}
},
"title": {
"description": "Column text; Title label (short)",
"message": "Title"
},
"unlimited": {
"description": "Option text; Prefs/Network",
"message": "Unlimited"
},
"useonlyonce": {
"description": "Label for Use-Once checkboxes",
"message": "Use Once"
},
"add_download": {
"description": "Action for adding a download",
"message": "Add Download"
},
"add_new": {
"description": "Button text (adding filters, limits and such)",
"message": "Add New"
},
"add_paused_once": {
"description": "Checkbox label",
"message": "Only add paused this time"
},
"add_paused_question": {
"description": "Messagebox text",
"message": "Do you want to remember this decision and always add new downloads paused from now on?"
},
"add_paused_title": {
"description": "Title for the add-paused dialog",
"message": "Always add paused?"
},
"ask_again_later": {
"description": "Button text",
"message": "Ask me again later"
},
"batch_batch": {
"description": "Button text",
"message": "Batch Download"
},
"batch_desc": {
"description": "",
"message": "The current URL seems to contain instructions for a batch download."
},
"batch_items": {
"description": "Messagebox info text for batch confirmations",
"message": "Number of items:"
},
"batch_preview": {
"description": "Messagebox info text for batch confirmations",
"message": "Preview:"
},
"batch_question": {
"description": "Messagebox info text for batch confirmations",
"message": "Do you want to add this as a batch or as a single download?"
},
"batch_single": {
"description": "Button text for batch confirmation",
"message": "Single Download"
},
"batch_title": {
"description": "Messagebox title for batch confirmations",
"message": "Batch Download"
},
"cancel_download": {
"description": "Action to cancel downloads, e.g. from the context menu",
"message": "Cancel"
},
"cannot_be_empty": {
"description": "Error message when an input field is empty but has to have a value",
"message": "This field cannot be empty"
},
"change_later_reminder": {
"description": "Checkbox label text for decision confirmations",
"message": "You can later change this decision in the Preferences"
},
"check_selected_items": {
"description": "Menu text",
"message": "Check Selected Items"
},
"conflict_overwrite": {
"description": "Option text; prefs/general",
"message": "Overwrite"
@ -405,26 +207,58 @@
"description": "Filter label for the Videos filter",
"message": "Videos (mp4, webm, mkv, …)"
},
"delete": {
"description": "button text",
"message": "Delete"
},
"deletefiles": {
"description": "menu action",
"message": "Delete Files"
},
"deletefiles_button": {
"description": "button text",
"message": "Delete"
},
"deletefiles_text": {
"description": "messagebox text",
"message": "Are you sure you want to delete the following files?"
},
"deletefiles_title": {
"description": "messagebox title",
"message": "Delete Files"
},
"description": {
"description": "Description (keep it short); e.g. the description column in select",
"message": "Description"
},
"disable_other_filters": {
"description": "Checkbox label. Keep it short",
"message": "Disable others"
},
"donate": {
"description": "Donate button",
"message": "Donate!"
},
"done": {
"description": "Status text",
"message": "Done"
},
"download": {
"description": "Download (noun); e.g. Download column in select",
"message": "Download"
},
"download_verb": {
"description": "Download (verb/action); e.g. in single and select buttons",
"message": "Download"
},
"dta_regular_all": {
"description": "Menu text",
"message": "DownThemAll! - All Tabs"
},
"dta_turbo_all": {
"description": "Menu text",
"message": "OneClick! - All Tabs"
},
"dta_regular": {
"description": "Regular dta action; Menu text",
"message": "DownThemAll!"
},
"dta_regular_all": {
"description": "Menu text",
"message": "DownThemAll! - All Tabs"
},
"dta_regular_image": {
"description": "Menu text",
"message": "Save Image with DownThemAll!"
@ -445,6 +279,10 @@
"description": "OneClick! action; Menu text",
"message": "OneClick!"
},
"dta_turbo_all": {
"description": "Menu text",
"message": "OneClick! - All Tabs"
},
"dta_turbo_image": {
"description": "Menu text",
"message": "Save Image with OneClick!"
@ -477,10 +315,42 @@
"description": "Error Message; select window",
"message": "No items selected"
},
"error_noabsolutepath": {
"description": "Error Message; select/single window",
"message": "Absolute paths for subfolders are not supported by browsers"
},
"error_nodotsinpath": {
"description": "Error Message; select/single window",
"message": "Dots (.) in subfolders are not supported by browsers"
},
"export": {
"description": "menu text",
"message": "Export To File"
},
"export_aria2": {
"description": "menu text",
"message": "Export As aria2 List"
},
"export_metalink": {
"description": "menu text",
"message": "Export As Metalink"
},
"export_text": {
"description": "menu text",
"message": "Export As Text"
},
"extensionDescription": {
"description": "DownThemAll! tagline, displayed in about:addons; Please do NOT refer to a specific browser such as firefox, as we will probably support more than one",
"message": "The Mass Downloader for your browser"
},
"fastfilter_placeholder": {
"description": "Placeholder for fastfilter inputs",
"message": "Wildcard expression or regular expression"
},
"fastfiltering": {
"description": "Label for Fast Filtering input",
"message": "Fast Filtering"
},
"filter_at_least_one": {
"description": "Error message when no filter types are selected for a filter in the preferences UI",
"message": "You must select at least one filter type!"
@ -509,10 +379,18 @@
"description": "Message box label",
"message": "Filter-Types"
},
"finishing": {
"description": "Status text",
"message": "Finishing"
},
"force_start": {
"description": "Menu text",
"message": "Force Start"
},
"import": {
"description": "menu text",
"message": "Import From File"
},
"information_title": {
"description": "Used in message boxes",
"message": "Information"
@ -553,10 +431,26 @@
"description": "Short for PageUp-key",
"message": "PageUp"
},
"language": {
"description": "Lanuage Name in your language",
"message": "English (US)"
},
"language_code": {
"description": "Language code the locale will use, e.g. de or en-GB or pt-BR",
"message": "en"
},
"limited_to": {
"description": "Label text; used in prefs/network",
"message": "Limited to"
},
"links": {
"description": "Links tab label (short); select window",
"message": "Links"
},
"manager_short": {
"description": "Menu text",
"message": "Manager"
},
"manager_status_items": {
"description": "Status bar text; manager",
"message": "Completed $COMPLETE$ of $TOTAL$ downloads ($SHOWING$ displayed), $RUNNING$ running",
@ -579,18 +473,26 @@
}
}
},
"manager_short": {
"description": "Menu text",
"message": "Manager"
},
"manager_title": {
"description": "Window/tab title",
"message": "DownThemAll! Manager"
},
"mask": {
"description": "Renaming mask (short); used in e.g. select",
"message": "Mask"
},
"mask_default": {
"description": "Status text; Used in the mask column, select window",
"message": "Default Mask"
},
"media": {
"description": "Media label (short)",
"message": "Media"
},
"missing": {
"description": "Status text in manager",
"message": "Missing"
},
"move_bottom": {
"description": "Action for moving a download to the bottom",
"message": "Bottom"
@ -639,6 +541,10 @@
}
}
},
"ok": {
"description": "Button text; Used in message boxes",
"message": "OK"
},
"open_directory": {
"description": "Menu text; manager context",
"message": "Open Directory"
@ -667,10 +573,34 @@
"description": "Action for pausing a download",
"message": "Pause"
},
"paused": {
"description": "Status text; manager",
"message": "Paused"
},
"pref_add_paused": {
"description": "Preferences/General",
"message": "Add new downloads paused, instead of starting them immediately"
},
"pref_button_type": {
"description": "label",
"message": "DownThemAll! button:"
},
"pref_button_type_dta": {
"description": "label",
"message": "DownThemAll! selection"
},
"pref_button_type_manager": {
"description": "label",
"message": "Open Manager"
},
"pref_button_type_popup": {
"description": "label",
"message": "Popup menu"
},
"pref_button_type_turbo": {
"description": "label",
"message": "OneClick!"
},
"pref_concurrent_downloads": {
"description": "Preferences/Network",
"message": "Concurrent downloads"
@ -679,18 +609,26 @@
"description": "Preferences/General",
"message": "Show a notification when the queue finishes downloading"
},
"pref_global_turbo": {
"description": "Preferences/General",
"message": "Browser button should be OneClick!"
},
"pref_hide_context": {
"description": "Preferences/General",
"message": "Do not show general context menu items"
},
"pref_manager": {
"description": "Preferences/General; group text",
"message": "Manager"
},
"pref_manager_in_popup": {
"description": "checkbox text",
"message": "Open manager in a new popup window"
},
"pref_manager_tooltip": {
"description": "Preferences/General",
"message": "Show tooltips in Manager tabs"
},
"pref_netglobal": {
"description": "Preferences/General; group text",
"message": "Global Network Limits"
},
"pref_open_manager_on_queue": {
"description": "Preferences/General",
"message": "Open the Manager tab after queuing some downloads"
@ -699,29 +637,49 @@
"description": "Preferences/General",
"message": "Show a notification when queuing new downloads"
},
"pref_queueing": {
"description": "Preferences/General; group text",
"message": "Queuing Downloads"
},
"pref_remove_missing_on_init": {
"description": "Preferences/General",
"message": "Remove missing downloads after a restart"
},
"pref_retries": {
"description": "pref text",
"message": "Number of retries of downloads on temporary errors"
},
"pref_retry_time": {
"description": "pref text",
"message": "Retry every (in minutes)"
},
"pref_show_urls": {
"description": "Preferences/General",
"message": "Show URLs instead of Names"
},
"pref_sounds": {
"description": "checkbox text",
"message": "Play sounds"
},
"pref_text_links": {
"description": "Preferences/General",
"message": "Try to find links in the website text (slower)"
},
"pref_manager": {
"description": "Preferences/General; group text",
"message": "Manager"
"pref_theme": {
"description": "label text",
"message": "Theme:"
},
"pref_netglobal": {
"description": "Preferences/General; group text",
"message": "Global Network Limits"
"pref_theme_dark": {
"description": "option text",
"message": "Dark"
},
"pref_queueing": {
"description": "Preferences/General; group text",
"message": "Queuing Downloads"
"pref_theme_default": {
"description": "option text",
"message": "System/Browser"
},
"pref_theme_light": {
"description": "option text",
"message": "Light"
},
"pref_ui": {
"description": "Preferences/General; group text",
@ -743,6 +701,10 @@
"description": "Notification text",
"message": "The download queue has finished"
},
"queued": {
"description": "Status text",
"message": "Queued"
},
"queued_download": {
"description": "Notification text; single download",
"message": "Queued 1 download!"
@ -757,6 +719,14 @@
}
}
},
"referrer": {
"description": "Label for \"Referrer\"",
"message": "Referrer"
},
"remember": {
"description": "Checkbox text for confirmation, e.g. when removing a download in manager",
"message": "Remember this decision"
},
"remove_all_complete_downloads": {
"description": "Menu text",
"message": "Remove All Complete"
@ -889,6 +859,10 @@
"description": "Menu text",
"message": "Remove Selected"
},
"rename": {
"description": "UI for renaming; currently unused",
"message": "Rename"
},
"renamer_batch": {
"description": "Mask text; see mask button",
"message": "Batch Number"
@ -1005,6 +979,14 @@
"description": "Mask text; see mask button",
"message": "Date Added - Year"
},
"renmask": {
"description": "Renaming mask (long)",
"message": "Renaming mask"
},
"reset": {
"description": "Button text; pref window",
"message": "Reset"
},
"reset_confirmations": {
"description": "Button text; pref/General",
"message": "Reset remembered confirmations"
@ -1025,6 +1007,32 @@
"description": "Action for resuming a download",
"message": "Resume"
},
"retrying": {
"description": "Status text",
"message": "Retrying"
},
"retrying_error": {
"description": "status text",
"message": "Retrying - $ERROR$",
"placeholders": {
"error": {
"content": "$1",
"example": "Server Error"
}
}
},
"running": {
"description": "Status text",
"message": "Running"
},
"save": {
"description": "Button text; e.g. prefs/Network",
"message": "Save"
},
"search": {
"description": "Placeholder text; manager status search field",
"message": "Search…"
},
"select_all": {
"description": "Menu text; e.g. select context",
"message": "Select All"
@ -1045,6 +1053,18 @@
"description": "Menu text; select window",
"message": "Set Renaming Mask"
},
"set_mask_text": {
"description": "dialog text",
"message": "Set a new renaming mask"
},
"set_referrer": {
"description": "menu text",
"message": "Set Referrer"
},
"set_referrer_text": {
"description": "dialog text",
"message": "Set a new referrer"
},
"single_batchexamples": {
"description": "Header text; single window",
"message": "Batches are supported, e.g.:"
@ -1057,6 +1077,66 @@
"description": "Title of single window",
"message": "DownThemAll! - Add a link"
},
"sizeB": {
"description": "Size formatting; bytes",
"message": "$S$B",
"placeholders": {
"s": {
"content": "$1",
"example": "100b"
}
}
},
"sizeGB": {
"description": "Size formatting; giga bytes",
"message": "$S$GB",
"placeholders": {
"s": {
"content": "$1",
"example": "100.200GB"
}
}
},
"sizeKB": {
"description": "Size formatting; kilo bytes",
"message": "$S$KB",
"placeholders": {
"s": {
"content": "$1",
"example": "100.2KB"
}
}
},
"sizeMB": {
"description": "Size formatting; mega bytes",
"message": "$S$MB",
"placeholders": {
"s": {
"content": "$1",
"example": "100.22MB"
}
}
},
"sizePB": {
"description": "Size formatting; peta bytes (you never know)",
"message": "$S$PB",
"placeholders": {
"s": {
"content": "$1",
"example": "100.212PB"
}
}
},
"sizeTB": {
"description": "Size formatting; tera bytes (you never know)",
"message": "$S$TB",
"placeholders": {
"s": {
"content": "$1",
"example": "100.002TB"
}
}
},
"size_progress": {
"description": "Status text; manager size column",
"message": "$WRITTEN$ of $TOTAL$",
@ -1127,6 +1207,36 @@
}
}
},
"speedB": {
"description": "Speed formatting; bytes",
"message": "$SPEED$b/s",
"placeholders": {
"speed": {
"content": "$1",
"example": "100b/s"
}
}
},
"speedKB": {
"description": "Speed formatting; kilo bytes",
"message": "$SPEED$KB/s",
"placeholders": {
"speed": {
"content": "$1",
"example": "100.1KB/s"
}
}
},
"speedMB": {
"description": "Speed formatting; mega bytes",
"message": "$SPEED$MB/s",
"placeholders": {
"speed": {
"content": "$1",
"example": "100.20MB/s"
}
}
},
"statusNetwork_active_title": {
"description": "Status bar tooltip; manager network icon",
"message": "New Downloads will be started"
@ -1135,6 +1245,18 @@
"description": "Status bar tooltip; manager network icon",
"message": "No new Downloads will be started"
},
"subfolder": {
"description": "label text",
"message": "Subfolder:"
},
"subfolder_placeholder": {
"description": "placeholder text within an input box",
"message": "Place files in this subfolder within your downloads directory"
},
"title": {
"description": "Column text; Title label (short)",
"message": "Title"
},
"toggle_selected_items": {
"description": "Menu text; select",
"message": "Toggle Check for Selected Items"
@ -1166,5 +1288,13 @@
"uncheck_selected_items": {
"description": "Menu text; select",
"message": "Uncheck Selected Items"
},
"unlimited": {
"description": "Option text; Prefs/Network",
"message": "Unlimited"
},
"useonlyonce": {
"description": "Label for Use-Once checkboxes",
"message": "Use Once"
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1300
_locales/hu/messages.json Normal file

File diff suppressed because it is too large Load Diff

View File

@ -24,7 +24,7 @@
"description": "Checkbox label"
},
"add_paused_question": {
"message": "Apa Anda ingin mengingat keputusan ini dan mulai sekarang tambahkan unduhan dalam kondisi terpause?",
"message": "Ingat keputusan ini dan tambahkan unduhan dalam kondisi terpause mulai sekarang?",
"description": "Messagebox text"
},
"add_paused_title": {
@ -175,6 +175,22 @@
"message": "Hapus",
"description": "button text"
},
"deletefiles": {
"message": "Hapus Berkas",
"description": "menu action"
},
"deletefiles_button": {
"message": "Hapus",
"description": "button text"
},
"deletefiles_text": {
"message": "Hapus berkas-berkas berikut ini?",
"description": "messagebox text"
},
"deletefiles_title": {
"message": "Hapus Berkas",
"description": "messagebox title"
},
"description": {
"message": "Keterangan",
"description": "Description (keep it short); e.g. the description column in select"
@ -251,10 +267,34 @@
"message": "URL Tidak Benar",
"description": "Error message; single window"
},
"error_noabsolutepath": {
"message": "Path absolut untuk subfolder tidak didukung oleh peramban",
"description": "Error Message; select/single window"
},
"error_nodotsinpath": {
"message": "Titik (.) di subfolder tidak didukung oleh peramban",
"description": "Error Message; select/single window"
},
"error_noItemsSelected": {
"message": "Tidak ada item terpilih",
"description": "Error Message; select window"
},
"export": {
"message": "Ekspor Ke Berkas",
"description": "menu text"
},
"export_aria2": {
"message": "Ekspor Sebagai Daftar aria2",
"description": "menu text"
},
"export_metalink": {
"message": "Ekspor Sebagai Metalink",
"description": "menu text"
},
"export_text": {
"message": "Ekspor Sebagai Teks",
"description": "menu text"
},
"extensionDescription": {
"message": "Pengunduh Masal untuk browser anda",
"description": "DownThemAll! tagline, displayed in about:addons; Please do NOT refer to a specific browser such as firefox, as we will probably support more than one"
@ -280,15 +320,15 @@
"description": "Message box title"
},
"filter_expression": {
"message": "Ekspres-Filter",
"message": "Ekspresi",
"description": "Message box label"
},
"filter_label": {
"message": "Label-Filter",
"message": "Label",
"description": "Message box label"
},
"filter_types": {
"message": "Tipe-Filter",
"message": "Tipe",
"description": "Message box label"
},
"filter_type_link": {
@ -307,6 +347,10 @@
"message": "Paksa Mulai",
"description": "Menu text"
},
"import": {
"message": "Impor Dari Berkas",
"description": "menu text"
},
"information_title": {
"message": "Informasi",
"description": "Used in message boxes"
@ -320,7 +364,7 @@
"description": "Menu text"
},
"limited_to": {
"message": "Terbatas ke",
"message": "Batasi ke",
"description": "Label text; used in prefs/network"
},
"links": {
@ -362,11 +406,11 @@
"description": "Status text; Used in the mask column, select window"
},
"missing": {
"message": "Tidak Ada",
"message": "Hilang",
"description": "Status text in manager"
},
"move_bottom": {
"message": "Bawah",
"message": "Ke Bawah",
"description": "Action for moving a download to the bottom"
},
"move_down": {
@ -374,7 +418,7 @@
"description": "Action for moving a download down"
},
"move_top": {
"message": "Atas",
"message": "Ke Atas",
"description": "Action for moving a download to the top"
},
"move_up": {
@ -461,6 +505,22 @@
"message": "Tambahkan unduhan terpause, alih-alih langsung memulai mengunduh",
"description": "Preferences/General"
},
"pref_button_type": {
"message": "Tombol DownThemAll!:",
"description": "label"
},
"pref_button_type_dta": {
"message": "Pilihan DownThemAll!",
"description": "label"
},
"pref_button_type_manager": {
"message": "Buka Pengelola",
"description": "label"
},
"pref_button_type_popup": {
"message": "Menu popup",
"description": "label"
},
"pref_concurrent_downloads": {
"message": "Unduhan Bersamaan",
"description": "Preferences/Network"
@ -469,10 +529,6 @@
"message": "Tampilkan pemberitahuan ketika antrian unduhan selesai",
"description": "Preferences/General"
},
"pref_global_turbo": {
"message": "Tombol peramban sebaiknya OneClick!",
"description": "Preferences/General"
},
"pref_hide_context": {
"message": "Jangan perlihatkan item menu general context",
"description": "Preferences/General"
@ -481,6 +537,10 @@
"message": "Pengelola",
"description": "Preferences/General; group text"
},
"pref_manager_in_popup": {
"message": "Buka pengelola di jendela popup baru",
"description": "checkbox text"
},
"pref_manager_tooltip": {
"message": "Tampilkan tooltip di tab Pengelola",
"description": "Preferences/General"
@ -505,10 +565,22 @@
"message": "Setelah restart, hapus unduhan yang tidak ada",
"description": "Preferences/General"
},
"pref_retries": {
"message": "Jumlah percobaan ulang ketika gagal mengunduh",
"description": "pref text"
},
"pref_retry_time": {
"message": "Coba setiap (dalam menit)",
"description": "pref text"
},
"pref_show_urls": {
"message": "Tampilan URL alih-alih Nama",
"description": "Preferences/General"
},
"pref_sounds": {
"message": "Bunyikan suara",
"description": "checkbox text"
},
"pref_text_links": {
"message": "Coba cari tautan di teks di situs web (lambat)",
"description": "Preferences/General"
@ -560,7 +632,7 @@
"description": "Menu text"
},
"remove_batch_downloads_question": {
"message": "Hapus semua unduhan dari kumpulan yang sama dengan unduhan terpilih?",
"message": "Hapus semua unduhan dari batch yang sama dengan unduhan terpilih?",
"description": "Messagebox text"
},
"remove_complete_downloads": {
@ -600,7 +672,7 @@
}
},
"remove_domain_downloads": {
"message": "Hapus Domain Ini",
"message": "Hapus Unduhan Dari Domain Ini",
"description": "Menu text"
},
"remove_domain_downloads_question": {
@ -630,7 +702,7 @@
"description": "Messagebox text"
},
"remove_failed_downloads": {
"message": "Gagal Menghapus",
"message": "Hapus Unduhan Gagal",
"description": "Menu text"
},
"remove_failed_downloads_question": {
@ -648,11 +720,11 @@
}
},
"remove_missing": {
"message": "Hapus Unduhan Yang Tidak Ada",
"message": "Hapus Unduhan Yang Hilang",
"description": "Menu text"
},
"remove_missing_downloads_question": {
"message": "Hapus semua unduhan yang tidak ada?",
"message": "Hapus semua unduhan yang hilang?",
"description": "Messagebox text"
},
"remove_paused_downloads": {
@ -664,7 +736,7 @@
"description": "Messagebox text"
},
"remove_selected_complete_downloads": {
"message": "Hapus Yang Selesai Di Pilihan",
"message": "Hapus Yang Selesai Dari Unduhan Terpilih",
"description": "Menu text"
},
"remove_selected_complete_downloads_question": {
@ -767,6 +839,10 @@
"message": "Tanggal Ditambahkan - Detik",
"description": "Mask text; see mask button"
},
"renamer_tags": {
"message": "Penanda Mask Penamaan",
"description": "Mask text; see mask button"
},
"renamer_text": {
"message": "Teks Deskripsi",
"description": "Mask text; see mask button"
@ -783,6 +859,10 @@
"message": "Tanggal Ditambahkan - Tahun",
"description": "Mask text; see mask button"
},
"renmask": {
"message": "Mask penamaan",
"description": "Renaming mask (long)"
},
"reset": {
"message": "Atur Ulang",
"description": "Button text; pref window"
@ -807,6 +887,20 @@
"message": "Lanjutkan",
"description": "Action for resuming a download"
},
"retrying": {
"message": "Mengulang",
"description": "Status text"
},
"retrying_error": {
"message": "Mengulang - $ERROR$",
"description": "status text",
"placeholders": {
"error": {
"content": "$1",
"example": "Server Error"
}
}
},
"running": {
"message": "Berjalan",
"description": "Status text"
@ -851,6 +945,22 @@
"message": "Tidak Diizinkan",
"description": "Error message"
},
"set_mask": {
"message": "Set Mask Penamaan",
"description": "Menu text; select window"
},
"set_mask_text": {
"message": "Tentukan mask penamaan baru",
"description": "dialog text"
},
"set_referrer": {
"message": "Tentukan Referrer",
"description": "menu text"
},
"set_referrer_text": {
"message": "Tentukan referrer baru",
"description": "dialog text"
},
"single_batchexamples": {
"message": "Batch bisa digunakan, misalnya:",
"description": "Header text; single window"
@ -971,6 +1081,10 @@
"message": "Tidak ada Unduhan baru yang akan dimulai",
"description": "Status bar tooltip; manager network icon"
},
"subfolder_placeholder": {
"message": "Simpan berkas di subfolder berikut di dalam direktori unduhan Anda",
"description": "placeholder text within an input box"
},
"title": {
"message": "Judul",
"description": "Column text; Title label (short)"
@ -1014,5 +1128,9 @@
"useonlyonce": {
"message": "Gunakan Sekali",
"description": "Label for Use-Once checkboxes"
},
"USER_CANCELED": {
"message": "Dibatalkan Pengguna",
"description": "Error message"
}
}

1284
_locales/it/messages.json Normal file

File diff suppressed because it is too large Load Diff

1300
_locales/ja/messages.json Normal file

File diff suppressed because it is too large Load Diff

View File

@ -191,6 +191,22 @@
"message": "삭제",
"description": "button text"
},
"deletefiles": {
"message": "파일 삭제",
"description": "menu action"
},
"deletefiles_button": {
"message": "삭제",
"description": "button text"
},
"deletefiles_text": {
"message": "정말 다음 파일(들)을 삭제하시겠습니까?",
"description": "messagebox text"
},
"deletefiles_title": {
"message": "파일 삭제",
"description": "messagebox title"
},
"description": {
"message": "설명",
"description": "Description (keep it short); e.g. the description column in select"
@ -275,10 +291,34 @@
"message": "잘못된 URL",
"description": "Error message; single window"
},
"error_noabsolutepath": {
"message": "하위 폴더의 절대 경로는 브라우저에서 지원되지 않습니다",
"description": "Error Message; select/single window"
},
"error_nodotsinpath": {
"message": "하위 폴더의 점(.)은 브라우저에서 지원되지 않습니다",
"description": "Error Message; select/single window"
},
"error_noItemsSelected": {
"message": "선택된 항목 없음",
"description": "Error Message; select window"
},
"export": {
"message": "파일로 내보내기",
"description": "menu text"
},
"export_aria2": {
"message": "aria2 리스트로 내보내기",
"description": "menu text"
},
"export_metalink": {
"message": "메타링크로 내보내기",
"description": "menu text"
},
"export_text": {
"message": "텍스트로 내보내기",
"description": "menu text"
},
"extensionDescription": {
"message": "브라우저용 대량 다운로더",
"description": "DownThemAll! tagline, displayed in about:addons; Please do NOT refer to a specific browser such as firefox, as we will probably support more than one"
@ -331,6 +371,10 @@
"message": "강제 시작",
"description": "Menu text"
},
"import": {
"message": "파일에서 가져오기",
"description": "menu text"
},
"information_title": {
"message": "정보",
"description": "Used in message boxes"
@ -529,6 +573,26 @@
"message": "새 다운로드를 즉시 시작하는 대신 일시중지로 추가",
"description": "Preferences/General"
},
"pref_button_type": {
"message": "DownThemAll! 버튼:",
"description": "label"
},
"pref_button_type_dta": {
"message": "DownThemAll! 선택",
"description": "label"
},
"pref_button_type_manager": {
"message": "관리자 열기",
"description": "label"
},
"pref_button_type_popup": {
"message": "팝업 메뉴",
"description": "label"
},
"pref_button_type_turbo": {
"message": "OneClick!",
"description": "label"
},
"pref_concurrent_downloads": {
"message": "동시 다운로드",
"description": "Preferences/Network"
@ -537,10 +601,6 @@
"message": "다운로드 대기열이 끝나면 알림 표시",
"description": "Preferences/General"
},
"pref_global_turbo": {
"message": "브라우저 버튼을 OneClick!으로 작동",
"description": "Preferences/General"
},
"pref_hide_context": {
"message": "일반 컨텍스트 메뉴 항목 표시 안 함",
"description": "Preferences/General"
@ -549,6 +609,10 @@
"message": "관리자",
"description": "Preferences/General; group text"
},
"pref_manager_in_popup": {
"message": "새 팝업 창에 관리자 열기",
"description": "checkbox text"
},
"pref_manager_tooltip": {
"message": "관리자 탭에서 툴팁 표시",
"description": "Preferences/General"
@ -573,10 +637,22 @@
"message": "다시 시작한 후 누락된 다운로드 제거",
"description": "Preferences/General"
},
"pref_retries": {
"message": "일시적인 오류에 대한 다운로드 재시도 횟수",
"description": "pref text"
},
"pref_retry_time": {
"message": "재시도 간격 (분)",
"description": "pref text"
},
"pref_show_urls": {
"message": "이름 대신 URL 표시",
"description": "Preferences/General"
},
"pref_sounds": {
"message": "소리 재생",
"description": "checkbox text"
},
"pref_text_links": {
"message": "웹 사이트 텍스트에서 링크를 찾도록 시도 (느림)",
"description": "Preferences/General"
@ -895,6 +971,20 @@
"message": "계속",
"description": "Action for resuming a download"
},
"retrying": {
"message": "재시도중",
"description": "Status text"
},
"retrying_error": {
"message": "재시도중 - $ERROR$",
"description": "status text",
"placeholders": {
"error": {
"content": "$1",
"example": "Server Error"
}
}
},
"running": {
"message": "실행중",
"description": "Status text"
@ -943,6 +1033,18 @@
"message": "이름 바꾸기 마스크 설정",
"description": "Menu text; select window"
},
"set_mask_text": {
"message": "새 이름 바꾸기 마스크 설정",
"description": "dialog text"
},
"set_referrer": {
"message": "참조 페이지 설정",
"description": "menu text"
},
"set_referrer_text": {
"message": "새 참조 페이지 설정",
"description": "dialog text"
},
"single_batchexamples": {
"message": "일괄 처리가 지원됩니다, 예:",
"description": "Header text; single window"
@ -1123,6 +1225,14 @@
"message": "새 다운로드가 시작되지 않습니다",
"description": "Status bar tooltip; manager network icon"
},
"subfolder": {
"message": "하위 폴더",
"description": "label text"
},
"subfolder_placeholder": {
"message": "다운로드 디렉토리 내의 이 하위 폴더에 파일을 저장합니다",
"description": "placeholder text within an input box"
},
"title": {
"message": "제목",
"description": "Column text; Title label (short)"
@ -1166,5 +1276,9 @@
"useonlyonce": {
"message": "한번만",
"description": "Label for Use-Once checkboxes"
},
"USER_CANCELED": {
"message": "사용자 취소",
"description": "Error message"
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

140
_locales/ru/messages.json Normal file → Executable file
View File

@ -191,6 +191,22 @@
"message": "Удалить",
"description": "button text"
},
"deletefiles": {
"message": "Удалить файлы",
"description": "menu action"
},
"deletefiles_button": {
"message": "Удалить",
"description": "button text"
},
"deletefiles_text": {
"message": "Точно удалить эти файлы?",
"description": "messagebox text"
},
"deletefiles_title": {
"message": "Удаление файлов",
"description": "messagebox title"
},
"description": {
"message": "Описание",
"description": "Description (keep it short); e.g. the description column in select"
@ -244,7 +260,7 @@
"description": "OneClick! action; Menu text"
},
"dta_turbo_all": {
"message": "ОднимКликом! - Все вкладки",
"message": "OneClick! - Все вкладки",
"description": "Menu text"
},
"dta_turbo_image": {
@ -275,10 +291,34 @@
"message": "Неправильная ссылка",
"description": "Error message; single window"
},
"error_noabsolutepath": {
"message": "Полные пути к папкам не поддерживаются браузерами",
"description": "Error Message; select/single window"
},
"error_nodotsinpath": {
"message": "Точки (.) в названии папок не поддерживаются браузерами",
"description": "Error Message; select/single window"
},
"error_noItemsSelected": {
"message": "Ничего не выбрано",
"description": "Error Message; select window"
},
"export": {
"message": "Экспортировать в файл",
"description": "menu text"
},
"export_aria2": {
"message": "Экспортировать как список для aria2",
"description": "menu text"
},
"export_metalink": {
"message": "Экспортировать как Metalink",
"description": "menu text"
},
"export_text": {
"message": "Экспортировать как текст",
"description": "menu text"
},
"extensionDescription": {
"message": "Универсальная качалка для вашего браузера",
"description": "DownThemAll! tagline, displayed in about:addons; Please do NOT refer to a specific browser such as firefox, as we will probably support more than one"
@ -331,6 +371,10 @@
"message": "Принудительный старт",
"description": "Menu text"
},
"import": {
"message": "Импортировать из файла",
"description": "menu text"
},
"information_title": {
"message": "Информация",
"description": "Used in message boxes"
@ -529,6 +573,26 @@
"message": "Добавлять закачки приостановленными, вместо того чтобы качать сразу",
"description": "Preferences/General"
},
"pref_button_type": {
"message": "Кнопка DownThemAll!",
"description": "label"
},
"pref_button_type_dta": {
"message": "DownThemAll! выделенного",
"description": "label"
},
"pref_button_type_manager": {
"message": "Открыть менеджер",
"description": "label"
},
"pref_button_type_popup": {
"message": "Всплывающее меню",
"description": "label"
},
"pref_button_type_turbo": {
"message": "OneClick!",
"description": "label"
},
"pref_concurrent_downloads": {
"message": "Настройки/Сеть",
"description": "Preferences/Network"
@ -537,10 +601,6 @@
"message": "Показывать уведомление когда список закачек завешен",
"description": "Preferences/General"
},
"pref_global_turbo": {
"message": "Использовать OneClick! по умолчанию на кнопке в браузере",
"description": "Preferences/General"
},
"pref_hide_context": {
"message": "Не добавлять пункты в общее контекстное меню",
"description": "Preferences/General"
@ -549,6 +609,10 @@
"message": "Менеджер",
"description": "Preferences/General; group text"
},
"pref_manager_in_popup": {
"message": "Открывать менеджер в новом всплывающем окне",
"description": "checkbox text"
},
"pref_manager_tooltip": {
"message": "Показывать подсказки на вкладках менеджера",
"description": "Preferences/General"
@ -573,14 +637,42 @@
"message": "Удалять неудавшиеся закачки после перезапуска",
"description": "Preferences/General"
},
"pref_retries": {
"message": "Сколько раз пробовать перезапустить закачку при некритичных сбоях",
"description": "pref text"
},
"pref_retry_time": {
"message": "Как часто пробовать перезапустить закачку (в минутах)",
"description": "pref text"
},
"pref_show_urls": {
"message": "Показывать ссылки вместо имён",
"description": "Preferences/General"
},
"pref_sounds": {
"message": "Проигрывать звуки",
"description": "checkbox text"
},
"pref_text_links": {
"message": "Пытаться обнаружить ссылки в тексте на сайте",
"description": "Preferences/General"
},
"pref_theme": {
"message": "Тема:",
"description": "label text"
},
"pref_theme_dark": {
"message": "Тёмная",
"description": "option text"
},
"pref_theme_default": {
"message": "Система/Браузер",
"description": "option text"
},
"pref_theme_light": {
"message": "Светлая",
"description": "option text"
},
"pref_ui": {
"message": "Интерфейс пользователя",
"description": "Preferences/General; group text"
@ -895,6 +987,20 @@
"message": "Продолжить",
"description": "Action for resuming a download"
},
"retrying": {
"message": "Перезапуск",
"description": "Status text"
},
"retrying_error": {
"message": "Перезапуск - $ERROR$",
"description": "status text",
"placeholders": {
"error": {
"content": "$1",
"example": "Server Error"
}
}
},
"running": {
"message": "В процессе",
"description": "Status text"
@ -943,6 +1049,18 @@
"message": "Задать маску переименования",
"description": "Menu text; select window"
},
"set_mask_text": {
"message": "Задать новую маску переименования",
"description": "dialog text"
},
"set_referrer": {
"message": "Задать реферера",
"description": "menu text"
},
"set_referrer_text": {
"message": "Задать нового реферера",
"description": "dialog text"
},
"single_batchexamples": {
"message": "Можно задать группы, к примеру:",
"description": "Header text; single window"
@ -1123,6 +1241,14 @@
"message": "Новые закачки запускаться не будут",
"description": "Status bar tooltip; manager network icon"
},
"subfolder": {
"message": "Подпапка",
"description": "label text"
},
"subfolder_placeholder": {
"message": "Размещать файлы в подпапке выбранного пути для закачек",
"description": "placeholder text within an input box"
},
"title": {
"message": "Заголовок",
"description": "Column text; Title label (short)"
@ -1166,5 +1292,9 @@
"useonlyonce": {
"message": "Только сейчас",
"description": "Label for Use-Once checkboxes"
},
"USER_CANCELED": {
"message": "Отменено пользователем",
"description": "Error message"
}
}

File diff suppressed because it is too large Load Diff

1300
_locales/zh_TW/messages.json Normal file

File diff suppressed because it is too large Load Diff

396
data/mime.json Normal file
View File

@ -0,0 +1,396 @@
{
"e": {
"3gpp": "3gp",
"asx": "asf",
"gz": "gzip",
"heic": "heif",
"html": [
"htm",
"shtml",
"php"
],
"jar": [
"war",
"ear"
],
"jpg": [
"jpeg",
"jpe",
"jfif"
],
"js": "jsx",
"mid": [
"midi",
"kar"
],
"mkv": [
"mk3d",
"mks"
],
"mov": [
"qt",
"moov"
],
"mpg": [
"mpe",
"mpeg"
],
"pem": [
"crt",
"der"
],
"pl": "pm",
"prc": "pdb",
"ps": [
"eps",
"ai"
],
"svg": "svgz",
"tcl": "tk",
"tif": "tiff"
},
"m": {
"application/7z": "7z",
"application/7z-compressed": "7z",
"application/ai": "ps",
"application/atom": "atom",
"application/atom+xml": "atom",
"application/bz2": "bz2",
"application/bzip2": "bz2",
"application/cco": "cco",
"application/cocoa": "cco",
"application/compressed": "gz",
"application/crt": "pem",
"application/der": "pem",
"application/doc": "doc",
"application/ear": "jar",
"application/eot": "eot",
"application/eps": "ps",
"application/gz": "gz",
"application/gzip": "gz",
"application/hqx": "hqx",
"application/jar": "jar",
"application/jardiff": "jardiff",
"application/java-archive": "jar",
"application/java-archive-diff": "jardiff",
"application/java-jnlp-file": "jnlp",
"application/javascript": "js",
"application/jnlp": "jnlp",
"application/js": "js",
"application/json": "json",
"application/jsx": "js",
"application/kml": "kml",
"application/kmz": "kmz",
"application/m3u8": "m3u8",
"application/mac-binhex40": "hqx",
"application/makeself": "run",
"application/msword": "doc",
"application/odg": "odg",
"application/odp": "odp",
"application/ods": "ods",
"application/odt": "odt",
"application/pdb": "prc",
"application/pdf": "pdf",
"application/pem": "pem",
"application/perl": "pl",
"application/pilot": "prc",
"application/pl": "pl",
"application/pm": "pl",
"application/postscript": "ps",
"application/ppt": "ppt",
"application/prc": "prc",
"application/ps": "ps",
"application/rar": "rar",
"application/rar-compressed": "rar",
"application/redhat-package-manager": "rpm",
"application/rpm": "rpm",
"application/rss": "rss",
"application/rss+xml": "rss",
"application/rtf": "rtf",
"application/run": "run",
"application/sea": "sea",
"application/shockwave-flash": "swf",
"application/sit": "sit",
"application/stuffit": "sit",
"application/swf": "swf",
"application/tar": "tar",
"application/tcl": "tcl",
"application/tk": "tcl",
"application/vnd.apple.mpegurl": "m3u8",
"application/vnd.google-earth.kml+xml": "kml",
"application/vnd.google-earth.kmz": "kmz",
"application/vnd.ms-excel": "xls",
"application/vnd.ms-fontobject": "eot",
"application/vnd.ms-powerpoint": "ppt",
"application/vnd.oasis.opendocument.graphics": "odg",
"application/vnd.oasis.opendocument.presentation": "odp",
"application/vnd.oasis.opendocument.spreadsheet": "ods",
"application/vnd.oasis.opendocument.text": "odt",
"application/vnd.wap.wmlc": "wmlc",
"application/war": "jar",
"application/wmlc": "wmlc",
"application/x-7z": "7z",
"application/x-7z-compressed": "7z",
"application/x-ai": "ps",
"application/x-atom": "atom",
"application/x-atom+xml": "atom",
"application/x-bz2": "bz2",
"application/x-bzip2": "bz2",
"application/x-cco": "cco",
"application/x-cocoa": "cco",
"application/x-compressed": "gz",
"application/x-crt": "pem",
"application/x-der": "pem",
"application/x-doc": "doc",
"application/x-ear": "jar",
"application/x-eot": "eot",
"application/x-eps": "ps",
"application/x-gz": "gz",
"application/x-gzip": "gz",
"application/x-hqx": "hqx",
"application/x-jar": "jar",
"application/x-jardiff": "jardiff",
"application/x-java-archive": "jar",
"application/x-java-archive-diff": "jardiff",
"application/x-java-jnlp-file": "jnlp",
"application/x-javascript": "js",
"application/x-jnlp": "jnlp",
"application/x-js": "js",
"application/x-json": "json",
"application/x-jsx": "js",
"application/x-kml": "kml",
"application/x-kmz": "kmz",
"application/x-m3u8": "m3u8",
"application/x-mac-binhex40": "hqx",
"application/x-makeself": "run",
"application/x-msword": "doc",
"application/x-odg": "odg",
"application/x-odp": "odp",
"application/x-ods": "ods",
"application/x-odt": "odt",
"application/x-pdb": "prc",
"application/x-pdf": "pdf",
"application/x-pem": "pem",
"application/x-perl": "pl",
"application/x-pilot": "prc",
"application/x-pl": "pl",
"application/x-pm": "pl",
"application/x-postscript": "ps",
"application/x-ppt": "ppt",
"application/x-prc": "prc",
"application/x-ps": "ps",
"application/x-rar": "rar",
"application/x-rar-compressed": "rar",
"application/x-redhat-package-manager": "rpm",
"application/x-rpm": "rpm",
"application/x-rss": "rss",
"application/x-rss+xml": "rss",
"application/x-rtf": "rtf",
"application/x-run": "run",
"application/x-sea": "sea",
"application/x-shockwave-flash": "swf",
"application/x-sit": "sit",
"application/x-stuffit": "sit",
"application/x-swf": "swf",
"application/x-tar": "tar",
"application/x-tcl": "tcl",
"application/x-tk": "tcl",
"application/x-vnd.apple.mpegurl": "m3u8",
"application/x-vnd.google-earth.kml+xml": "kml",
"application/x-vnd.google-earth.kmz": "kmz",
"application/x-vnd.ms-excel": "xls",
"application/x-vnd.ms-fontobject": "eot",
"application/x-vnd.ms-powerpoint": "ppt",
"application/x-vnd.oasis.opendocument.graphics": "odg",
"application/x-vnd.oasis.opendocument.presentation": "odp",
"application/x-vnd.oasis.opendocument.spreadsheet": "ods",
"application/x-vnd.oasis.opendocument.text": "odt",
"application/x-vnd.wap.wmlc": "wmlc",
"application/x-war": "jar",
"application/x-wmlc": "wmlc",
"application/x-x509-ca-cert": "pem",
"application/x-xhtml": "xhtml",
"application/x-xhtml+xml": "xhtml",
"application/x-xls": "xls",
"application/x-xpi": "xpi",
"application/x-xpinstall": "xpi",
"application/x-xspf": "xspf",
"application/x-xspf+xml": "xspf",
"application/x-xz": "xz",
"application/x-zip": "zip",
"application/x509-ca-cert": "pem",
"application/xhtml": "xhtml",
"application/xhtml+xml": "xhtml",
"application/xls": "xls",
"application/xpi": "xpi",
"application/xpinstall": "xpi",
"application/xspf": "xspf",
"application/xspf+xml": "xspf",
"application/xz": "xz",
"application/zip": "zip",
"audio/kar": "mid",
"audio/m4a": "m4a",
"audio/matroska": "mka",
"audio/mid": "mid",
"audio/midi": "mid",
"audio/mka": "mka",
"audio/mp3": "mp3",
"audio/mpeg": "mp3",
"audio/ogg": "ogg",
"audio/ra": "ra",
"audio/realaudio": "ra",
"audio/x-kar": "mid",
"audio/x-m4a": "m4a",
"audio/x-matroska": "mka",
"audio/x-mid": "mid",
"audio/x-midi": "mid",
"audio/x-mka": "mka",
"audio/x-mp3": "mp3",
"audio/x-mpeg": "mp3",
"audio/x-ogg": "ogg",
"audio/x-ra": "ra",
"audio/x-realaudio": "ra",
"font/woff": "woff",
"font/woff2": "woff2",
"font/x-woff": "woff",
"font/x-woff2": "woff2",
"image/bmp": "bmp",
"image/gif": "gif",
"image/heic": "heic",
"image/heif": "heic",
"image/heif-sequence": "heic",
"image/ico": "ico",
"image/icon": "ico",
"image/jfif": "jpg",
"image/jng": "jng",
"image/jpe": "jpg",
"image/jpeg": "jpg",
"image/jpg": "jpg",
"image/ms-bmp": "bmp",
"image/png": "png",
"image/svg": "svg",
"image/svg+xml": "svg",
"image/svgz": "svg",
"image/tif": "tif",
"image/tiff": "tif",
"image/vnd.wap.wbmp": "wbmp",
"image/wbmp": "wbmp",
"image/webp": "webp",
"image/x-bmp": "bmp",
"image/x-gif": "gif",
"image/x-heic": "heic",
"image/x-heif": "heic",
"image/x-heif-sequence": "heic",
"image/x-ico": "ico",
"image/x-icon": "ico",
"image/x-jfif": "jpg",
"image/x-jng": "jng",
"image/x-jpe": "jpg",
"image/x-jpeg": "jpg",
"image/x-jpg": "jpg",
"image/x-ms-bmp": "bmp",
"image/x-png": "png",
"image/x-svg": "svg",
"image/x-svg+xml": "svg",
"image/x-svgz": "svg",
"image/x-tif": "tif",
"image/x-tiff": "tif",
"image/x-vnd.wap.wbmp": "wbmp",
"image/x-wbmp": "wbmp",
"image/x-webp": "webp",
"text/component": "htc",
"text/css": "css",
"text/htc": "htc",
"text/htm": "html",
"text/html": "html",
"text/jad": "jad",
"text/javascript": "js",
"text/js": "js",
"text/jsx": "js",
"text/mathml": "mml",
"text/mml": "mml",
"text/php": "html",
"text/plain": "txt",
"text/shtml": "html",
"text/txt": "txt",
"text/vnd.sun.j2me.app-descriptor": "jad",
"text/vnd.wap.wml": "wml",
"text/wml": "wml",
"text/x-component": "htc",
"text/x-css": "css",
"text/x-htc": "htc",
"text/x-htm": "html",
"text/x-html": "html",
"text/x-jad": "jad",
"text/x-javascript": "js",
"text/x-js": "js",
"text/x-jsx": "js",
"text/x-mathml": "mml",
"text/x-mml": "mml",
"text/x-php": "html",
"text/x-plain": "txt",
"text/x-shtml": "html",
"text/x-txt": "txt",
"text/x-vnd.sun.j2me.app-descriptor": "jad",
"text/x-vnd.wap.wml": "wml",
"text/x-wml": "wml",
"text/x-xml": "xml",
"text/xml": "xml",
"video/3gp": "3gpp",
"video/3gpp": "3gpp",
"video/asf": "asx",
"video/asx": "asx",
"video/avi": "avi",
"video/flv": "flv",
"video/m4v": "m4v",
"video/matroska": "mkv",
"video/mk3d": "mkv",
"video/mks": "mkv",
"video/mkv": "mkv",
"video/mng": "mng",
"video/moov": "mov",
"video/mov": "mov",
"video/mp2t": "ts",
"video/mp4": "mp4",
"video/mpe": "mpg",
"video/mpeg": "mpg",
"video/mpg": "mpg",
"video/ms-asf": "asx",
"video/ms-wmv": "wmv",
"video/msvideo": "avi",
"video/opus": "opus",
"video/qt": "mov",
"video/quicktime": "mov",
"video/ts": "ts",
"video/webm": "webm",
"video/wmv": "wmv",
"video/x-3gp": "3gpp",
"video/x-3gpp": "3gpp",
"video/x-asf": "asx",
"video/x-asx": "asx",
"video/x-avi": "avi",
"video/x-flv": "flv",
"video/x-m4v": "m4v",
"video/x-matroska": "mkv",
"video/x-mk3d": "mkv",
"video/x-mks": "mkv",
"video/x-mkv": "mkv",
"video/x-mng": "mng",
"video/x-moov": "mov",
"video/x-mov": "mov",
"video/x-mp2t": "ts",
"video/x-mp4": "mp4",
"video/x-mpe": "mpg",
"video/x-mpeg": "mpg",
"video/x-mpg": "mpg",
"video/x-ms-asf": "asx",
"video/x-ms-wmv": "wmv",
"video/x-msvideo": "avi",
"video/x-opus": "opus",
"video/x-qt": "mov",
"video/x-quicktime": "mov",
"video/x-ts": "ts",
"video/x-webm": "webm",
"video/x-wmv": "wmv"
}
}

View File

@ -1,8 +1,10 @@
{
"global-turbo": false,
"button-type": "popup",
"manager-in-popup": false,
"concurrent": 4,
"queue-notification": true,
"finish-notification": true,
"sounds": true,
"open-manager-on-queue": true,
"text-links": true,
"add-paused": false,
@ -13,6 +15,9 @@
"tooltip": true,
"show-urls": false,
"remove-missing-on-init": false,
"retries": 5,
"retry-time": 10,
"theme": "default",
"limits": [
{
"domain": "*",

387
docs/changelog/index.html Normal file
View File

@ -0,0 +1,387 @@
<!doctype html>
<html lang="en">
<!-- License: Creative Commons Attribution-ShareAlike 4.0 International License -->
<head>
<meta charset="utf-8">
<title>DownThemAll! Changes</title>
<style>
@font-face {
font-family: "Reenie Beanie";
font-style: normal;
font-weight: 400;
font-display: block;
src: local("Reenie Beanie"), local("ReenieBeanie"),
url(res/ReenieBeanie-Regular.woff2) format("woff2");
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
U+FEFF, U+FFFD;
}
:root {
--content-width: 1000px;
}
html,
body {
margin: 0;
padding: 0;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Ubuntu",
"Helvetica Neue", sans-serif;
font-size: 12pt;
color: rgb(20, 20, 20);
background: white;
width: 100%;
height: 100%;
}
body {
display: grid;
background: white repeat-x url(res/background-tile.png);
grid-template-columns: 1fr [content] auto 1fr;
grid-template-rows: auto 1fr auto;
grid-template-areas:
". header ."
". content ."
"footer footer footer";
}
a {
color: rgb(30, 30, 70);
}
li {
list-style-type: circle;
}
p {
margin: 0;
margin-bottom: 16px;
}
nav {
max-width: var(--content-width);
grid-area: header;
display: flex;
box-sizing: border-box;
padding-right: 120px;
padding-top: 1em;
padding-left: 48px;
align-content: center;
align-items: baseline;
background: no-repeat top right url(res/halo.svg);
background-size: 120px;
min-height: 100px;
text-shadow: rgba(255, 255, 255, 0.8) 1px 3px 0px;
font-family: "Reenie Beanie", cursive;
}
nav h1,
nav h2 {
margin: 0;
margin-right: 1ex;
display: inline-block;
}
nav h1 {
font-size: 400%;
}
nav h2 {
font-size: 250%;
}
article {
max-width: var(--content-width);
grid-area: content;
box-sizing: border-box;
padding: 1em 48px;
background: white;
border-bottom: 0;
border-radius: 20px;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
h3 em {
display: inline-block;
padding-left: 1em;
font-size: 80%;
}
#paypal {
margin: 1em;
display: grid;
grid-template-columns: auto auto auto auto auto;
grid-row-gap: 1em;
grid-column-gap: 1em;
justify-content: center;
justify-items: center;
}
footer {
display: grid;
grid-template-columns: auto 1fr auto;
grid-column-gap: 2em;
padding: 2em 2em 1em 2em;
background: transparent center top repeat-x url(res/footerbg.png);
font-size: x-small;
color: gray;
grid-area: footer;
}
footer p {
margin: 0.3ex 0;
}
#logo {
width: 48px;
align-self: center;
opacity: 0.7;
filter: grayscale(90%);
}
@media only screen and (max-width: 750px) {
nav {
flex-direction: column;
margin-bottom: 1em;
padding-right: 120px;
}
nav h1 {
font-size: 275%;
}
nav h2 {
font-size: 220%;
}
#paypal {
grid-template-columns: auto auto;
}
#homepage {
display: none;
}
}
</style>
</head>
<body>
<nav>
<h1>DownThemAll!</h1>
<h2>Changes</h2>
</nav>
<article>
<h3>DownThemAll needs your support!</h3>
<section id="paypal">
<a href="https://www.paypal.me/NilsMaier/10" title="Donate €10" target="_blank">
<svg viewBox="0 0 300 72" width=110>
<rect x="1.5" y="1.5" width="297" height="69" ry="34.093" fill="#ffc439" fill-rule="evenodd" stroke="#dadce0" stroke-dashoffset="89.999" stroke-linejoin="round" stroke-width="3" style="paint-order:normal" />
<g transform="translate(28.855)">
<path d="m42.414 58.373 0.83858-5.284-1.868-0.04295h-8.9197l6.1988-38.991c0.01924-0.1177 0.08177-0.22746 0.17317-0.3054 0.09139-0.07794 0.20844-0.12089 0.3303-0.12089h15.04c4.993 0 8.4387 1.0307 10.238 3.0651 0.84339 0.95437 1.3805 1.9517 1.6403 3.0492 0.27258 1.1516 0.27739 2.5275 0.01122 4.2056l-0.01924 0.12248v1.0753l0.84339 0.474c0.71031 0.37379 1.2747 0.80167 1.7076 1.2916 0.72153 0.81599 1.1881 1.8531 1.3853 3.0826 0.20363 1.2645 0.13629 2.7693-0.19722 4.4728-0.38482 1.9596-1.0069 3.6664-1.8471 5.0629-0.77284 1.2868-1.7573 2.3541-2.9262 3.1812-1.116 0.78576-2.442 1.3822-3.9412 1.764-1.4527 0.37538-3.109 0.56467-4.9257 0.56467h-1.1705c-0.83698 0-1.6499 0.29904-2.2881 0.83507-0.63976 0.54717-1.0631 1.2948-1.1929 2.1123l-0.08819 0.47559-1.4815 9.3131-0.06734 0.34198c-0.01764 0.10816-0.0481 0.16224-0.093 0.19883-0.04008 0.0334-0.09781 0.05567-0.15393 0.05567z" fill="#253b80" />
<path d="m67.719 24.195c-0.0449 0.28472-0.0962 0.5758-0.15393 0.87484-1.9834 10.102-8.769 13.592-17.435 13.592h-4.4126c-1.0598 0-1.9529 0.7635-2.1181 1.8006l-2.2592 14.214-0.63976 4.029c-0.10743 0.68078 0.4217 1.2948 1.1144 1.2948h7.8262c0.92677 0 1.714-0.66806 1.8599-1.5747l0.07696-0.39447 1.4735-9.2765 0.0946-0.509c0.14431-0.90983 0.93318-1.5779 1.8599-1.5779h1.1705c7.5825 0 13.518-3.054 15.253-11.891 0.72474-3.6918 0.34954-6.7744-1.5681-8.9424-0.58043-0.65374-1.3004-1.1961-2.1421-1.6383z" fill="#179bd7" />
<path d="m65.644 23.374c-0.30304-0.08748-0.61571-0.16702-0.93639-0.23859-0.32228-0.06999-0.65259-0.13202-0.99251-0.1861-1.1897-0.19087-2.4933-0.28154-3.8899-0.28154h-11.788c-0.29022 0-0.566 0.06522-0.81293 0.18292-0.54355 0.25927-0.94761 0.76986-1.0454 1.395l-2.5077 15.757-0.07215 0.45969c0.16515-1.0371 1.0582-1.8006 2.1181-1.8006h4.4126c8.6664 0 15.452-3.4914 17.435-13.592 0.05933-0.29904 0.10903-0.59012 0.15393-0.87484-0.50187-0.26404-1.0454-0.48991-1.6307-0.68237-0.14431-0.04772-0.29342-0.09385-0.44414-0.13838z" fill="#222d65" />
<path d="m46.179 24.246c0.09781-0.62511 0.50187-1.1357 1.0454-1.3934 0.24853-0.11771 0.52271-0.18292 0.81293-0.18292h11.788c1.3966 0 2.7001 0.09066 3.8899 0.28154 0.33992 0.05408 0.67022 0.11612 0.99251 0.1861 0.32068 0.07158 0.63334 0.15111 0.93639 0.23859 0.15072 0.04454 0.29984 0.09067 0.44575 0.13679 0.58524 0.19246 1.1288 0.41992 1.6307 0.68237 0.59005-3.7332-0.0048-6.275-2.0395-8.5766-2.2432-2.5338-6.2918-3.6186-11.472-3.6186h-15.04c-1.0582 0-1.961 0.7635-2.1245 1.8022l-6.2645 39.392c-0.12346 0.7794 0.48262 1.4825 1.2747 1.4825h9.2853l2.3314-14.673z" fill="#253b80" />
</g>
<g transform="matrix(1.004 0 0 .996 4.7854 0)" fill="#009cde" stroke="#003087" stroke-width="1px" aria-label="10">
<path d="m173.05 47.333h7.9336v-22.517l-8.1436 1.6801v-6.1135l8.0969-1.6801h8.5403v28.631h7.9336v6.2069h-24.361z" />
<path d="m225.67 36.086q0-6.5335-1.2367-9.1936-1.2134-2.6834-4.1068-2.6834t-4.1301 2.6834q-1.2367 2.6601-1.2367 9.1936 0 6.6035 1.2367 9.3103 1.2367 2.7067 4.1301 2.7067 2.8701 0 4.1068-2.7067t1.2367-9.3103zm8.9836 0.07q0 8.6569-3.7334 13.37-3.7334 4.6901-10.594 4.6901-6.8835 0-10.617-4.6901-3.7334-4.7135-3.7334-13.37 0-8.6803 3.7334-13.37 3.7334-4.7135 10.617-4.7135 6.8602 0 10.594 4.7135 3.7334 4.6901 3.7334 13.37z" />
</g>
<g transform="matrix(1.004 0 0 .996 4.7854 0)" fill="#003087" aria-label="€">
<path d="m153.83 51.627q-2.2167 1.2834-4.6435 1.9367-2.4034 0.65335-5.0168 0.65335-6.1135 0-10.314-3.0334-4.1768-3.0568-5.9268-8.7736h-5.0635l2.0534-4.5501h2.2867q-0.0233-0.32668-0.0467-0.67669 0-0.37334 0-1.0267 0-0.67669 0-1.05 0.0233-0.37334 0.0467-0.72336h-4.3401l2.0534-4.5501h3.0101q1.7967-5.7402 5.9502-8.7503 4.1768-3.0101 10.29-3.0101 2.6134 0 5.0168 0.65335 2.4267 0.65335 4.6435 1.9367v7.2102q-1.8901-1.8201-4.0368-2.7301-2.1467-0.93336-4.4568-0.93336-2.9634 0-5.0635 1.4467-2.0767 1.4234-3.1268 4.1768h12.577l-2.0067 4.5501h-11.504q-0.0467 0.37334-0.07 0.79336 0 0.42001 0 1.26 0 0.30334 0 0.67669 0.0233 0.35001 0.0467 0.74669h10.01l-2.0767 4.5501h-6.9769q1.1667 2.8468 3.1968 4.2701 2.0534 1.4234 4.9935 1.4234 2.3101 0 4.4101-0.91003 2.1234-0.93336 4.0835-2.7768z" fill="#003087" stroke-width="1px" />
</g>
</svg>
</a>
<a href="https://www.paypal.me/NilsMaier/15" title="Donate €15" target="_blank">
<svg viewBox="0 0 300 72" width="110">
<rect x="1.5" y="1.5" width="297" height="69" ry="34.093" fill="#ffc439" fill-rule="evenodd" stroke="#dadce0" stroke-dashoffset="89.999" stroke-linejoin="round" stroke-width="3" style="paint-order:normal" />
<g transform="translate(28.855)">
<path d="m42.414 58.373 0.83858-5.284-1.868-0.04295h-8.9197l6.1988-38.991c0.01924-0.1177 0.08177-0.22746 0.17317-0.3054 0.09139-0.07794 0.20844-0.12089 0.3303-0.12089h15.04c4.993 0 8.4387 1.0307 10.238 3.0651 0.84339 0.95437 1.3805 1.9517 1.6403 3.0492 0.27258 1.1516 0.27739 2.5275 0.01122 4.2056l-0.01924 0.12248v1.0753l0.84339 0.474c0.71031 0.37379 1.2747 0.80167 1.7076 1.2916 0.72153 0.81599 1.1881 1.8531 1.3853 3.0826 0.20363 1.2645 0.13629 2.7693-0.19722 4.4728-0.38482 1.9596-1.0069 3.6664-1.8471 5.0629-0.77284 1.2868-1.7573 2.3541-2.9262 3.1812-1.116 0.78576-2.442 1.3822-3.9412 1.764-1.4527 0.37538-3.109 0.56467-4.9257 0.56467h-1.1705c-0.83698 0-1.6499 0.29904-2.2881 0.83507-0.63976 0.54717-1.0631 1.2948-1.1929 2.1123l-0.08819 0.47559-1.4815 9.3131-0.06734 0.34198c-0.01764 0.10816-0.0481 0.16224-0.093 0.19883-0.04008 0.0334-0.09781 0.05567-0.15393 0.05567z" fill="#253b80" />
<path d="m67.719 24.195c-0.0449 0.28472-0.0962 0.5758-0.15393 0.87484-1.9834 10.102-8.769 13.592-17.435 13.592h-4.4126c-1.0598 0-1.9529 0.7635-2.1181 1.8006l-2.2592 14.214-0.63976 4.029c-0.10743 0.68078 0.4217 1.2948 1.1144 1.2948h7.8262c0.92677 0 1.714-0.66806 1.8599-1.5747l0.07696-0.39447 1.4735-9.2765 0.0946-0.509c0.14431-0.90983 0.93318-1.5779 1.8599-1.5779h1.1705c7.5825 0 13.518-3.054 15.253-11.891 0.72474-3.6918 0.34954-6.7744-1.5681-8.9424-0.58043-0.65374-1.3004-1.1961-2.1421-1.6383z" fill="#179bd7" />
<path d="m65.644 23.374c-0.30304-0.08748-0.61571-0.16702-0.93639-0.23859-0.32228-0.06999-0.65259-0.13202-0.99251-0.1861-1.1897-0.19087-2.4933-0.28154-3.8899-0.28154h-11.788c-0.29022 0-0.566 0.06522-0.81293 0.18292-0.54355 0.25927-0.94761 0.76986-1.0454 1.395l-2.5077 15.757-0.07215 0.45969c0.16515-1.0371 1.0582-1.8006 2.1181-1.8006h4.4126c8.6664 0 15.452-3.4914 17.435-13.592 0.05933-0.29904 0.10903-0.59012 0.15393-0.87484-0.50187-0.26404-1.0454-0.48991-1.6307-0.68237-0.14431-0.04772-0.29342-0.09385-0.44414-0.13838z" fill="#222d65" />
<path d="m46.179 24.246c0.09781-0.62511 0.50187-1.1357 1.0454-1.3934 0.24853-0.11771 0.52271-0.18292 0.81293-0.18292h11.788c1.3966 0 2.7001 0.09066 3.8899 0.28154 0.33992 0.05408 0.67022 0.11612 0.99251 0.1861 0.32068 0.07158 0.63334 0.15111 0.93639 0.23859 0.15072 0.04454 0.29984 0.09067 0.44575 0.13679 0.58524 0.19246 1.1288 0.41992 1.6307 0.68237 0.59005-3.7332-0.0048-6.275-2.0395-8.5766-2.2432-2.5338-6.2918-3.6186-11.472-3.6186h-15.04c-1.0582 0-1.961 0.7635-2.1245 1.8022l-6.2645 39.392c-0.12346 0.7794 0.48262 1.4825 1.2747 1.4825h9.2853l2.3314-14.673z" fill="#253b80" />
</g>
<g transform="matrix(1.004 0 0 .996 4.7854 0)" fill="#009cde" opacity=".75" stroke="#003087" stroke-width="1px" aria-label="15">
<path d="m173.05 47.333h7.9336v-22.517l-8.1436 1.6801v-6.1135l8.0969-1.6801h8.5403v28.631h7.9336v6.2069h-24.361z" />
<path d="m208.75 18.702h22.331v6.6035h-15.167v5.3902q1.0267-0.28001 2.0534-0.42001 1.05-0.16334 2.1701-0.16334 6.3702 0 9.917 3.1968 3.5468 3.1734 3.5468 8.8669 0 5.6468-3.8734 8.8436-3.8501 3.1968-10.71 3.1968-2.9634 0-5.8802-0.58335-2.8934-0.56002-5.7635-1.7267v-7.0702q2.8468 1.6334 5.3902 2.4501 2.5667 0.81669 4.8302 0.81669 3.2668 0 5.1335-1.5867 1.89-1.61 1.89-4.3401 0-2.7534-1.89-4.3401-1.8667-1.5867-5.1335-1.5867-1.9367 0-4.1301 0.51335-2.1934 0.49002-4.7135 1.54z" />
</g>
<g transform="matrix(1.004 0 0 .996 4.7854 0)" fill="#003087" aria-label="€">
<path d="m153.83 51.627q-2.2167 1.2834-4.6435 1.9367-2.4034 0.65335-5.0168 0.65335-6.1135 0-10.314-3.0334-4.1768-3.0568-5.9268-8.7736h-5.0635l2.0534-4.5501h2.2867q-0.0233-0.32668-0.0467-0.67669 0-0.37334 0-1.0267 0-0.67669 0-1.05 0.0233-0.37334 0.0467-0.72336h-4.3401l2.0534-4.5501h3.0101q1.7967-5.7402 5.9502-8.7503 4.1768-3.0101 10.29-3.0101 2.6134 0 5.0168 0.65335 2.4267 0.65335 4.6435 1.9367v7.2102q-1.8901-1.8201-4.0368-2.7301-2.1467-0.93336-4.4568-0.93336-2.9634 0-5.0635 1.4467-2.0767 1.4234-3.1268 4.1768h12.577l-2.0067 4.5501h-11.504q-0.0467 0.37334-0.07 0.79336 0 0.42001 0 1.26 0 0.30334 0 0.67669 0.0233 0.35001 0.0467 0.74669h10.01l-2.0767 4.5501h-6.9769q1.1667 2.8468 3.1968 4.2701 2.0534 1.4234 4.9935 1.4234 2.3101 0 4.4101-0.91003 2.1234-0.93336 4.0835-2.7768z" fill="#003087" stroke-width="1px" />
</g>
</svg>
</a>
<a href="https://www.paypal.me/NilsMaier/20" title="Donate €20" target="_blank">
<svg viewBox="0 0 300 72" width="110">
<rect x="1.5" y="1.5" width="297" height="69" ry="34.093" fill="#ffc439" fill-rule="evenodd" stroke="#dadce0" stroke-dashoffset="89.999" stroke-linejoin="round" stroke-width="3" style="paint-order:normal" />
<g transform="translate(28.855)">
<path d="m42.414 58.373 0.83858-5.284-1.868-0.04295h-8.9197l6.1988-38.991c0.01924-0.1177 0.08177-0.22746 0.17317-0.3054 0.09139-0.07794 0.20844-0.12089 0.3303-0.12089h15.04c4.993 0 8.4387 1.0307 10.238 3.0651 0.84339 0.95437 1.3805 1.9517 1.6403 3.0492 0.27258 1.1516 0.27739 2.5275 0.01122 4.2056l-0.01924 0.12248v1.0753l0.84339 0.474c0.71031 0.37379 1.2747 0.80167 1.7076 1.2916 0.72153 0.81599 1.1881 1.8531 1.3853 3.0826 0.20363 1.2645 0.13629 2.7693-0.19722 4.4728-0.38482 1.9596-1.0069 3.6664-1.8471 5.0629-0.77284 1.2868-1.7573 2.3541-2.9262 3.1812-1.116 0.78576-2.442 1.3822-3.9412 1.764-1.4527 0.37538-3.109 0.56467-4.9257 0.56467h-1.1705c-0.83698 0-1.6499 0.29904-2.2881 0.83507-0.63976 0.54717-1.0631 1.2948-1.1929 2.1123l-0.08819 0.47559-1.4815 9.3131-0.06734 0.34198c-0.01764 0.10816-0.0481 0.16224-0.093 0.19883-0.04008 0.0334-0.09781 0.05567-0.15393 0.05567z" fill="#253b80" />
<path d="m67.719 24.195c-0.0449 0.28472-0.0962 0.5758-0.15393 0.87484-1.9834 10.102-8.769 13.592-17.435 13.592h-4.4126c-1.0598 0-1.9529 0.7635-2.1181 1.8006l-2.2592 14.214-0.63976 4.029c-0.10743 0.68078 0.4217 1.2948 1.1144 1.2948h7.8262c0.92677 0 1.714-0.66806 1.8599-1.5747l0.07696-0.39447 1.4735-9.2765 0.0946-0.509c0.14431-0.90983 0.93318-1.5779 1.8599-1.5779h1.1705c7.5825 0 13.518-3.054 15.253-11.891 0.72474-3.6918 0.34954-6.7744-1.5681-8.9424-0.58043-0.65374-1.3004-1.1961-2.1421-1.6383z" fill="#179bd7" />
<path d="m65.644 23.374c-0.30304-0.08748-0.61571-0.16702-0.93639-0.23859-0.32228-0.06999-0.65259-0.13202-0.99251-0.1861-1.1897-0.19087-2.4933-0.28154-3.8899-0.28154h-11.788c-0.29022 0-0.566 0.06522-0.81293 0.18292-0.54355 0.25927-0.94761 0.76986-1.0454 1.395l-2.5077 15.757-0.07215 0.45969c0.16515-1.0371 1.0582-1.8006 2.1181-1.8006h4.4126c8.6664 0 15.452-3.4914 17.435-13.592 0.05933-0.29904 0.10903-0.59012 0.15393-0.87484-0.50187-0.26404-1.0454-0.48991-1.6307-0.68237-0.14431-0.04772-0.29342-0.09385-0.44414-0.13838z" fill="#222d65" />
<path d="m46.179 24.246c0.09781-0.62511 0.50187-1.1357 1.0454-1.3934 0.24853-0.11771 0.52271-0.18292 0.81293-0.18292h11.788c1.3966 0 2.7001 0.09066 3.8899 0.28154 0.33992 0.05408 0.67022 0.11612 0.99251 0.1861 0.32068 0.07158 0.63334 0.15111 0.93639 0.23859 0.15072 0.04454 0.29984 0.09067 0.44575 0.13679 0.58524 0.19246 1.1288 0.41992 1.6307 0.68237 0.59005-3.7332-0.0048-6.275-2.0395-8.5766-2.2432-2.5338-6.2918-3.6186-11.472-3.6186h-15.04c-1.0582 0-1.961 0.7635-2.1245 1.8022l-6.2645 39.392c-0.12346 0.7794 0.48262 1.4825 1.2747 1.4825h9.2853l2.3314-14.673z" fill="#253b80" />
</g>
<g transform="matrix(1.004 0 0 .996 4.7854 0)" fill="#009cde" stroke="#003087" stroke-width="1px" aria-label="20">
<path d="m181.22 46.936h15.33v6.6035h-25.317v-6.6035l12.717-11.224q1.7034-1.54 2.5201-3.0101 0.81669-1.47 0.81669-3.0568 0-2.4501-1.6567-3.9435-1.6334-1.4934-4.3635-1.4934-2.1001 0-4.5968 0.91003-2.4968 0.88669-5.3435 2.6601v-7.6536q3.0334-1.0034 5.9968-1.5167 2.9634-0.53668 5.8102-0.53668 6.2535 0 9.707 2.7534 3.4768 2.7534 3.4768 7.6769 0 2.8468-1.47 5.3202-1.47 2.4501-6.1835 6.5802z" />
<path d="m225.67 36.086q0-6.5335-1.2367-9.1936-1.2134-2.6834-4.1068-2.6834t-4.1301 2.6834q-1.2367 2.6601-1.2367 9.1936 0 6.6035 1.2367 9.3103 1.2367 2.7067 4.1301 2.7067 2.8701 0 4.1068-2.7067t1.2367-9.3103zm8.9836 0.07q0 8.6569-3.7334 13.37-3.7334 4.6901-10.594 4.6901-6.8835 0-10.617-4.6901-3.7334-4.7135-3.7334-13.37 0-8.6803 3.7334-13.37 3.7334-4.7135 10.617-4.7135 6.8602 0 10.594 4.7135 3.7334 4.6901 3.7334 13.37z" />
</g>
<g transform="matrix(1.004 0 0 .996 4.7854 0)" fill="#003087" aria-label="€">
<path d="m153.83 51.627q-2.2167 1.2834-4.6435 1.9367-2.4034 0.65335-5.0168 0.65335-6.1135 0-10.314-3.0334-4.1768-3.0568-5.9268-8.7736h-5.0635l2.0534-4.5501h2.2867q-0.0233-0.32668-0.0467-0.67669 0-0.37334 0-1.0267 0-0.67669 0-1.05 0.0233-0.37334 0.0467-0.72336h-4.3401l2.0534-4.5501h3.0101q1.7967-5.7402 5.9502-8.7503 4.1768-3.0101 10.29-3.0101 2.6134 0 5.0168 0.65335 2.4267 0.65335 4.6435 1.9367v7.2102q-1.8901-1.8201-4.0368-2.7301-2.1467-0.93336-4.4568-0.93336-2.9634 0-5.0635 1.4467-2.0767 1.4234-3.1268 4.1768h12.577l-2.0067 4.5501h-11.504q-0.0467 0.37334-0.07 0.79336 0 0.42001 0 1.26 0 0.30334 0 0.67669 0.0233 0.35001 0.0467 0.74669h10.01l-2.0767 4.5501h-6.9769q1.1667 2.8468 3.1968 4.2701 2.0534 1.4234 4.9935 1.4234 2.3101 0 4.4101-0.91003 2.1234-0.93336 4.0835-2.7768z" fill="#003087" stroke-width="1px" />
</g>
</svg>
</a>
<a href="https://www.paypal.me/NilsMaier/30" title="Donate €30" target="_blank">
<svg viewBox="0 0 300 72" width="110">
<rect x="1.5" y="1.5" width="297" height="69" ry="34.093" fill="#ffc439" fill-rule="evenodd" stroke="#dadce0" stroke-dashoffset="89.999" stroke-linejoin="round" stroke-width="3" style="paint-order:normal" />
<g transform="translate(28.855)">
<path d="m42.414 58.373 0.83858-5.284-1.868-0.04295h-8.9197l6.1988-38.991c0.01924-0.1177 0.08177-0.22746 0.17317-0.3054 0.09139-0.07794 0.20844-0.12089 0.3303-0.12089h15.04c4.993 0 8.4387 1.0307 10.238 3.0651 0.84339 0.95437 1.3805 1.9517 1.6403 3.0492 0.27258 1.1516 0.27739 2.5275 0.01122 4.2056l-0.01924 0.12248v1.0753l0.84339 0.474c0.71031 0.37379 1.2747 0.80167 1.7076 1.2916 0.72153 0.81599 1.1881 1.8531 1.3853 3.0826 0.20363 1.2645 0.13629 2.7693-0.19722 4.4728-0.38482 1.9596-1.0069 3.6664-1.8471 5.0629-0.77284 1.2868-1.7573 2.3541-2.9262 3.1812-1.116 0.78576-2.442 1.3822-3.9412 1.764-1.4527 0.37538-3.109 0.56467-4.9257 0.56467h-1.1705c-0.83698 0-1.6499 0.29904-2.2881 0.83507-0.63976 0.54717-1.0631 1.2948-1.1929 2.1123l-0.08819 0.47559-1.4815 9.3131-0.06734 0.34198c-0.01764 0.10816-0.0481 0.16224-0.093 0.19883-0.04008 0.0334-0.09781 0.05567-0.15393 0.05567z" fill="#253b80" />
<path d="m67.719 24.195c-0.0449 0.28472-0.0962 0.5758-0.15393 0.87484-1.9834 10.102-8.769 13.592-17.435 13.592h-4.4126c-1.0598 0-1.9529 0.7635-2.1181 1.8006l-2.2592 14.214-0.63976 4.029c-0.10743 0.68078 0.4217 1.2948 1.1144 1.2948h7.8262c0.92677 0 1.714-0.66806 1.8599-1.5747l0.07696-0.39447 1.4735-9.2765 0.0946-0.509c0.14431-0.90983 0.93318-1.5779 1.8599-1.5779h1.1705c7.5825 0 13.518-3.054 15.253-11.891 0.72474-3.6918 0.34954-6.7744-1.5681-8.9424-0.58043-0.65374-1.3004-1.1961-2.1421-1.6383z" fill="#179bd7" />
<path d="m65.644 23.374c-0.30304-0.08748-0.61571-0.16702-0.93639-0.23859-0.32228-0.06999-0.65259-0.13202-0.99251-0.1861-1.1897-0.19087-2.4933-0.28154-3.8899-0.28154h-11.788c-0.29022 0-0.566 0.06522-0.81293 0.18292-0.54355 0.25927-0.94761 0.76986-1.0454 1.395l-2.5077 15.757-0.07215 0.45969c0.16515-1.0371 1.0582-1.8006 2.1181-1.8006h4.4126c8.6664 0 15.452-3.4914 17.435-13.592 0.05933-0.29904 0.10903-0.59012 0.15393-0.87484-0.50187-0.26404-1.0454-0.48991-1.6307-0.68237-0.14431-0.04772-0.29342-0.09385-0.44414-0.13838z" fill="#222d65" />
<path d="m46.179 24.246c0.09781-0.62511 0.50187-1.1357 1.0454-1.3934 0.24853-0.11771 0.52271-0.18292 0.81293-0.18292h11.788c1.3966 0 2.7001 0.09066 3.8899 0.28154 0.33992 0.05408 0.67022 0.11612 0.99251 0.1861 0.32068 0.07158 0.63334 0.15111 0.93639 0.23859 0.15072 0.04454 0.29984 0.09067 0.44575 0.13679 0.58524 0.19246 1.1288 0.41992 1.6307 0.68237 0.59005-3.7332-0.0048-6.275-2.0395-8.5766-2.2432-2.5338-6.2918-3.6186-11.472-3.6186h-15.04c-1.0582 0-1.961 0.7635-2.1245 1.8022l-6.2645 39.392c-0.12346 0.7794 0.48262 1.4825 1.2747 1.4825h9.2853l2.3314-14.673z" fill="#253b80" />
</g>
<g transform="matrix(1.004 0 0 .996 4.7854 0)" fill="#009cde" stroke="#003087" stroke-width="1px" aria-label="30">
<path d="m189.71 34.756q3.5234 0.91003 5.3435 3.1734 1.8434 2.2401 1.8434 5.7168 0 5.1802-3.9668 7.8869-3.9668 2.6834-11.574 2.6834-2.6834 0-5.3902-0.44335-2.6834-0.42001-5.3202-1.2834v-6.9302q2.5201 1.26 4.9935 1.9134 2.4967 0.63002 4.9002 0.63002 3.5701 0 5.4602-1.2367 1.9134-1.2367 1.9134-3.5468 0-2.3801-1.9601-3.5934-1.9367-1.2367-5.7402-1.2367h-3.5934v-5.7868h3.7801q3.3834 0 5.0402-1.05 1.6567-1.0734 1.6567-3.2434 0-2.0067-1.61-3.1034t-4.5501-1.0967q-2.1701 0-4.3868 0.49002t-4.4101 1.4467v-6.5802q2.6601-0.74669 5.2735-1.12 2.6134-0.37334 5.1335-0.37334 6.7902 0 10.15 2.2401 3.3834 2.2167 3.3834 6.6969 0 3.0568-1.61 5.0168-1.61 1.9367-4.7601 2.7301z" />
<path d="m225.67 36.086q0-6.5335-1.2367-9.1936-1.2134-2.6834-4.1068-2.6834t-4.1301 2.6834q-1.2367 2.6601-1.2367 9.1936 0 6.6035 1.2367 9.3103 1.2367 2.7067 4.1301 2.7067 2.8701 0 4.1068-2.7067t1.2367-9.3103zm8.9836 0.07q0 8.6569-3.7334 13.37-3.7334 4.6901-10.594 4.6901-6.8835 0-10.617-4.6901-3.7334-4.7135-3.7334-13.37 0-8.6803 3.7334-13.37 3.7334-4.7135 10.617-4.7135 6.8602 0 10.594 4.7135 3.7334 4.6901 3.7334 13.37z" />
</g>
<g transform="matrix(1.004 0 0 .996 4.7854 0)" fill="#003087" aria-label="€">
<path d="m153.83 51.627q-2.2167 1.2834-4.6435 1.9367-2.4034 0.65335-5.0168 0.65335-6.1135 0-10.314-3.0334-4.1768-3.0568-5.9268-8.7736h-5.0635l2.0534-4.5501h2.2867q-0.0233-0.32668-0.0467-0.67669 0-0.37334 0-1.0267 0-0.67669 0-1.05 0.0233-0.37334 0.0467-0.72336h-4.3401l2.0534-4.5501h3.0101q1.7967-5.7402 5.9502-8.7503 4.1768-3.0101 10.29-3.0101 2.6134 0 5.0168 0.65335 2.4267 0.65335 4.6435 1.9367v7.2102q-1.8901-1.8201-4.0368-2.7301-2.1467-0.93336-4.4568-0.93336-2.9634 0-5.0635 1.4467-2.0767 1.4234-3.1268 4.1768h12.577l-2.0067 4.5501h-11.504q-0.0467 0.37334-0.07 0.79336 0 0.42001 0 1.26 0 0.30334 0 0.67669 0.0233 0.35001 0.0467 0.74669h10.01l-2.0767 4.5501h-6.9769q1.1667 2.8468 3.1968 4.2701 2.0534 1.4234 4.9935 1.4234 2.3101 0 4.4101-0.91003 2.1234-0.93336 4.0835-2.7768z" fill="#003087" stroke-width="1px" />
</g>
</svg>
</a>
<a id="ppanother" href="https://www.paypal.me/NilsMaier" title="Donate another amount" target="_blank">
<svg viewBox="0 0 300 72" width="110">
<rect x="1.5" y="1.5" width="297" height="69" ry="34.093" fill="#ffc439" fill-rule="evenodd" stroke="#dadce0" stroke-dashoffset="89.999" stroke-linejoin="round" stroke-width="3" style="paint-order:normal" />
<g transform="translate(19.23)">
<path d="m42.414 58.373 0.83858-5.284-1.868-0.04295h-8.9197l6.1988-38.991c0.01924-0.1177 0.08177-0.22746 0.17317-0.3054 0.09139-0.07794 0.20844-0.12089 0.3303-0.12089h15.04c4.993 0 8.4387 1.0307 10.238 3.0651 0.84339 0.95437 1.3805 1.9517 1.6403 3.0492 0.27258 1.1516 0.27739 2.5275 0.01122 4.2056l-0.01924 0.12248v1.0753l0.84339 0.474c0.71031 0.37379 1.2747 0.80167 1.7076 1.2916 0.72153 0.81599 1.1881 1.8531 1.3853 3.0826 0.20363 1.2645 0.13629 2.7693-0.19722 4.4728-0.38482 1.9596-1.0069 3.6664-1.8471 5.0629-0.77284 1.2868-1.7573 2.3541-2.9262 3.1812-1.116 0.78576-2.442 1.3822-3.9412 1.764-1.4527 0.37538-3.109 0.56467-4.9257 0.56467h-1.1705c-0.83698 0-1.6499 0.29904-2.2881 0.83507-0.63976 0.54717-1.0631 1.2948-1.1929 2.1123l-0.08819 0.47559-1.4815 9.3131-0.06734 0.34198c-0.01764 0.10816-0.0481 0.16224-0.093 0.19883-0.04008 0.0334-0.09781 0.05567-0.15393 0.05567z" fill="#253b80" />
<path d="m67.719 24.195c-0.0449 0.28472-0.0962 0.5758-0.15393 0.87484-1.9834 10.102-8.769 13.592-17.435 13.592h-4.4126c-1.0598 0-1.9529 0.7635-2.1181 1.8006l-2.2592 14.214-0.63976 4.029c-0.10743 0.68078 0.4217 1.2948 1.1144 1.2948h7.8262c0.92677 0 1.714-0.66806 1.8599-1.5747l0.07696-0.39447 1.4735-9.2765 0.0946-0.509c0.14431-0.90983 0.93318-1.5779 1.8599-1.5779h1.1705c7.5825 0 13.518-3.054 15.253-11.891 0.72474-3.6918 0.34954-6.7744-1.5681-8.9424-0.58043-0.65374-1.3004-1.1961-2.1421-1.6383z" fill="#179bd7" />
<path d="m65.644 23.374c-0.30304-0.08748-0.61571-0.16702-0.93639-0.23859-0.32228-0.06999-0.65259-0.13202-0.99251-0.1861-1.1897-0.19087-2.4933-0.28154-3.8899-0.28154h-11.788c-0.29022 0-0.566 0.06522-0.81293 0.18292-0.54355 0.25927-0.94761 0.76986-1.0454 1.395l-2.5077 15.757-0.07215 0.45969c0.16515-1.0371 1.0582-1.8006 2.1181-1.8006h4.4126c8.6664 0 15.452-3.4914 17.435-13.592 0.05933-0.29904 0.10903-0.59012 0.15393-0.87484-0.50187-0.26404-1.0454-0.48991-1.6307-0.68237-0.14431-0.04772-0.29342-0.09385-0.44414-0.13838z" fill="#222d65" />
<path d="m46.179 24.246c0.09781-0.62511 0.50187-1.1357 1.0454-1.3934 0.24853-0.11771 0.52271-0.18292 0.81293-0.18292h11.788c1.3966 0 2.7001 0.09066 3.8899 0.28154 0.33992 0.05408 0.67022 0.11612 0.99251 0.1861 0.32068 0.07158 0.63334 0.15111 0.93639 0.23859 0.15072 0.04454 0.29984 0.09067 0.44575 0.13679 0.58524 0.19246 1.1288 0.41992 1.6307 0.68237 0.59005-3.7332-0.0048-6.275-2.0395-8.5766-2.2432-2.5338-6.2918-3.6186-11.472-3.6186h-15.04c-1.0582 0-1.961 0.7635-2.1245 1.8022l-6.2645 39.392c-0.12346 0.7794 0.48262 1.4825 1.2747 1.4825h9.2853l2.3314-14.673z" fill="#253b80" />
</g>
<g transform="translate(0 -.24886)" stroke-width="1.7342px">
<g transform="matrix(.57894 0 0 .57432 95.638 27.862)" fill="#009cde" stroke="#003087" aria-label="Amount">
<path d="m62.511 47.193h-14.047l-2.2167 6.3469h-9.0303l12.904-34.838h10.71l12.904 34.838h-9.0303zm-11.807-6.4635h9.5436l-4.7601-13.86z" />
<path d="m105.19 31.746q1.5867-2.4267 3.7568-3.6868 2.1934-1.2834 4.8068-1.2834 4.5035 0 6.8602 2.7768t2.3567 8.0736v15.914h-8.4002v-13.627q0.0233-0.30334 0.0233-0.63002 0.0233-0.32668 0.0233-0.93336 0-2.7768-0.8167-4.0135-0.81669-1.26-2.6367-1.26-2.3801 0-3.6868 1.9601-1.2834 1.9601-1.33 5.6702v12.834h-8.4002v-13.627q0-4.3401-0.74669-5.5768-0.74669-1.26-2.6601-1.26-2.4034 0-3.7101 1.9834-1.3067 1.9601-1.3067 5.6235v12.857h-8.4003v-26.134h8.4003v3.8268q1.54-2.2167 3.5234-3.3368 2.0067-1.12 4.4101-1.12 2.7067 0 4.7835 1.3067 2.0767 1.3067 3.1501 3.6634z" />
<path d="m146.26 32.749q-2.7768 0-4.2468 2.0067-1.4467 1.9834-1.4467 5.7402t1.4467 5.7635q1.47 1.9834 4.2468 1.9834 2.7301 0 4.1768-1.9834 1.4467-2.0067 1.4467-5.7635t-1.4467-5.7402q-1.4467-2.0067-4.1768-2.0067zm0-5.9735q6.7435 0 10.524 3.6401 3.8034 3.6401 3.8034 10.08 0 6.4402-3.8034 10.08-3.7801 3.6401-10.524 3.6401-6.7669 0-10.594-3.6401-3.8034-3.6401-3.8034-10.08 0-6.4402 3.8034-10.08 3.8268-3.6401 10.594-3.6401z" />
<path d="m169.41 43.366v-15.96h8.4002v2.6134q0 2.1234-0.0233 5.3435-0.0233 3.1968-0.0233 4.2701 0 3.1501 0.16334 4.5501 0.16334 1.3767 0.56002 2.0067 0.51335 0.81669 1.33 1.26 0.84002 0.44335 1.9134 0.44335 2.6134 0 4.1068-2.0067t1.4934-5.5768v-12.904h8.3536v26.134h-8.3536v-3.7801q-1.8901 2.2867-4.0134 3.3834-2.1001 1.0734-4.6435 1.0734-4.5268 0-6.9069-2.7768-2.3567-2.7768-2.3567-8.0736z" />
<path d="m233.04 37.626v15.914h-8.4003v-12.18q0-3.3834-0.16333-4.6668-0.14001-1.2834-0.51335-1.8901-0.49002-0.81669-1.33-1.26-0.84003-0.46668-1.9134-0.46668-2.6134 0-4.1068 2.0301-1.4934 2.0067-1.4934 5.5768v12.857h-8.3536v-26.134h8.3536v3.8268q1.8901-2.2867 4.0135-3.3601 2.1234-1.0967 4.6901-1.0967 4.5268 0 6.8602 2.7768 2.3567 2.7768 2.3567 8.0736z" />
<path d="m252.97 19.986v7.4202h8.6103v5.9735h-8.6103v11.084q0 1.8201 0.72335 2.4734 0.72336 0.63002 2.8701 0.63002h4.2935v5.9735h-7.1636q-4.9468 0-7.0236-2.0534-2.0534-2.0767-2.0534-7.0235v-11.084h-4.1535v-5.9735h4.1535v-7.4202z" />
</g>
<g transform="matrix(.57894 0 0 .57432 95.638 23.862)" fill="#003087" aria-label="Another">
<path d="m57.459 11.049h-14.047l-2.2167 6.3469h-9.0303l12.904-34.838h10.71l12.904 34.838h-9.0303zm-11.807-6.4635h9.5436l-4.7601-13.86z" />
<path d="m102.19 1.4817v15.914h-8.4003v-12.18q0-3.3834-0.16334-4.6668-0.14-1.2834-0.51335-1.8901-0.49002-0.81669-1.33-1.26-0.84002-0.46668-1.9134-0.46668-2.6134 0-4.1068 2.0301-1.4934 2.0067-1.4934 5.5768v12.857h-8.3536v-26.134h8.3536v3.8268q1.8901-2.2867 4.0135-3.3601 2.1234-1.0967 4.6901-1.0967 4.5268 0 6.8602 2.7768 2.3567 2.7768 2.3567 8.0736z" />
<path d="m125.43-3.3951q-2.7768 0-4.2468 2.0067-1.4467 1.9834-1.4467 5.7402t1.4467 5.7635q1.47 1.9834 4.2468 1.9834 2.7301 0 4.1768-1.9834 1.4467-2.0067 1.4467-5.7635t-1.4467-5.7402q-1.4467-2.0067-4.1768-2.0067zm0-5.9735q6.7435 0 10.524 3.6401 3.8034 3.6401 3.8034 10.08 0 6.4402-3.8034 10.08-3.7801 3.6401-10.524 3.6401-6.7669 0-10.594-3.6401-3.8034-3.6401-3.8034-10.08 0-6.4402 3.8034-10.08 3.8268-3.6401 10.594-3.6401z" />
<path d="m157.99-16.159v7.4202h8.6103v5.9735h-8.6103v11.084q0 1.8201 0.72336 2.4734 0.72336 0.63002 2.8701 0.63002h4.2935v5.9735h-7.1636q-4.9468 0-7.0236-2.0534-2.0534-2.0767-2.0534-7.0235v-11.084h-4.1535v-5.9735h4.1535v-7.4202z" />
<path d="m201.02 1.4817v15.914h-8.4002v-12.134q0-3.4301-0.16334-4.7135-0.14001-1.2834-0.51335-1.8901-0.49002-0.81669-1.33-1.26-0.84003-0.46668-1.9134-0.46668-2.6134 0-4.1068 2.0301-1.4934 2.0067-1.4934 5.5768v12.857h-8.3536v-36.308h8.3536v14q1.89-2.2867 4.0134-3.3601 2.1234-1.0967 4.6901-1.0967 4.5268 0 6.8602 2.7768 2.3567 2.7768 2.3567 8.0736z" />
<path d="m237.91 4.2585v2.3801h-19.531q0.30334 2.9401 2.1234 4.4101 1.8201 1.47 5.0868 1.47 2.6367 0 5.3902-0.77002 2.7768-0.79336 5.6935-2.3801v6.4402q-2.9634 1.12-5.9268 1.6801-2.9634 0.58335-5.9268 0.58335-7.0936 0-11.037-3.5934-3.9201-3.6168-3.9201-10.127 0-6.3935 3.8501-10.057 3.8734-3.6634 10.64-3.6634 6.1602 0 9.847 3.7101 3.7101 3.7101 3.7101 9.917zm-8.5869-2.7768q0-2.3801-1.4-3.8268-1.3767-1.47-3.6168-1.47-2.4267 0-3.9434 1.3767-1.5167 1.3534-1.8901 3.9201z" />
<path d="m266.64-1.6217q-1.0967-0.51335-2.1934-0.74669-1.0734-0.25667-2.1701-0.25667-3.2201 0-4.9702 2.0767-1.7267 2.0534-1.7267 5.9035v12.04h-8.3536v-26.134h8.3536v4.2935q1.61-2.5667 3.6868-3.7334 2.1001-1.19 5.0168-1.19 0.42001 0 0.91002 0.046668 0.49002 0.023334 1.4234 0.14z" />
</g>
</g>
</svg>
</a>
</section>
<p>It requires <strong>a lot of time and some money</strong> to create the extension, keep up with browser
changes, read and answer emails, bug reports and feature requests, and actually publish the final versions.
<em>Any contribution is appreciated. Thank you!</em></p>
<p>If you're still new to DownThemAll!, have a look at our <a href="https://about.downthemall.org/4.0/">Welcome page</a> with some introductory videos.</p>
<h2>Major version changes</h2>
<h3>Version 4.2 <em>October 9, 2019</em></h3>
<ul>
<li>Vastly improved name handling in Chrome. (<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1245652">Missing in Firefox</a>)</li>
<li>Support <code>[a:z]</code> character batches</li>
<li>Dark theme support</li>
<li>Improved the gathering of images in websites</li>
<li>The windows, in particular the Manager window, will now usually remember the size and position correctly.</li>
<li>Temporarily removed sounds on Opera. See <a href="https://github.com/downthemall/downthemall/issues/125">#125</a></li>
<li>Fixed some issues with the Import functionality</li>
</ul>
<h3>Version 4.1 <em>September 21, 2019</em></h3>
<ul>
<li>Subfolder dropdown. While it was previously possible to use masks for subfolders already, based on user
feedback having a dedicated subfolder selection dropdown is more convenient and easier to discover.</li>
<li>You can configure the browser button to more different actions now</li>
<li>Play sounds: When the queue finishes, play a sound (can be enabled/disabled in the preferences)</li>
<li>Delete files from within the manager</li>
<li>Manager can now configured to be opened in a popup window instead of a tab</li>
<li>Automatic retries (This feature relies on Firefox reporting errors correctly to extensions, which it
only started doing in Firefox 71, which is currently available as Nightly).</li>
</ul>
<h3>Version 4.0 <em>August 31, 2019</em></h3>
<p>DownThemAll! reborn, as a WebExtension</p>
</article>
<footer>
<svg id="logo" viewBox="0 0 16 16">
<defs>
<linearGradient id="b">
<stop stop-color="#116597" offset="0" />
<stop stop-color="#062638" offset="1" />
</linearGradient>
<linearGradient id="a">
<stop stop-color="#fffe99" offset="0" />
<stop stop-color="#e49218" offset=".2" />
<stop stop-color="#116597" offset="1" />
</linearGradient>
<radialGradient id="c" xlink:href="#a" gradientUnits="userSpaceOnUse" cy="17.413" cx="11.75" gradientTransform="matrix(.41233 0 0 1.1548 3.24 -8.74)" r="10.752" />
<linearGradient id="h" y2="-.242" xlink:href="#a" gradientUnits="userSpaceOnUse" x2="7.763" gradientTransform="translate(2.495 -6.342) scale(.6787)" y1="4.218" x1="8.101" />
<linearGradient id="i" y2="-.242" xlink:href="#a" gradientUnits="userSpaceOnUse" x2="7.763" gradientTransform="translate(2.495 -1.882) scale(.6787)" y1="4.218" x1="8.101" />
<linearGradient id="g" y2="-.242" xlink:href="#b" gradientUnits="userSpaceOnUse" x2="7.763" gradientTransform="translate(7.08 4.18) scale(.43866)" y1="4.218" x1="8.101" />
<linearGradient id="f" y2="-.242" xlink:href="#b" gradientUnits="userSpaceOnUse" x2="7.763" gradientTransform="translate(7.657 1.298) scale(.43866)" y1="4.218" x1="8.101" />
<linearGradient id="e" y2="-.242" xlink:href="#b" gradientUnits="userSpaceOnUse" x2="7.763" gradientTransform="translate(1.851 4.18) scale(.43866)" y1="4.218" x1="8.101" />
<linearGradient id="d" y2="-.242" xlink:href="#b" gradientUnits="userSpaceOnUse" x2="7.763" gradientTransform="translate(1.851 1.298) scale(.43866)" y1="4.218" x1="8.101" />
</defs>
<g stroke="#072739">
<g stroke-width=".646">
<path d="M4.561 7.134v1.515H1.996v.262l2.949 3.333 2.666 3.05h.99l2.686-3.05 2.848-3.252V8.65h-2.727V7.134H4.561z" fill="url(#c)" />
<g stroke-linecap="round" stroke-dashoffset="10" fill-rule="evenodd">
<path fill="url(#d)" d="M4.562 1.346h1.649v1.649H4.562z" />
<path fill="url(#e)" d="M4.562 4.228h1.649v1.649H4.562z" />
<path fill="url(#f)" d="M10.368 1.346h1.649v1.649h-1.649z" />
<path fill="url(#g)" d="M9.792 4.228h1.649v1.649H9.792z" />
</g>
</g>
<g fill-rule="evenodd" stroke-linecap="round" stroke-dashoffset="10">
<path fill="url(#h)" d="M6.689-6.268H9.24v2.551H6.689z" transform="translate(2.874 4.614) scale(.64633)" />
<path fill="url(#i)" d="M6.689-1.808H9.24V.743H6.689z" transform="translate(2.874 4.614) scale(.64633)" />
</g>
</g>
</svg>
<section>
<p>Copyright © 2007-2018 Nils Maier, Stefano Verna, Federico Parodi</p>
<p>Copyright © 2007-2019 Nils Maier</p>
<p>The information on this website is licensed under the
<a href="https://creativecommons.org/licenses/by-sa/4.0/">
Creative Commons Attribution-ShareAlike 4.0 International License</a>.</p>
</section>
<a id="homepage" href="https://downthemall.org/">
<svg viewBox="0 0 250 32" height="20" xmlns="http://www.w3.org/2000/svg">
<g transform="matrix(1.1174 0 0 1.122 -217.76 -441.22)">
<path d="m277.86 402.4c-2.106 0.594-3.9921 1.3387-5.0625 3.0371-1.8782 2.9802-1.8825 0.50072-5.0625 1.0117-0.075 4.312-1.6927 7.0814-1.0117 12.148 0.251 1.099-0.2614 1.8228 2.0234 2.0254 5.078-2.0169 2.6252-12.605 9.1113-13.162 0.661 5.076 1.325 12.532 3.0371 14.174h2.0254c2.0004 0 2.4284-0.24992 2.0254-4.0449-0.157-1.478-1.5594-2.1928-2.0234-4.0508-0.436-1.744-0.20767-2.7525-1.0137-5.0625 0.20397-2.5435-3.0757-5.9543-4.0488-6.0762z" />
<path d="m205.98 396.32c0.71583-0.71583 3.037 0 3.037 0 3.312 2.743 2.107 7.979 3.037 12.148 0.97 4.354 2.863 8.229 3.037 12.149-3.865 0.827-3.919-2.155-5.062-4.05-3.517 0.195-3.843 3.58-7.086 4.05 0 0-3.0927 1.1003-6.074 0-2.2496-1.309-2.6451-6.2394-0.9158-9.8255 1.7293-3.5861 5.5833-5.828 10.027-5.3615 0 0-2.1472-6.9628 0-9.11zm-7.087 21.261c5.626-0.111 9.345-2.129 9.111-8.1-5.62-4-11.843 3.748-9.111 8.1z" />
<path d="m262.67 400.37c3.124 1.378 4.2238 9.6188 3.037 14.174-0.21875 0.83965-3.6 4.9793-4.049 5.062-5.6104 1.0329-9.589-0.535-13.161-2.024-3.76 0.627-4.631 4.142-10.124 3.037-2.976-2.578-3.758-15.21 2.025-15.187 0.646 5.261-2.233 8.114 0 12.149 7.523 0.437 4.919-9.254 9.111-12.149 4.209 1.404 0.0379 4.9881 2.024 8.1 0.7405 1.1602 0.55971 3.037 2.025 3.037h5.062c2.561-0.813 3.5092-3.7334 4.049-6.074 1.0218-4.4307-3.744-7.344 1e-3 -10.125z" />
<path d="m229.26 404.42c4.2274 1.6428 6.429 7.195 4.049 13.161-6.917 2.7019-16.888 6.2299-17.211-1.012-0.35916-8.0617 4.062-15.685 13.162-12.149zm-9.111 11.136c2.075 3.041 7.753 2.154 10.124 0 2.323-10.366-12.448-10.366-10.124 0z" />
<path d="m415.54 393.28c1.635-0.285 1.742 0.957 3.037 1.012 0.117 7.88 0.244 15.768-6.074 17.211 0.518-6.569 1.518-12.656 3.037-18.223z" />
<path d="m397.32 396.32c0.901 0.449 1.811 0.89 2.024 2.025 1.436 2.366 1.224 7.424 1.013 12.148-0.182 4.063 1.111 10.063-3.037 10.124-1.656-5.939-1.656-18.356 0-24.297z" />
<path d="m405.42 396.32c0.901 0.449 1.811 0.89 2.024 2.025 1.436 2.366 1.225 7.424 1.013 12.148-0.182 4.063 1.112 10.063-3.037 10.124-1.656-5.939-1.656-18.356 0-24.297z" />
<path d="m386.18 405.43c1.879 2.172 2.706 5.394 3.037 9.112 0.405 2.632 3.021 3.053 3.037 6.074-3.694 0.657-5.392-0.683-7.086-2.025-1.896 2.882-11.656 3.4133-12.148 0-1.2181-8.4422 3.734-13.813 13.16-13.161zm-10.123 11.136c5.229 3.119 8.32-1.521 8.123-7.087-3.941-4.338-8.175 1.277-8.123 7.087z" />
<path d="m412.5 414.54c2.928 0.446 4.614 2.134 5.062 5.062-3.131 3.21-8.628-1.578-5.062-5.062z" />
<g fill="#069">
<path d="m344.67 399.36c-3.462 3.288-12.431 1.068-14.174 6.074-0.212 4.938 5.378 4.072 10.124 4.05-0.763 3.287-5.684 2.415-8.099 4.05 0.194 6.297 7.9627 1.1977 12.148 3.037 2.1858 0.96059-2.6665 2.6983-4.05 3.037-0.92 0.229-7.2519 3.9961-10.124 1.013-4.022-4.1774-6.0966-12.401-2.0268-19.74 2.1561-3.8884 7.9908-2.3919 12.151-3.5449 2.1724-1.0195 4.0825-0.57137 4.051 2.024z" />
<path d="m368.97 398.35c0.91935 1.2579 1.638 4.258 2.024 7.086 0.632 4.615 1.344 11.963-3.037 12.149 0.605-6.006-1.776-9.022-1.012-15.187-2.943 2.12-2.8572 7.4034-6.074 9.112-5.4038 2.8702-7.236-2.214-10.124-4.05-0.162 4.899 0.612 10.735-4.05 11.136-0.788-6.862 1.383-10.766 1.013-17.21 6.881-1.144 5.642 5.832 10.124 7.086 2.854-2.881 4.6308-6.3006 7.086-10.123 0.7296-1.1359 3.2534-1.0889 4.05 1e-3z" />
<path d="m299.12 404.42c2.5659-0.14763 2.6804 4.5418 3.037 7.087 0.319 2.835 0.61 6.509-1.012 8.099-3.139 1.088-1.619-3.049-2.025-5.062-0.701-3.477-2.194-6.897 0-10.124z" />
<path d="m324 395.29c-4.1284 0.12154 0.92333 9.4224-3.6191 9.1289-3.094-0.731-3.6892 1.0347-6.0742 1.0117-5.024-0.414 3.2846-5.0625 3.2846-5.0625-1.3331-0.17112-4.8554 0.83219-4.9679-2.0635-1.1226-0.18087-1.4286 0.17857-3.0288 0.0563-0.30668 3.1413-2.5989 3.3131-5.6576 3.0448-6.3424-0.5564-15.93 1.6227-20.001 5.0366-0.88745 0.20112-1.9712 0.15704-2.4673-0.0332l0.44194 2.0606c8.225-2.236 14.819-5.3086 26.322-5.0625 0.802 5.947-2.2449 15.743 3.0371 17.211 4.327-0.057 0.29512-5.5363 2.0234-9.0879 1.899-3.9024 2.4597-3.319 5.0625-4.0723 5.9836-1.7317 0.3075 9.815 5.0625 10.123 3.109 0.858 1.9194-3.3815 2.0234-5.0625 0.3-4.805 0.0473-13.108-1.0117-17.211-0.15291-0.0158-0.29651-0.0215-0.42969-0.0176z" />
</g>
</g>
</svg>
</a>
</footer>
</body>
</html>

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

@ -0,0 +1,55 @@
<svg version="1.1" viewBox="0 0 200 180" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<radialGradient id="d" cx="161.46" cy="-144.02" r="160.02" gradientTransform="matrix(1 0 0 .99838 0 -.23281)" gradientUnits="userSpaceOnUse">
<stop stop-color="#febb00" offset="0"/>
<stop stop-color="#ffd571" stop-opacity=".49804" offset=".64286"/>
<stop stop-color="#ffe5a7" stop-opacity="0" offset=".95153"/>
<stop stop-color="#ffe5a7" stop-opacity="0" offset="1"/>
</radialGradient>
<filter id="e" color-interpolation-filters="sRGB">
<feGaussianBlur stdDeviation="0.32807532"/>
</filter>
<radialGradient id="c" cx="161.46" cy="-144.02" r="160.02" gradientTransform="matrix(1 0 0 .99838 0 -.23281)" gradientUnits="userSpaceOnUse">
<stop stop-color="#ffd14e" offset="0"/>
<stop stop-color="#ffeeb5" stop-opacity=".49804" offset=".71429"/>
<stop stop-color="#ffeeb5" stop-opacity=".49804" offset="1"/>
</radialGradient>
<radialGradient id="b" cx="12.389" cy="11.882" r="8.199" gradientUnits="userSpaceOnUse">
<stop stop-color="#e69412" offset="0"/>
<stop stop-color="#f4c478" stop-opacity="0" offset="1"/>
</radialGradient>
<radialGradient id="a" cx="11.75" cy="17.413" r="10.752" gradientTransform="matrix(3.3776 0 0 9.4595 121.98 -293.39)" gradientUnits="userSpaceOnUse">
<stop stop-color="#fffe99" offset="0"/>
<stop stop-color="#f69706" offset=".2"/>
<stop stop-color="#136fa7" offset="1"/>
</radialGradient>
</defs>
<g transform="translate(-61.457 224.02)">
<g transform="matrix(.62494 0 0 .62494 60.557 -51.015)" fill="url(#d)" fill-rule="evenodd">
<path d="m161.46-144.02 72.75 144.62-46.61 15.146z"/>
<path d="m161.46-144.02 143.86 74.228-28.81 39.653z"/>
<path d="m161.46-144.02 160.02-24.507v49.014z"/>
<path d="m161.46-144.02 115.05-113.88 28.81 39.653z"/>
<path d="m161.46-144.02 26.14-159.76 46.615 15.146z"/>
<path d="m161.46-144.02-72.755-144.61 46.615-15.146z"/>
<path d="m161.46-144.02-143.86-74.228 28.81-39.653z"/>
<path d="m161.46-144.02-160.02 24.507-2.7e-6 -49.014z"/>
<path d="m161.46-144.02-115.05 113.89-28.81-39.653z"/>
<path d="m161.46-144.02-26.14 159.76-46.618-15.146z"/>
</g>
<g transform="matrix(.59435 -.19312 .19312 .59435 93.307 -24.24)" fill="url(#c)" fill-rule="evenodd" opacity=".88">
<path d="m161.46-144.02 72.75 144.62-46.61 15.146z"/>
<path d="m161.46-144.02 143.86 74.228-28.81 39.653z"/>
<path d="m161.46-144.02 160.02-24.507v49.014z"/>
<path d="m161.46-144.02 115.05-113.88 28.81 39.653z"/>
<path d="m161.46-144.02 26.14-159.76 46.615 15.146z"/>
<path d="m161.46-144.02-72.755-144.61 46.615-15.146z"/>
<path d="m161.46-144.02-143.86-74.228 28.81-39.653z"/>
<path d="m161.46-144.02-160.02 24.507-2.7e-6 -49.014z"/>
<path d="m161.46-144.02-115.05 113.89-28.81-39.653z"/>
<path d="m161.46-144.02-26.14 159.76-46.618-15.146z"/>
</g>
<path transform="matrix(7.0729 0 0 7.4575 73.647 -229.61)" d="m20.588 11.882a8.199 8.199 0 1 1-16.398 0 8.199 8.199 0 1 1 16.398 0z" fill="url(#b)" filter="url(#e)"/>
<path d="m133.31-207.91v55.137h-17.218c-6.602-0.97334-3.1317 2.1508-3.1317 2.1508l23.494 26.472 18.653 21.422c1.9951 2.9976 3.1147 2.8985 6.486 2.8985 3.5137 0.43957 4.2275-0.28033 6.4176-2.757l19.07-21.564 22.666-25.81c3.6888-3.9672-2.8847-2.8126-2.8847-2.8126h-18.954v-54.904c0.65539-9.337-1.0536-9.0538-8.6714-8.7929h-37.608c-7.6308-0.26075-8.3181 0.1211-8.3181 8.5607z" fill="url(#a)" stroke="#0a3b56" stroke-width="5.1532"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.6 KiB

BIN
docs/landing/batches.jpg Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

BIN
docs/landing/batches.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

BIN
docs/landing/batches.webm Executable file

Binary file not shown.

BIN
docs/landing/first.jpg Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

BIN
docs/landing/first.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

BIN
docs/landing/first.webm Executable file

Binary file not shown.

501
docs/landing/index.html Executable file
View File

@ -0,0 +1,501 @@
<!doctype html>
<html lang="en">
<!-- License: Creative Commons Attribution-ShareAlike 4.0 International License -->
<head>
<meta charset="utf-8">
<title>Welcome to DownThemAll!</title>
<style crossorigin="anonymous">
@font-face {
font-family: "Reenie Beanie";
font-style: normal;
font-weight: 400;
font-display: block;
src: local("Reenie Beanie"), local("ReenieBeanie"),
url(res/ReenieBeanie-Regular.woff2) format("woff2");
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
U+FEFF, U+FFFD;
}
:root {
--content-width: 1000px;
}
html,
body {
margin: 0;
padding: 0;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Ubuntu",
"Helvetica Neue", sans-serif;
font-size: 12pt;
color: rgb(20, 20, 20);
background: white;
width: 100%;
height: 100%;
}
body {
display: grid;
background: white repeat-x url(res/background-tile.png);
grid-template-columns: 1fr [content] auto 1fr;
grid-template-rows: auto 1fr auto;
grid-template-areas:
". header ."
". content ."
"footer footer footer";
}
a {
color: rgb(30, 30, 70);
}
li {
list-style-type: circle;
}
p {
margin: 0;
margin-bottom: 12px;
}
nav {
max-width: var(--content-width);
grid-area: header;
display: flex;
box-sizing: border-box;
padding-right: 120px;
padding-top: 1em;
padding-left: 48px;
align-content: center;
align-items: baseline;
background: no-repeat top right url(res/halo.svg);
background-size: 120px;
min-height: 100px;
text-shadow: rgba(255, 255, 255, 0.8) 1px 3px 0px;
font-family: "Reenie Beanie", cursive;
}
nav h1,
nav h2 {
margin: 0;
margin-right: 1ex;
display: inline-block;
}
nav h1 {
font-size: 400%;
}
nav h2 {
font-size: 250%;
}
article {
max-width: var(--content-width);
grid-area: content;
box-sizing: border-box;
padding: 1em 48px;
background: white;
border-bottom: 0;
border-radius: 20px;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
h3 em {
display: inline-block;
padding-left: 1em;
font-size: 80%;
}
#paypal {
margin: 1em;
display: grid;
grid-template-columns: auto auto auto auto auto;
grid-row-gap: 1em;
grid-column-gap: 1em;
justify-content: center;
justify-items: center;
}
footer {
display: grid;
grid-template-columns: auto 1fr auto;
grid-column-gap: 2em;
padding: 2em 2em 1em 2em;
background: transparent center top repeat-x url(res/footerbg.png);
font-size: x-small;
color: gray;
grid-area: footer;
}
footer p {
margin: 0.3ex 0;
}
#logo {
width: 48px;
align-self: center;
opacity: 0.7;
filter: grayscale(90%);
}
figure {
margin: 16px 0;
padding: 0;
display: grid;
width: 100%;
justify-content: center;
align-content: center;
grid-template-columns: [content] 1fr;
text-align: center;
cursor: pointer;
}
video {
grid-area: content;
margin: 0 auto;
width: 720px;
max-width: 90%;
}
.play {
grid-area: content;
z-index: 100;
min-height: 64px;
min-width: 64px;
background-repeat: no-repeat;
background-position: center;
background-size: 20%;
background-image: url(res/go.svg);
opacity: 0.4;
transition: opacity 700ms;
}
.play:hover {
opacity: 0.95;
}
#privacy {
display: grid;
grid-template-columns: auto 1fr;
grid-column-gap: 1em;
align-items: center;
margin: 0;
}
#privacy svg {
opacity: 0.6;
fill: green;
}
@media only screen and (max-width: 750px) {
nav {
flex-direction: column;
margin-bottom: 1em;
padding-right: 120px;
}
nav h1 {
font-size: 275%;
}
nav h2 {
font-size: 220%;
}
#paypal {
grid-template-columns: auto auto;
}
#homepage {
display: none;
}
}
</style>
</head>
<body>
<nav>
<h2>Welcome to</h2>
<h1>DownThemAll!</h1>
</nav>
<article>
<h3>DownThemAll needs your support!</h3>
<section id="paypal">
<a href="https://www.paypal.me/NilsMaier/10" title="Donate €10" target="_blank">
<svg viewBox="0 0 300 72" width=110>
<rect x="1.5" y="1.5" width="297" height="69" ry="34.093" fill="#ffc439" fill-rule="evenodd" stroke="#dadce0" stroke-dashoffset="89.999" stroke-linejoin="round" stroke-width="3" style="paint-order:normal" />
<g transform="translate(28.855)">
<path d="m42.414 58.373 0.83858-5.284-1.868-0.04295h-8.9197l6.1988-38.991c0.01924-0.1177 0.08177-0.22746 0.17317-0.3054 0.09139-0.07794 0.20844-0.12089 0.3303-0.12089h15.04c4.993 0 8.4387 1.0307 10.238 3.0651 0.84339 0.95437 1.3805 1.9517 1.6403 3.0492 0.27258 1.1516 0.27739 2.5275 0.01122 4.2056l-0.01924 0.12248v1.0753l0.84339 0.474c0.71031 0.37379 1.2747 0.80167 1.7076 1.2916 0.72153 0.81599 1.1881 1.8531 1.3853 3.0826 0.20363 1.2645 0.13629 2.7693-0.19722 4.4728-0.38482 1.9596-1.0069 3.6664-1.8471 5.0629-0.77284 1.2868-1.7573 2.3541-2.9262 3.1812-1.116 0.78576-2.442 1.3822-3.9412 1.764-1.4527 0.37538-3.109 0.56467-4.9257 0.56467h-1.1705c-0.83698 0-1.6499 0.29904-2.2881 0.83507-0.63976 0.54717-1.0631 1.2948-1.1929 2.1123l-0.08819 0.47559-1.4815 9.3131-0.06734 0.34198c-0.01764 0.10816-0.0481 0.16224-0.093 0.19883-0.04008 0.0334-0.09781 0.05567-0.15393 0.05567z" fill="#253b80" />
<path d="m67.719 24.195c-0.0449 0.28472-0.0962 0.5758-0.15393 0.87484-1.9834 10.102-8.769 13.592-17.435 13.592h-4.4126c-1.0598 0-1.9529 0.7635-2.1181 1.8006l-2.2592 14.214-0.63976 4.029c-0.10743 0.68078 0.4217 1.2948 1.1144 1.2948h7.8262c0.92677 0 1.714-0.66806 1.8599-1.5747l0.07696-0.39447 1.4735-9.2765 0.0946-0.509c0.14431-0.90983 0.93318-1.5779 1.8599-1.5779h1.1705c7.5825 0 13.518-3.054 15.253-11.891 0.72474-3.6918 0.34954-6.7744-1.5681-8.9424-0.58043-0.65374-1.3004-1.1961-2.1421-1.6383z" fill="#179bd7" />
<path d="m65.644 23.374c-0.30304-0.08748-0.61571-0.16702-0.93639-0.23859-0.32228-0.06999-0.65259-0.13202-0.99251-0.1861-1.1897-0.19087-2.4933-0.28154-3.8899-0.28154h-11.788c-0.29022 0-0.566 0.06522-0.81293 0.18292-0.54355 0.25927-0.94761 0.76986-1.0454 1.395l-2.5077 15.757-0.07215 0.45969c0.16515-1.0371 1.0582-1.8006 2.1181-1.8006h4.4126c8.6664 0 15.452-3.4914 17.435-13.592 0.05933-0.29904 0.10903-0.59012 0.15393-0.87484-0.50187-0.26404-1.0454-0.48991-1.6307-0.68237-0.14431-0.04772-0.29342-0.09385-0.44414-0.13838z" fill="#222d65" />
<path d="m46.179 24.246c0.09781-0.62511 0.50187-1.1357 1.0454-1.3934 0.24853-0.11771 0.52271-0.18292 0.81293-0.18292h11.788c1.3966 0 2.7001 0.09066 3.8899 0.28154 0.33992 0.05408 0.67022 0.11612 0.99251 0.1861 0.32068 0.07158 0.63334 0.15111 0.93639 0.23859 0.15072 0.04454 0.29984 0.09067 0.44575 0.13679 0.58524 0.19246 1.1288 0.41992 1.6307 0.68237 0.59005-3.7332-0.0048-6.275-2.0395-8.5766-2.2432-2.5338-6.2918-3.6186-11.472-3.6186h-15.04c-1.0582 0-1.961 0.7635-2.1245 1.8022l-6.2645 39.392c-0.12346 0.7794 0.48262 1.4825 1.2747 1.4825h9.2853l2.3314-14.673z" fill="#253b80" />
</g>
<g transform="matrix(1.004 0 0 .996 4.7854 0)" fill="#009cde" stroke="#003087" stroke-width="1px" aria-label="10">
<path d="m173.05 47.333h7.9336v-22.517l-8.1436 1.6801v-6.1135l8.0969-1.6801h8.5403v28.631h7.9336v6.2069h-24.361z" />
<path d="m225.67 36.086q0-6.5335-1.2367-9.1936-1.2134-2.6834-4.1068-2.6834t-4.1301 2.6834q-1.2367 2.6601-1.2367 9.1936 0 6.6035 1.2367 9.3103 1.2367 2.7067 4.1301 2.7067 2.8701 0 4.1068-2.7067t1.2367-9.3103zm8.9836 0.07q0 8.6569-3.7334 13.37-3.7334 4.6901-10.594 4.6901-6.8835 0-10.617-4.6901-3.7334-4.7135-3.7334-13.37 0-8.6803 3.7334-13.37 3.7334-4.7135 10.617-4.7135 6.8602 0 10.594 4.7135 3.7334 4.6901 3.7334 13.37z" />
</g>
<g transform="matrix(1.004 0 0 .996 4.7854 0)" fill="#003087" aria-label="€">
<path d="m153.83 51.627q-2.2167 1.2834-4.6435 1.9367-2.4034 0.65335-5.0168 0.65335-6.1135 0-10.314-3.0334-4.1768-3.0568-5.9268-8.7736h-5.0635l2.0534-4.5501h2.2867q-0.0233-0.32668-0.0467-0.67669 0-0.37334 0-1.0267 0-0.67669 0-1.05 0.0233-0.37334 0.0467-0.72336h-4.3401l2.0534-4.5501h3.0101q1.7967-5.7402 5.9502-8.7503 4.1768-3.0101 10.29-3.0101 2.6134 0 5.0168 0.65335 2.4267 0.65335 4.6435 1.9367v7.2102q-1.8901-1.8201-4.0368-2.7301-2.1467-0.93336-4.4568-0.93336-2.9634 0-5.0635 1.4467-2.0767 1.4234-3.1268 4.1768h12.577l-2.0067 4.5501h-11.504q-0.0467 0.37334-0.07 0.79336 0 0.42001 0 1.26 0 0.30334 0 0.67669 0.0233 0.35001 0.0467 0.74669h10.01l-2.0767 4.5501h-6.9769q1.1667 2.8468 3.1968 4.2701 2.0534 1.4234 4.9935 1.4234 2.3101 0 4.4101-0.91003 2.1234-0.93336 4.0835-2.7768z" fill="#003087" stroke-width="1px" />
</g>
</svg>
</a>
<a href="https://www.paypal.me/NilsMaier/15" title="Donate €15" target="_blank">
<svg viewBox="0 0 300 72" width="110">
<rect x="1.5" y="1.5" width="297" height="69" ry="34.093" fill="#ffc439" fill-rule="evenodd" stroke="#dadce0" stroke-dashoffset="89.999" stroke-linejoin="round" stroke-width="3" style="paint-order:normal" />
<g transform="translate(28.855)">
<path d="m42.414 58.373 0.83858-5.284-1.868-0.04295h-8.9197l6.1988-38.991c0.01924-0.1177 0.08177-0.22746 0.17317-0.3054 0.09139-0.07794 0.20844-0.12089 0.3303-0.12089h15.04c4.993 0 8.4387 1.0307 10.238 3.0651 0.84339 0.95437 1.3805 1.9517 1.6403 3.0492 0.27258 1.1516 0.27739 2.5275 0.01122 4.2056l-0.01924 0.12248v1.0753l0.84339 0.474c0.71031 0.37379 1.2747 0.80167 1.7076 1.2916 0.72153 0.81599 1.1881 1.8531 1.3853 3.0826 0.20363 1.2645 0.13629 2.7693-0.19722 4.4728-0.38482 1.9596-1.0069 3.6664-1.8471 5.0629-0.77284 1.2868-1.7573 2.3541-2.9262 3.1812-1.116 0.78576-2.442 1.3822-3.9412 1.764-1.4527 0.37538-3.109 0.56467-4.9257 0.56467h-1.1705c-0.83698 0-1.6499 0.29904-2.2881 0.83507-0.63976 0.54717-1.0631 1.2948-1.1929 2.1123l-0.08819 0.47559-1.4815 9.3131-0.06734 0.34198c-0.01764 0.10816-0.0481 0.16224-0.093 0.19883-0.04008 0.0334-0.09781 0.05567-0.15393 0.05567z" fill="#253b80" />
<path d="m67.719 24.195c-0.0449 0.28472-0.0962 0.5758-0.15393 0.87484-1.9834 10.102-8.769 13.592-17.435 13.592h-4.4126c-1.0598 0-1.9529 0.7635-2.1181 1.8006l-2.2592 14.214-0.63976 4.029c-0.10743 0.68078 0.4217 1.2948 1.1144 1.2948h7.8262c0.92677 0 1.714-0.66806 1.8599-1.5747l0.07696-0.39447 1.4735-9.2765 0.0946-0.509c0.14431-0.90983 0.93318-1.5779 1.8599-1.5779h1.1705c7.5825 0 13.518-3.054 15.253-11.891 0.72474-3.6918 0.34954-6.7744-1.5681-8.9424-0.58043-0.65374-1.3004-1.1961-2.1421-1.6383z" fill="#179bd7" />
<path d="m65.644 23.374c-0.30304-0.08748-0.61571-0.16702-0.93639-0.23859-0.32228-0.06999-0.65259-0.13202-0.99251-0.1861-1.1897-0.19087-2.4933-0.28154-3.8899-0.28154h-11.788c-0.29022 0-0.566 0.06522-0.81293 0.18292-0.54355 0.25927-0.94761 0.76986-1.0454 1.395l-2.5077 15.757-0.07215 0.45969c0.16515-1.0371 1.0582-1.8006 2.1181-1.8006h4.4126c8.6664 0 15.452-3.4914 17.435-13.592 0.05933-0.29904 0.10903-0.59012 0.15393-0.87484-0.50187-0.26404-1.0454-0.48991-1.6307-0.68237-0.14431-0.04772-0.29342-0.09385-0.44414-0.13838z" fill="#222d65" />
<path d="m46.179 24.246c0.09781-0.62511 0.50187-1.1357 1.0454-1.3934 0.24853-0.11771 0.52271-0.18292 0.81293-0.18292h11.788c1.3966 0 2.7001 0.09066 3.8899 0.28154 0.33992 0.05408 0.67022 0.11612 0.99251 0.1861 0.32068 0.07158 0.63334 0.15111 0.93639 0.23859 0.15072 0.04454 0.29984 0.09067 0.44575 0.13679 0.58524 0.19246 1.1288 0.41992 1.6307 0.68237 0.59005-3.7332-0.0048-6.275-2.0395-8.5766-2.2432-2.5338-6.2918-3.6186-11.472-3.6186h-15.04c-1.0582 0-1.961 0.7635-2.1245 1.8022l-6.2645 39.392c-0.12346 0.7794 0.48262 1.4825 1.2747 1.4825h9.2853l2.3314-14.673z" fill="#253b80" />
</g>
<g transform="matrix(1.004 0 0 .996 4.7854 0)" fill="#009cde" opacity=".75" stroke="#003087" stroke-width="1px" aria-label="15">
<path d="m173.05 47.333h7.9336v-22.517l-8.1436 1.6801v-6.1135l8.0969-1.6801h8.5403v28.631h7.9336v6.2069h-24.361z" />
<path d="m208.75 18.702h22.331v6.6035h-15.167v5.3902q1.0267-0.28001 2.0534-0.42001 1.05-0.16334 2.1701-0.16334 6.3702 0 9.917 3.1968 3.5468 3.1734 3.5468 8.8669 0 5.6468-3.8734 8.8436-3.8501 3.1968-10.71 3.1968-2.9634 0-5.8802-0.58335-2.8934-0.56002-5.7635-1.7267v-7.0702q2.8468 1.6334 5.3902 2.4501 2.5667 0.81669 4.8302 0.81669 3.2668 0 5.1335-1.5867 1.89-1.61 1.89-4.3401 0-2.7534-1.89-4.3401-1.8667-1.5867-5.1335-1.5867-1.9367 0-4.1301 0.51335-2.1934 0.49002-4.7135 1.54z" />
</g>
<g transform="matrix(1.004 0 0 .996 4.7854 0)" fill="#003087" aria-label="€">
<path d="m153.83 51.627q-2.2167 1.2834-4.6435 1.9367-2.4034 0.65335-5.0168 0.65335-6.1135 0-10.314-3.0334-4.1768-3.0568-5.9268-8.7736h-5.0635l2.0534-4.5501h2.2867q-0.0233-0.32668-0.0467-0.67669 0-0.37334 0-1.0267 0-0.67669 0-1.05 0.0233-0.37334 0.0467-0.72336h-4.3401l2.0534-4.5501h3.0101q1.7967-5.7402 5.9502-8.7503 4.1768-3.0101 10.29-3.0101 2.6134 0 5.0168 0.65335 2.4267 0.65335 4.6435 1.9367v7.2102q-1.8901-1.8201-4.0368-2.7301-2.1467-0.93336-4.4568-0.93336-2.9634 0-5.0635 1.4467-2.0767 1.4234-3.1268 4.1768h12.577l-2.0067 4.5501h-11.504q-0.0467 0.37334-0.07 0.79336 0 0.42001 0 1.26 0 0.30334 0 0.67669 0.0233 0.35001 0.0467 0.74669h10.01l-2.0767 4.5501h-6.9769q1.1667 2.8468 3.1968 4.2701 2.0534 1.4234 4.9935 1.4234 2.3101 0 4.4101-0.91003 2.1234-0.93336 4.0835-2.7768z" fill="#003087" stroke-width="1px" />
</g>
</svg>
</a>
<a href="https://www.paypal.me/NilsMaier/20" title="Donate €20" target="_blank">
<svg viewBox="0 0 300 72" width="110">
<rect x="1.5" y="1.5" width="297" height="69" ry="34.093" fill="#ffc439" fill-rule="evenodd" stroke="#dadce0" stroke-dashoffset="89.999" stroke-linejoin="round" stroke-width="3" style="paint-order:normal" />
<g transform="translate(28.855)">
<path d="m42.414 58.373 0.83858-5.284-1.868-0.04295h-8.9197l6.1988-38.991c0.01924-0.1177 0.08177-0.22746 0.17317-0.3054 0.09139-0.07794 0.20844-0.12089 0.3303-0.12089h15.04c4.993 0 8.4387 1.0307 10.238 3.0651 0.84339 0.95437 1.3805 1.9517 1.6403 3.0492 0.27258 1.1516 0.27739 2.5275 0.01122 4.2056l-0.01924 0.12248v1.0753l0.84339 0.474c0.71031 0.37379 1.2747 0.80167 1.7076 1.2916 0.72153 0.81599 1.1881 1.8531 1.3853 3.0826 0.20363 1.2645 0.13629 2.7693-0.19722 4.4728-0.38482 1.9596-1.0069 3.6664-1.8471 5.0629-0.77284 1.2868-1.7573 2.3541-2.9262 3.1812-1.116 0.78576-2.442 1.3822-3.9412 1.764-1.4527 0.37538-3.109 0.56467-4.9257 0.56467h-1.1705c-0.83698 0-1.6499 0.29904-2.2881 0.83507-0.63976 0.54717-1.0631 1.2948-1.1929 2.1123l-0.08819 0.47559-1.4815 9.3131-0.06734 0.34198c-0.01764 0.10816-0.0481 0.16224-0.093 0.19883-0.04008 0.0334-0.09781 0.05567-0.15393 0.05567z" fill="#253b80" />
<path d="m67.719 24.195c-0.0449 0.28472-0.0962 0.5758-0.15393 0.87484-1.9834 10.102-8.769 13.592-17.435 13.592h-4.4126c-1.0598 0-1.9529 0.7635-2.1181 1.8006l-2.2592 14.214-0.63976 4.029c-0.10743 0.68078 0.4217 1.2948 1.1144 1.2948h7.8262c0.92677 0 1.714-0.66806 1.8599-1.5747l0.07696-0.39447 1.4735-9.2765 0.0946-0.509c0.14431-0.90983 0.93318-1.5779 1.8599-1.5779h1.1705c7.5825 0 13.518-3.054 15.253-11.891 0.72474-3.6918 0.34954-6.7744-1.5681-8.9424-0.58043-0.65374-1.3004-1.1961-2.1421-1.6383z" fill="#179bd7" />
<path d="m65.644 23.374c-0.30304-0.08748-0.61571-0.16702-0.93639-0.23859-0.32228-0.06999-0.65259-0.13202-0.99251-0.1861-1.1897-0.19087-2.4933-0.28154-3.8899-0.28154h-11.788c-0.29022 0-0.566 0.06522-0.81293 0.18292-0.54355 0.25927-0.94761 0.76986-1.0454 1.395l-2.5077 15.757-0.07215 0.45969c0.16515-1.0371 1.0582-1.8006 2.1181-1.8006h4.4126c8.6664 0 15.452-3.4914 17.435-13.592 0.05933-0.29904 0.10903-0.59012 0.15393-0.87484-0.50187-0.26404-1.0454-0.48991-1.6307-0.68237-0.14431-0.04772-0.29342-0.09385-0.44414-0.13838z" fill="#222d65" />
<path d="m46.179 24.246c0.09781-0.62511 0.50187-1.1357 1.0454-1.3934 0.24853-0.11771 0.52271-0.18292 0.81293-0.18292h11.788c1.3966 0 2.7001 0.09066 3.8899 0.28154 0.33992 0.05408 0.67022 0.11612 0.99251 0.1861 0.32068 0.07158 0.63334 0.15111 0.93639 0.23859 0.15072 0.04454 0.29984 0.09067 0.44575 0.13679 0.58524 0.19246 1.1288 0.41992 1.6307 0.68237 0.59005-3.7332-0.0048-6.275-2.0395-8.5766-2.2432-2.5338-6.2918-3.6186-11.472-3.6186h-15.04c-1.0582 0-1.961 0.7635-2.1245 1.8022l-6.2645 39.392c-0.12346 0.7794 0.48262 1.4825 1.2747 1.4825h9.2853l2.3314-14.673z" fill="#253b80" />
</g>
<g transform="matrix(1.004 0 0 .996 4.7854 0)" fill="#009cde" stroke="#003087" stroke-width="1px" aria-label="20">
<path d="m181.22 46.936h15.33v6.6035h-25.317v-6.6035l12.717-11.224q1.7034-1.54 2.5201-3.0101 0.81669-1.47 0.81669-3.0568 0-2.4501-1.6567-3.9435-1.6334-1.4934-4.3635-1.4934-2.1001 0-4.5968 0.91003-2.4968 0.88669-5.3435 2.6601v-7.6536q3.0334-1.0034 5.9968-1.5167 2.9634-0.53668 5.8102-0.53668 6.2535 0 9.707 2.7534 3.4768 2.7534 3.4768 7.6769 0 2.8468-1.47 5.3202-1.47 2.4501-6.1835 6.5802z" />
<path d="m225.67 36.086q0-6.5335-1.2367-9.1936-1.2134-2.6834-4.1068-2.6834t-4.1301 2.6834q-1.2367 2.6601-1.2367 9.1936 0 6.6035 1.2367 9.3103 1.2367 2.7067 4.1301 2.7067 2.8701 0 4.1068-2.7067t1.2367-9.3103zm8.9836 0.07q0 8.6569-3.7334 13.37-3.7334 4.6901-10.594 4.6901-6.8835 0-10.617-4.6901-3.7334-4.7135-3.7334-13.37 0-8.6803 3.7334-13.37 3.7334-4.7135 10.617-4.7135 6.8602 0 10.594 4.7135 3.7334 4.6901 3.7334 13.37z" />
</g>
<g transform="matrix(1.004 0 0 .996 4.7854 0)" fill="#003087" aria-label="€">
<path d="m153.83 51.627q-2.2167 1.2834-4.6435 1.9367-2.4034 0.65335-5.0168 0.65335-6.1135 0-10.314-3.0334-4.1768-3.0568-5.9268-8.7736h-5.0635l2.0534-4.5501h2.2867q-0.0233-0.32668-0.0467-0.67669 0-0.37334 0-1.0267 0-0.67669 0-1.05 0.0233-0.37334 0.0467-0.72336h-4.3401l2.0534-4.5501h3.0101q1.7967-5.7402 5.9502-8.7503 4.1768-3.0101 10.29-3.0101 2.6134 0 5.0168 0.65335 2.4267 0.65335 4.6435 1.9367v7.2102q-1.8901-1.8201-4.0368-2.7301-2.1467-0.93336-4.4568-0.93336-2.9634 0-5.0635 1.4467-2.0767 1.4234-3.1268 4.1768h12.577l-2.0067 4.5501h-11.504q-0.0467 0.37334-0.07 0.79336 0 0.42001 0 1.26 0 0.30334 0 0.67669 0.0233 0.35001 0.0467 0.74669h10.01l-2.0767 4.5501h-6.9769q1.1667 2.8468 3.1968 4.2701 2.0534 1.4234 4.9935 1.4234 2.3101 0 4.4101-0.91003 2.1234-0.93336 4.0835-2.7768z" fill="#003087" stroke-width="1px" />
</g>
</svg>
</a>
<a href="https://www.paypal.me/NilsMaier/30" title="Donate €30" target="_blank">
<svg viewBox="0 0 300 72" width="110">
<rect x="1.5" y="1.5" width="297" height="69" ry="34.093" fill="#ffc439" fill-rule="evenodd" stroke="#dadce0" stroke-dashoffset="89.999" stroke-linejoin="round" stroke-width="3" style="paint-order:normal" />
<g transform="translate(28.855)">
<path d="m42.414 58.373 0.83858-5.284-1.868-0.04295h-8.9197l6.1988-38.991c0.01924-0.1177 0.08177-0.22746 0.17317-0.3054 0.09139-0.07794 0.20844-0.12089 0.3303-0.12089h15.04c4.993 0 8.4387 1.0307 10.238 3.0651 0.84339 0.95437 1.3805 1.9517 1.6403 3.0492 0.27258 1.1516 0.27739 2.5275 0.01122 4.2056l-0.01924 0.12248v1.0753l0.84339 0.474c0.71031 0.37379 1.2747 0.80167 1.7076 1.2916 0.72153 0.81599 1.1881 1.8531 1.3853 3.0826 0.20363 1.2645 0.13629 2.7693-0.19722 4.4728-0.38482 1.9596-1.0069 3.6664-1.8471 5.0629-0.77284 1.2868-1.7573 2.3541-2.9262 3.1812-1.116 0.78576-2.442 1.3822-3.9412 1.764-1.4527 0.37538-3.109 0.56467-4.9257 0.56467h-1.1705c-0.83698 0-1.6499 0.29904-2.2881 0.83507-0.63976 0.54717-1.0631 1.2948-1.1929 2.1123l-0.08819 0.47559-1.4815 9.3131-0.06734 0.34198c-0.01764 0.10816-0.0481 0.16224-0.093 0.19883-0.04008 0.0334-0.09781 0.05567-0.15393 0.05567z" fill="#253b80" />
<path d="m67.719 24.195c-0.0449 0.28472-0.0962 0.5758-0.15393 0.87484-1.9834 10.102-8.769 13.592-17.435 13.592h-4.4126c-1.0598 0-1.9529 0.7635-2.1181 1.8006l-2.2592 14.214-0.63976 4.029c-0.10743 0.68078 0.4217 1.2948 1.1144 1.2948h7.8262c0.92677 0 1.714-0.66806 1.8599-1.5747l0.07696-0.39447 1.4735-9.2765 0.0946-0.509c0.14431-0.90983 0.93318-1.5779 1.8599-1.5779h1.1705c7.5825 0 13.518-3.054 15.253-11.891 0.72474-3.6918 0.34954-6.7744-1.5681-8.9424-0.58043-0.65374-1.3004-1.1961-2.1421-1.6383z" fill="#179bd7" />
<path d="m65.644 23.374c-0.30304-0.08748-0.61571-0.16702-0.93639-0.23859-0.32228-0.06999-0.65259-0.13202-0.99251-0.1861-1.1897-0.19087-2.4933-0.28154-3.8899-0.28154h-11.788c-0.29022 0-0.566 0.06522-0.81293 0.18292-0.54355 0.25927-0.94761 0.76986-1.0454 1.395l-2.5077 15.757-0.07215 0.45969c0.16515-1.0371 1.0582-1.8006 2.1181-1.8006h4.4126c8.6664 0 15.452-3.4914 17.435-13.592 0.05933-0.29904 0.10903-0.59012 0.15393-0.87484-0.50187-0.26404-1.0454-0.48991-1.6307-0.68237-0.14431-0.04772-0.29342-0.09385-0.44414-0.13838z" fill="#222d65" />
<path d="m46.179 24.246c0.09781-0.62511 0.50187-1.1357 1.0454-1.3934 0.24853-0.11771 0.52271-0.18292 0.81293-0.18292h11.788c1.3966 0 2.7001 0.09066 3.8899 0.28154 0.33992 0.05408 0.67022 0.11612 0.99251 0.1861 0.32068 0.07158 0.63334 0.15111 0.93639 0.23859 0.15072 0.04454 0.29984 0.09067 0.44575 0.13679 0.58524 0.19246 1.1288 0.41992 1.6307 0.68237 0.59005-3.7332-0.0048-6.275-2.0395-8.5766-2.2432-2.5338-6.2918-3.6186-11.472-3.6186h-15.04c-1.0582 0-1.961 0.7635-2.1245 1.8022l-6.2645 39.392c-0.12346 0.7794 0.48262 1.4825 1.2747 1.4825h9.2853l2.3314-14.673z" fill="#253b80" />
</g>
<g transform="matrix(1.004 0 0 .996 4.7854 0)" fill="#009cde" stroke="#003087" stroke-width="1px" aria-label="30">
<path d="m189.71 34.756q3.5234 0.91003 5.3435 3.1734 1.8434 2.2401 1.8434 5.7168 0 5.1802-3.9668 7.8869-3.9668 2.6834-11.574 2.6834-2.6834 0-5.3902-0.44335-2.6834-0.42001-5.3202-1.2834v-6.9302q2.5201 1.26 4.9935 1.9134 2.4967 0.63002 4.9002 0.63002 3.5701 0 5.4602-1.2367 1.9134-1.2367 1.9134-3.5468 0-2.3801-1.9601-3.5934-1.9367-1.2367-5.7402-1.2367h-3.5934v-5.7868h3.7801q3.3834 0 5.0402-1.05 1.6567-1.0734 1.6567-3.2434 0-2.0067-1.61-3.1034t-4.5501-1.0967q-2.1701 0-4.3868 0.49002t-4.4101 1.4467v-6.5802q2.6601-0.74669 5.2735-1.12 2.6134-0.37334 5.1335-0.37334 6.7902 0 10.15 2.2401 3.3834 2.2167 3.3834 6.6969 0 3.0568-1.61 5.0168-1.61 1.9367-4.7601 2.7301z" />
<path d="m225.67 36.086q0-6.5335-1.2367-9.1936-1.2134-2.6834-4.1068-2.6834t-4.1301 2.6834q-1.2367 2.6601-1.2367 9.1936 0 6.6035 1.2367 9.3103 1.2367 2.7067 4.1301 2.7067 2.8701 0 4.1068-2.7067t1.2367-9.3103zm8.9836 0.07q0 8.6569-3.7334 13.37-3.7334 4.6901-10.594 4.6901-6.8835 0-10.617-4.6901-3.7334-4.7135-3.7334-13.37 0-8.6803 3.7334-13.37 3.7334-4.7135 10.617-4.7135 6.8602 0 10.594 4.7135 3.7334 4.6901 3.7334 13.37z" />
</g>
<g transform="matrix(1.004 0 0 .996 4.7854 0)" fill="#003087" aria-label="€">
<path d="m153.83 51.627q-2.2167 1.2834-4.6435 1.9367-2.4034 0.65335-5.0168 0.65335-6.1135 0-10.314-3.0334-4.1768-3.0568-5.9268-8.7736h-5.0635l2.0534-4.5501h2.2867q-0.0233-0.32668-0.0467-0.67669 0-0.37334 0-1.0267 0-0.67669 0-1.05 0.0233-0.37334 0.0467-0.72336h-4.3401l2.0534-4.5501h3.0101q1.7967-5.7402 5.9502-8.7503 4.1768-3.0101 10.29-3.0101 2.6134 0 5.0168 0.65335 2.4267 0.65335 4.6435 1.9367v7.2102q-1.8901-1.8201-4.0368-2.7301-2.1467-0.93336-4.4568-0.93336-2.9634 0-5.0635 1.4467-2.0767 1.4234-3.1268 4.1768h12.577l-2.0067 4.5501h-11.504q-0.0467 0.37334-0.07 0.79336 0 0.42001 0 1.26 0 0.30334 0 0.67669 0.0233 0.35001 0.0467 0.74669h10.01l-2.0767 4.5501h-6.9769q1.1667 2.8468 3.1968 4.2701 2.0534 1.4234 4.9935 1.4234 2.3101 0 4.4101-0.91003 2.1234-0.93336 4.0835-2.7768z" fill="#003087" stroke-width="1px" />
</g>
</svg>
</a>
<a id="ppanother" href="https://www.paypal.me/NilsMaier" title="Donate another amount" target="_blank">
<svg viewBox="0 0 300 72" width="110">
<rect x="1.5" y="1.5" width="297" height="69" ry="34.093" fill="#ffc439" fill-rule="evenodd" stroke="#dadce0" stroke-dashoffset="89.999" stroke-linejoin="round" stroke-width="3" style="paint-order:normal" />
<g transform="translate(19.23)">
<path d="m42.414 58.373 0.83858-5.284-1.868-0.04295h-8.9197l6.1988-38.991c0.01924-0.1177 0.08177-0.22746 0.17317-0.3054 0.09139-0.07794 0.20844-0.12089 0.3303-0.12089h15.04c4.993 0 8.4387 1.0307 10.238 3.0651 0.84339 0.95437 1.3805 1.9517 1.6403 3.0492 0.27258 1.1516 0.27739 2.5275 0.01122 4.2056l-0.01924 0.12248v1.0753l0.84339 0.474c0.71031 0.37379 1.2747 0.80167 1.7076 1.2916 0.72153 0.81599 1.1881 1.8531 1.3853 3.0826 0.20363 1.2645 0.13629 2.7693-0.19722 4.4728-0.38482 1.9596-1.0069 3.6664-1.8471 5.0629-0.77284 1.2868-1.7573 2.3541-2.9262 3.1812-1.116 0.78576-2.442 1.3822-3.9412 1.764-1.4527 0.37538-3.109 0.56467-4.9257 0.56467h-1.1705c-0.83698 0-1.6499 0.29904-2.2881 0.83507-0.63976 0.54717-1.0631 1.2948-1.1929 2.1123l-0.08819 0.47559-1.4815 9.3131-0.06734 0.34198c-0.01764 0.10816-0.0481 0.16224-0.093 0.19883-0.04008 0.0334-0.09781 0.05567-0.15393 0.05567z" fill="#253b80" />
<path d="m67.719 24.195c-0.0449 0.28472-0.0962 0.5758-0.15393 0.87484-1.9834 10.102-8.769 13.592-17.435 13.592h-4.4126c-1.0598 0-1.9529 0.7635-2.1181 1.8006l-2.2592 14.214-0.63976 4.029c-0.10743 0.68078 0.4217 1.2948 1.1144 1.2948h7.8262c0.92677 0 1.714-0.66806 1.8599-1.5747l0.07696-0.39447 1.4735-9.2765 0.0946-0.509c0.14431-0.90983 0.93318-1.5779 1.8599-1.5779h1.1705c7.5825 0 13.518-3.054 15.253-11.891 0.72474-3.6918 0.34954-6.7744-1.5681-8.9424-0.58043-0.65374-1.3004-1.1961-2.1421-1.6383z" fill="#179bd7" />
<path d="m65.644 23.374c-0.30304-0.08748-0.61571-0.16702-0.93639-0.23859-0.32228-0.06999-0.65259-0.13202-0.99251-0.1861-1.1897-0.19087-2.4933-0.28154-3.8899-0.28154h-11.788c-0.29022 0-0.566 0.06522-0.81293 0.18292-0.54355 0.25927-0.94761 0.76986-1.0454 1.395l-2.5077 15.757-0.07215 0.45969c0.16515-1.0371 1.0582-1.8006 2.1181-1.8006h4.4126c8.6664 0 15.452-3.4914 17.435-13.592 0.05933-0.29904 0.10903-0.59012 0.15393-0.87484-0.50187-0.26404-1.0454-0.48991-1.6307-0.68237-0.14431-0.04772-0.29342-0.09385-0.44414-0.13838z" fill="#222d65" />
<path d="m46.179 24.246c0.09781-0.62511 0.50187-1.1357 1.0454-1.3934 0.24853-0.11771 0.52271-0.18292 0.81293-0.18292h11.788c1.3966 0 2.7001 0.09066 3.8899 0.28154 0.33992 0.05408 0.67022 0.11612 0.99251 0.1861 0.32068 0.07158 0.63334 0.15111 0.93639 0.23859 0.15072 0.04454 0.29984 0.09067 0.44575 0.13679 0.58524 0.19246 1.1288 0.41992 1.6307 0.68237 0.59005-3.7332-0.0048-6.275-2.0395-8.5766-2.2432-2.5338-6.2918-3.6186-11.472-3.6186h-15.04c-1.0582 0-1.961 0.7635-2.1245 1.8022l-6.2645 39.392c-0.12346 0.7794 0.48262 1.4825 1.2747 1.4825h9.2853l2.3314-14.673z" fill="#253b80" />
</g>
<g transform="translate(0 -.24886)" stroke-width="1.7342px">
<g transform="matrix(.57894 0 0 .57432 95.638 27.862)" fill="#009cde" stroke="#003087" aria-label="Amount">
<path d="m62.511 47.193h-14.047l-2.2167 6.3469h-9.0303l12.904-34.838h10.71l12.904 34.838h-9.0303zm-11.807-6.4635h9.5436l-4.7601-13.86z" />
<path d="m105.19 31.746q1.5867-2.4267 3.7568-3.6868 2.1934-1.2834 4.8068-1.2834 4.5035 0 6.8602 2.7768t2.3567 8.0736v15.914h-8.4002v-13.627q0.0233-0.30334 0.0233-0.63002 0.0233-0.32668 0.0233-0.93336 0-2.7768-0.8167-4.0135-0.81669-1.26-2.6367-1.26-2.3801 0-3.6868 1.9601-1.2834 1.9601-1.33 5.6702v12.834h-8.4002v-13.627q0-4.3401-0.74669-5.5768-0.74669-1.26-2.6601-1.26-2.4034 0-3.7101 1.9834-1.3067 1.9601-1.3067 5.6235v12.857h-8.4003v-26.134h8.4003v3.8268q1.54-2.2167 3.5234-3.3368 2.0067-1.12 4.4101-1.12 2.7067 0 4.7835 1.3067 2.0767 1.3067 3.1501 3.6634z" />
<path d="m146.26 32.749q-2.7768 0-4.2468 2.0067-1.4467 1.9834-1.4467 5.7402t1.4467 5.7635q1.47 1.9834 4.2468 1.9834 2.7301 0 4.1768-1.9834 1.4467-2.0067 1.4467-5.7635t-1.4467-5.7402q-1.4467-2.0067-4.1768-2.0067zm0-5.9735q6.7435 0 10.524 3.6401 3.8034 3.6401 3.8034 10.08 0 6.4402-3.8034 10.08-3.7801 3.6401-10.524 3.6401-6.7669 0-10.594-3.6401-3.8034-3.6401-3.8034-10.08 0-6.4402 3.8034-10.08 3.8268-3.6401 10.594-3.6401z" />
<path d="m169.41 43.366v-15.96h8.4002v2.6134q0 2.1234-0.0233 5.3435-0.0233 3.1968-0.0233 4.2701 0 3.1501 0.16334 4.5501 0.16334 1.3767 0.56002 2.0067 0.51335 0.81669 1.33 1.26 0.84002 0.44335 1.9134 0.44335 2.6134 0 4.1068-2.0067t1.4934-5.5768v-12.904h8.3536v26.134h-8.3536v-3.7801q-1.8901 2.2867-4.0134 3.3834-2.1001 1.0734-4.6435 1.0734-4.5268 0-6.9069-2.7768-2.3567-2.7768-2.3567-8.0736z" />
<path d="m233.04 37.626v15.914h-8.4003v-12.18q0-3.3834-0.16333-4.6668-0.14001-1.2834-0.51335-1.8901-0.49002-0.81669-1.33-1.26-0.84003-0.46668-1.9134-0.46668-2.6134 0-4.1068 2.0301-1.4934 2.0067-1.4934 5.5768v12.857h-8.3536v-26.134h8.3536v3.8268q1.8901-2.2867 4.0135-3.3601 2.1234-1.0967 4.6901-1.0967 4.5268 0 6.8602 2.7768 2.3567 2.7768 2.3567 8.0736z" />
<path d="m252.97 19.986v7.4202h8.6103v5.9735h-8.6103v11.084q0 1.8201 0.72335 2.4734 0.72336 0.63002 2.8701 0.63002h4.2935v5.9735h-7.1636q-4.9468 0-7.0236-2.0534-2.0534-2.0767-2.0534-7.0235v-11.084h-4.1535v-5.9735h4.1535v-7.4202z" />
</g>
<g transform="matrix(.57894 0 0 .57432 95.638 23.862)" fill="#003087" aria-label="Another">
<path d="m57.459 11.049h-14.047l-2.2167 6.3469h-9.0303l12.904-34.838h10.71l12.904 34.838h-9.0303zm-11.807-6.4635h9.5436l-4.7601-13.86z" />
<path d="m102.19 1.4817v15.914h-8.4003v-12.18q0-3.3834-0.16334-4.6668-0.14-1.2834-0.51335-1.8901-0.49002-0.81669-1.33-1.26-0.84002-0.46668-1.9134-0.46668-2.6134 0-4.1068 2.0301-1.4934 2.0067-1.4934 5.5768v12.857h-8.3536v-26.134h8.3536v3.8268q1.8901-2.2867 4.0135-3.3601 2.1234-1.0967 4.6901-1.0967 4.5268 0 6.8602 2.7768 2.3567 2.7768 2.3567 8.0736z" />
<path d="m125.43-3.3951q-2.7768 0-4.2468 2.0067-1.4467 1.9834-1.4467 5.7402t1.4467 5.7635q1.47 1.9834 4.2468 1.9834 2.7301 0 4.1768-1.9834 1.4467-2.0067 1.4467-5.7635t-1.4467-5.7402q-1.4467-2.0067-4.1768-2.0067zm0-5.9735q6.7435 0 10.524 3.6401 3.8034 3.6401 3.8034 10.08 0 6.4402-3.8034 10.08-3.7801 3.6401-10.524 3.6401-6.7669 0-10.594-3.6401-3.8034-3.6401-3.8034-10.08 0-6.4402 3.8034-10.08 3.8268-3.6401 10.594-3.6401z" />
<path d="m157.99-16.159v7.4202h8.6103v5.9735h-8.6103v11.084q0 1.8201 0.72336 2.4734 0.72336 0.63002 2.8701 0.63002h4.2935v5.9735h-7.1636q-4.9468 0-7.0236-2.0534-2.0534-2.0767-2.0534-7.0235v-11.084h-4.1535v-5.9735h4.1535v-7.4202z" />
<path d="m201.02 1.4817v15.914h-8.4002v-12.134q0-3.4301-0.16334-4.7135-0.14001-1.2834-0.51335-1.8901-0.49002-0.81669-1.33-1.26-0.84003-0.46668-1.9134-0.46668-2.6134 0-4.1068 2.0301-1.4934 2.0067-1.4934 5.5768v12.857h-8.3536v-36.308h8.3536v14q1.89-2.2867 4.0134-3.3601 2.1234-1.0967 4.6901-1.0967 4.5268 0 6.8602 2.7768 2.3567 2.7768 2.3567 8.0736z" />
<path d="m237.91 4.2585v2.3801h-19.531q0.30334 2.9401 2.1234 4.4101 1.8201 1.47 5.0868 1.47 2.6367 0 5.3902-0.77002 2.7768-0.79336 5.6935-2.3801v6.4402q-2.9634 1.12-5.9268 1.6801-2.9634 0.58335-5.9268 0.58335-7.0936 0-11.037-3.5934-3.9201-3.6168-3.9201-10.127 0-6.3935 3.8501-10.057 3.8734-3.6634 10.64-3.6634 6.1602 0 9.847 3.7101 3.7101 3.7101 3.7101 9.917zm-8.5869-2.7768q0-2.3801-1.4-3.8268-1.3767-1.47-3.6168-1.47-2.4267 0-3.9434 1.3767-1.5167 1.3534-1.8901 3.9201z" />
<path d="m266.64-1.6217q-1.0967-0.51335-2.1934-0.74669-1.0734-0.25667-2.1701-0.25667-3.2201 0-4.9702 2.0767-1.7267 2.0534-1.7267 5.9035v12.04h-8.3536v-26.134h8.3536v4.2935q1.61-2.5667 3.6868-3.7334 2.1001-1.19 5.0168-1.19 0.42001 0 0.91002 0.046668 0.49002 0.023334 1.4234 0.14z" />
</g>
</g>
</svg>
</a>
</section>
<p>It requires <strong>a lot of time and some money</strong> to create the extension, keep up with browser
changes, read and answer emails, bug reports and feature requests, and actually publish the final versions.
<em>Any contribution is appreciated. Thank you!</em></p>
<h2>Overview</h2>
<p>DownThemAll! is an extension designed for people who have to download a lot of files and do not want to click on
each individual link.
Subfolders and renaming masks also help you sort downloads quickly. Customizable filters will help you to rapidly
select what links to download, </p>
<p>What's more, DownThemAll! comes with the OneClick feature which will select files using your last used filters
and preferences.</p>
<h2>Privacy Notice</h2>
<section id="privacy">
<svg version="1.1" viewBox="0 0 24 24" width="64" height="64">
<path d="M12 23.81h-.11a10.34 10.34 0 0 1-6.67-4c-1.92-2.61-2.7-4.91-3.08-9.12C2 9.24 2 6.28 2 4a2.53 2.53 0 0 1 2.09-2.5L12 .19l7.91 1.35A2.53 2.53 0 0 1 22 4c0 1.83 0 5.12-.14 6.59-.38 4.21-1.16 6.51-3.08 9.12a10.34 10.34 0 0 1-6.67 4zm0-21.6l-7.58 1.3A.54.54 0 0 0 4 4c0 1.8 0 5 .13 6.41.35 3.84 1 5.81 2.7 8.11A8.53 8.53 0 0 0 12 21.79a8.5 8.5 0 0 0 5.17-3.23c1.69-2.3 2.35-4.27 2.7-8.11C20 9.06 20 5.84 20 4a.52.52 0 0 0-.42-.52z"/>
<path d="M12 4.57l-5.4.93c0 2 .07 3.58.13 4.33.42 4.59 1.21 5.95 2.45 7.63a5.71 5.71 0 0 0 2.82 2z"/>
</svg>
<div>
<p>DownThemAll! does <strong>not</strong> collect any personal information!</p>
<p>All information, such as your preferences and downloads, is <em>only</em> stored in your browser - under your full control - and the developers of DownThemAll! do <em>not</em> have access to this information.
DownThemAll! is not monetized and does not contain ads. The project is financed by donations, including the time the developers and translators spend on maintaining the project.</p>
</div>
</section>
<h2>Getting Started</h2>
<p>After installing DownThemAll! there will be a new button in your browser toolbar. You can add or remove this
button using your browser's customization preferences. The button gives you quick and easy access to DownThemAll!
main features.</p>
<ul>
<li>DownThemAll! + OneClick for the current or all tabs in the current window</li>
<li>Manually adding downloads</li>
<li>Opening the Manager or the extension preferences</li>
</ul>
<p>Most user will want to start using the extension with the DownThemAll! action, which brings up a selection window
for the current tab where you can select/filter links and media contained in the website, and select the location
where to save files (within your Downloads directory).</p>
<p>After you queue some downloads, the Manager will open in a new tab by default. You can change that behavior to
not have it open automatically, or open in a new window instead of a tab.</p>
<p>The Manager will then allow you to start, pause, cancel or remove downloads, open completed files, and more.</p>
<p>The following video demonstrates how to add and manage, some downloads:</p>
<figure>
<video src="first.webm" poster="first.jpg"></video>
</figure>
<p>Once you have configured your preferred settings and filters, you can speed up future queuing by using OneClick!:
</p>
<figure>
<video src="oneclick.webm" poster="oneclick.jpg"></video>
</figure>
<h2>Context Menu</h2>
<p>DownThemAll! is also available from your context menu (right clicking on elements of a website). Along with the
usual actions, the context menus also offers way to queue individual links, images or videos.</p>
<figure>
<video src="onecontext.webm" poster="onecontext.jpg"></video>
</figure>
<h2>Manually Adding Downloads</h2>
<p>DownThemAll! allows to manually add downloads. If further supports batches, where links follow a certain pattern,
e.g. "image1" to "image10".</p>
<figure>
<video src="batches.webm" poster="batches.jpg"></video>
</figure>
<h2>Preferences</h2>
<p>The extension also comes with a wide variety of options and customizations, including choosing a light or dark theme, choosing the translation to use, custom filters and custom network limits.</p>
<p>All those general settings are available in the Preferences tab.</p>
<figure>
<video src="prefs.webm" poster="prefs.jpg"></video>
</figure>
<p>If DownThemAll! is not yet available in your language, consider helping out. Our <a href="https://github.com/downthemall/downthemall/blob/master/_locales/Readme.md">Translation Guide</a> explains how to translate the extension.</a></p>
<h2>Hope you enjoy DownThemAll!</h2>
<p>And thanks for all your support, be it in donations, reporting bugs, helping testing or translating it to your native language!</p>
</article>
<footer>
<svg id="logo" viewBox="0 0 16 16">
<defs>
<linearGradient id="b">
<stop stop-color="#116597" offset="0" />
<stop stop-color="#062638" offset="1" />
</linearGradient>
<linearGradient id="a">
<stop stop-color="#fffe99" offset="0" />
<stop stop-color="#e49218" offset=".2" />
<stop stop-color="#116597" offset="1" />
</linearGradient>
<radialGradient id="c" xlink:href="#a" gradientUnits="userSpaceOnUse" cy="17.413" cx="11.75" gradientTransform="matrix(.41233 0 0 1.1548 3.24 -8.74)" r="10.752" />
<linearGradient id="h" y2="-.242" xlink:href="#a" gradientUnits="userSpaceOnUse" x2="7.763" gradientTransform="translate(2.495 -6.342) scale(.6787)" y1="4.218" x1="8.101" />
<linearGradient id="i" y2="-.242" xlink:href="#a" gradientUnits="userSpaceOnUse" x2="7.763" gradientTransform="translate(2.495 -1.882) scale(.6787)" y1="4.218" x1="8.101" />
<linearGradient id="g" y2="-.242" xlink:href="#b" gradientUnits="userSpaceOnUse" x2="7.763" gradientTransform="translate(7.08 4.18) scale(.43866)" y1="4.218" x1="8.101" />
<linearGradient id="f" y2="-.242" xlink:href="#b" gradientUnits="userSpaceOnUse" x2="7.763" gradientTransform="translate(7.657 1.298) scale(.43866)" y1="4.218" x1="8.101" />
<linearGradient id="e" y2="-.242" xlink:href="#b" gradientUnits="userSpaceOnUse" x2="7.763" gradientTransform="translate(1.851 4.18) scale(.43866)" y1="4.218" x1="8.101" />
<linearGradient id="d" y2="-.242" xlink:href="#b" gradientUnits="userSpaceOnUse" x2="7.763" gradientTransform="translate(1.851 1.298) scale(.43866)" y1="4.218" x1="8.101" />
</defs>
<g stroke="#072739">
<g stroke-width=".646">
<path d="M4.561 7.134v1.515H1.996v.262l2.949 3.333 2.666 3.05h.99l2.686-3.05 2.848-3.252V8.65h-2.727V7.134H4.561z" fill="url(#c)" />
<g stroke-linecap="round" stroke-dashoffset="10" fill-rule="evenodd">
<path fill="url(#d)" d="M4.562 1.346h1.649v1.649H4.562z" />
<path fill="url(#e)" d="M4.562 4.228h1.649v1.649H4.562z" />
<path fill="url(#f)" d="M10.368 1.346h1.649v1.649h-1.649z" />
<path fill="url(#g)" d="M9.792 4.228h1.649v1.649H9.792z" />
</g>
</g>
<g fill-rule="evenodd" stroke-linecap="round" stroke-dashoffset="10">
<path fill="url(#h)" d="M6.689-6.268H9.24v2.551H6.689z" transform="translate(2.874 4.614) scale(.64633)" />
<path fill="url(#i)" d="M6.689-1.808H9.24V.743H6.689z" transform="translate(2.874 4.614) scale(.64633)" />
</g>
</g>
</svg>
<section>
<p>Copyright © 2007-2018 Nils Maier, Stefano Verna, Federico Parodi</p>
<p>Copyright © 2007-2019 Nils Maier</p>
<p>The information on this website is licensed under the
<a href="https://creativecommons.org/licenses/by-sa/4.0/">
Creative Commons Attribution-ShareAlike 4.0 International License</a>.</p>
</section>
<a id="homepage" href="https://downthemall.org/">
<svg viewBox="0 0 250 32" height="20" xmlns="http://www.w3.org/2000/svg">
<g transform="matrix(1.1174 0 0 1.122 -217.76 -441.22)">
<path d="m277.86 402.4c-2.106 0.594-3.9921 1.3387-5.0625 3.0371-1.8782 2.9802-1.8825 0.50072-5.0625 1.0117-0.075 4.312-1.6927 7.0814-1.0117 12.148 0.251 1.099-0.2614 1.8228 2.0234 2.0254 5.078-2.0169 2.6252-12.605 9.1113-13.162 0.661 5.076 1.325 12.532 3.0371 14.174h2.0254c2.0004 0 2.4284-0.24992 2.0254-4.0449-0.157-1.478-1.5594-2.1928-2.0234-4.0508-0.436-1.744-0.20767-2.7525-1.0137-5.0625 0.20397-2.5435-3.0757-5.9543-4.0488-6.0762z" />
<path d="m205.98 396.32c0.71583-0.71583 3.037 0 3.037 0 3.312 2.743 2.107 7.979 3.037 12.148 0.97 4.354 2.863 8.229 3.037 12.149-3.865 0.827-3.919-2.155-5.062-4.05-3.517 0.195-3.843 3.58-7.086 4.05 0 0-3.0927 1.1003-6.074 0-2.2496-1.309-2.6451-6.2394-0.9158-9.8255 1.7293-3.5861 5.5833-5.828 10.027-5.3615 0 0-2.1472-6.9628 0-9.11zm-7.087 21.261c5.626-0.111 9.345-2.129 9.111-8.1-5.62-4-11.843 3.748-9.111 8.1z" />
<path d="m262.67 400.37c3.124 1.378 4.2238 9.6188 3.037 14.174-0.21875 0.83965-3.6 4.9793-4.049 5.062-5.6104 1.0329-9.589-0.535-13.161-2.024-3.76 0.627-4.631 4.142-10.124 3.037-2.976-2.578-3.758-15.21 2.025-15.187 0.646 5.261-2.233 8.114 0 12.149 7.523 0.437 4.919-9.254 9.111-12.149 4.209 1.404 0.0379 4.9881 2.024 8.1 0.7405 1.1602 0.55971 3.037 2.025 3.037h5.062c2.561-0.813 3.5092-3.7334 4.049-6.074 1.0218-4.4307-3.744-7.344 1e-3 -10.125z" />
<path d="m229.26 404.42c4.2274 1.6428 6.429 7.195 4.049 13.161-6.917 2.7019-16.888 6.2299-17.211-1.012-0.35916-8.0617 4.062-15.685 13.162-12.149zm-9.111 11.136c2.075 3.041 7.753 2.154 10.124 0 2.323-10.366-12.448-10.366-10.124 0z" />
<path d="m415.54 393.28c1.635-0.285 1.742 0.957 3.037 1.012 0.117 7.88 0.244 15.768-6.074 17.211 0.518-6.569 1.518-12.656 3.037-18.223z" />
<path d="m397.32 396.32c0.901 0.449 1.811 0.89 2.024 2.025 1.436 2.366 1.224 7.424 1.013 12.148-0.182 4.063 1.111 10.063-3.037 10.124-1.656-5.939-1.656-18.356 0-24.297z" />
<path d="m405.42 396.32c0.901 0.449 1.811 0.89 2.024 2.025 1.436 2.366 1.225 7.424 1.013 12.148-0.182 4.063 1.112 10.063-3.037 10.124-1.656-5.939-1.656-18.356 0-24.297z" />
<path d="m386.18 405.43c1.879 2.172 2.706 5.394 3.037 9.112 0.405 2.632 3.021 3.053 3.037 6.074-3.694 0.657-5.392-0.683-7.086-2.025-1.896 2.882-11.656 3.4133-12.148 0-1.2181-8.4422 3.734-13.813 13.16-13.161zm-10.123 11.136c5.229 3.119 8.32-1.521 8.123-7.087-3.941-4.338-8.175 1.277-8.123 7.087z" />
<path d="m412.5 414.54c2.928 0.446 4.614 2.134 5.062 5.062-3.131 3.21-8.628-1.578-5.062-5.062z" />
<g fill="#069">
<path d="m344.67 399.36c-3.462 3.288-12.431 1.068-14.174 6.074-0.212 4.938 5.378 4.072 10.124 4.05-0.763 3.287-5.684 2.415-8.099 4.05 0.194 6.297 7.9627 1.1977 12.148 3.037 2.1858 0.96059-2.6665 2.6983-4.05 3.037-0.92 0.229-7.2519 3.9961-10.124 1.013-4.022-4.1774-6.0966-12.401-2.0268-19.74 2.1561-3.8884 7.9908-2.3919 12.151-3.5449 2.1724-1.0195 4.0825-0.57137 4.051 2.024z" />
<path d="m368.97 398.35c0.91935 1.2579 1.638 4.258 2.024 7.086 0.632 4.615 1.344 11.963-3.037 12.149 0.605-6.006-1.776-9.022-1.012-15.187-2.943 2.12-2.8572 7.4034-6.074 9.112-5.4038 2.8702-7.236-2.214-10.124-4.05-0.162 4.899 0.612 10.735-4.05 11.136-0.788-6.862 1.383-10.766 1.013-17.21 6.881-1.144 5.642 5.832 10.124 7.086 2.854-2.881 4.6308-6.3006 7.086-10.123 0.7296-1.1359 3.2534-1.0889 4.05 1e-3z" />
<path d="m299.12 404.42c2.5659-0.14763 2.6804 4.5418 3.037 7.087 0.319 2.835 0.61 6.509-1.012 8.099-3.139 1.088-1.619-3.049-2.025-5.062-0.701-3.477-2.194-6.897 0-10.124z" />
<path d="m324 395.29c-4.1284 0.12154 0.92333 9.4224-3.6191 9.1289-3.094-0.731-3.6892 1.0347-6.0742 1.0117-5.024-0.414 3.2846-5.0625 3.2846-5.0625-1.3331-0.17112-4.8554 0.83219-4.9679-2.0635-1.1226-0.18087-1.4286 0.17857-3.0288 0.0563-0.30668 3.1413-2.5989 3.3131-5.6576 3.0448-6.3424-0.5564-15.93 1.6227-20.001 5.0366-0.88745 0.20112-1.9712 0.15704-2.4673-0.0332l0.44194 2.0606c8.225-2.236 14.819-5.3086 26.322-5.0625 0.802 5.947-2.2449 15.743 3.0371 17.211 4.327-0.057 0.29512-5.5363 2.0234-9.0879 1.899-3.9024 2.4597-3.319 5.0625-4.0723 5.9836-1.7317 0.3075 9.815 5.0625 10.123 3.109 0.858 1.9194-3.3815 2.0234-5.0625 0.3-4.805 0.0473-13.108-1.0117-17.211-0.15291-0.0158-0.29651-0.0215-0.42969-0.0176z" />
</g>
</g>
</svg>
</a>
</footer>
<script>
for (const video of document.querySelectorAll("video")) {
const p = document.createElement("div");
p.className = "play";
video.parentElement.appendChild(p);
video.onclick = () => {
video.pause();
video.currentTime = 0;
p.style.display = "block";
}
video.onended = () => {
p.style.display = "block";
video.currentTime = 0;
};
p.onclick = () => {
p.style.display = "none";
video.currentTime = 0;
video.play();
}
}
</script>
</body>
</html>

BIN
docs/landing/oneclick.jpg Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

BIN
docs/landing/oneclick.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

BIN
docs/landing/oneclick.webm Executable file

Binary file not shown.

BIN
docs/landing/onecontext.jpg Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

BIN
docs/landing/onecontext.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

BIN
docs/landing/onecontext.webm Executable file

Binary file not shown.

BIN
docs/landing/prefs.jpg Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

BIN
docs/landing/prefs.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

BIN
docs/landing/prefs.webm Executable file

Binary file not shown.

18
docs/landing/produce.py Executable file
View File

@ -0,0 +1,18 @@
import sys
from path import Path
from subprocess import check_call
options = '-map v:0 -map_metadata -1 -c:v libvpx-vp9 -deadline best -b:v 0 -crf 5 -pass 2 -row-mt 1 -vf scale=720:480:force_original_aspect_ratio=decrease:flags=spline+accurate_rnd+full_chroma_int+full_chroma_inp,pad=720:480:(ow-iw)/2:(oh-ih)/2:color=White'.split(" ")
for f in Path(".").files("*.mov"):
for p in [1, 2]:
d = f.namebase + ".webm"
final = ["ffmpeg", "-y", "-i", f.name] + options + ["-pass", str(p), d]
print(final)
check_call(final)
for f in Path(".").files("*.webm"):
for ext in [".png", ".jpg"]:
d = f.namebase + ext
final = ["ffmpeg", "-y", "-i", f, "-ss", "1", "-q:v", "2", "-frames", "1", d]
print(final)
check_call(final)

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
docs/landing/res/footerbg.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

3
docs/landing/res/go.svg Executable file
View File

@ -0,0 +1,3 @@
<svg version="1.1" viewBox="0 0 16 16" width="16" height="16" xmlns="http://www.w3.org/2000/svg">
<path d="m8 0a8 8 0 0 0-8 8 8 8 0 0 0 8 8 8 8 0 0 0 8-8 8 8 0 0 0-8-8zm-3 3 8 5-8 5v-5-5z" fill="rgb(235, 176, 37)" fill-rule="evenodd"/>
</svg>

After

Width:  |  Height:  |  Size: 248 B

55
docs/landing/res/halo.svg Executable file
View File

@ -0,0 +1,55 @@
<svg version="1.1" viewBox="0 0 200 180" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<radialGradient id="d" cx="161.46" cy="-144.02" r="160.02" gradientTransform="matrix(1 0 0 .99838 0 -.23281)" gradientUnits="userSpaceOnUse">
<stop stop-color="#febb00" offset="0"/>
<stop stop-color="#ffd571" stop-opacity=".49804" offset=".64286"/>
<stop stop-color="#ffe5a7" stop-opacity="0" offset=".95153"/>
<stop stop-color="#ffe5a7" stop-opacity="0" offset="1"/>
</radialGradient>
<filter id="e" color-interpolation-filters="sRGB">
<feGaussianBlur stdDeviation="0.32807532"/>
</filter>
<radialGradient id="c" cx="161.46" cy="-144.02" r="160.02" gradientTransform="matrix(1 0 0 .99838 0 -.23281)" gradientUnits="userSpaceOnUse">
<stop stop-color="#ffd14e" offset="0"/>
<stop stop-color="#ffeeb5" stop-opacity=".49804" offset=".71429"/>
<stop stop-color="#ffeeb5" stop-opacity=".49804" offset="1"/>
</radialGradient>
<radialGradient id="b" cx="12.389" cy="11.882" r="8.199" gradientUnits="userSpaceOnUse">
<stop stop-color="#e69412" offset="0"/>
<stop stop-color="#f4c478" stop-opacity="0" offset="1"/>
</radialGradient>
<radialGradient id="a" cx="11.75" cy="17.413" r="10.752" gradientTransform="matrix(3.3776 0 0 9.4595 121.98 -293.39)" gradientUnits="userSpaceOnUse">
<stop stop-color="#fffe99" offset="0"/>
<stop stop-color="#f69706" offset=".2"/>
<stop stop-color="#136fa7" offset="1"/>
</radialGradient>
</defs>
<g transform="translate(-61.457 224.02)">
<g transform="matrix(.62494 0 0 .62494 60.557 -51.015)" fill="url(#d)" fill-rule="evenodd">
<path d="m161.46-144.02 72.75 144.62-46.61 15.146z"/>
<path d="m161.46-144.02 143.86 74.228-28.81 39.653z"/>
<path d="m161.46-144.02 160.02-24.507v49.014z"/>
<path d="m161.46-144.02 115.05-113.88 28.81 39.653z"/>
<path d="m161.46-144.02 26.14-159.76 46.615 15.146z"/>
<path d="m161.46-144.02-72.755-144.61 46.615-15.146z"/>
<path d="m161.46-144.02-143.86-74.228 28.81-39.653z"/>
<path d="m161.46-144.02-160.02 24.507-2.7e-6 -49.014z"/>
<path d="m161.46-144.02-115.05 113.89-28.81-39.653z"/>
<path d="m161.46-144.02-26.14 159.76-46.618-15.146z"/>
</g>
<g transform="matrix(.59435 -.19312 .19312 .59435 93.307 -24.24)" fill="url(#c)" fill-rule="evenodd" opacity=".88">
<path d="m161.46-144.02 72.75 144.62-46.61 15.146z"/>
<path d="m161.46-144.02 143.86 74.228-28.81 39.653z"/>
<path d="m161.46-144.02 160.02-24.507v49.014z"/>
<path d="m161.46-144.02 115.05-113.88 28.81 39.653z"/>
<path d="m161.46-144.02 26.14-159.76 46.615 15.146z"/>
<path d="m161.46-144.02-72.755-144.61 46.615-15.146z"/>
<path d="m161.46-144.02-143.86-74.228 28.81-39.653z"/>
<path d="m161.46-144.02-160.02 24.507-2.7e-6 -49.014z"/>
<path d="m161.46-144.02-115.05 113.89-28.81-39.653z"/>
<path d="m161.46-144.02-26.14 159.76-46.618-15.146z"/>
</g>
<path transform="matrix(7.0729 0 0 7.4575 73.647 -229.61)" d="m20.588 11.882a8.199 8.199 0 1 1-16.398 0 8.199 8.199 0 1 1 16.398 0z" fill="url(#b)" filter="url(#e)"/>
<path d="m133.31-207.91v55.137h-17.218c-6.602-0.97334-3.1317 2.1508-3.1317 2.1508l23.494 26.472 18.653 21.422c1.9951 2.9976 3.1147 2.8985 6.486 2.8985 3.5137 0.43957 4.2275-0.28033 6.4176-2.757l19.07-21.564 22.666-25.81c3.6888-3.9672-2.8847-2.8126-2.8847-2.8126h-18.954v-54.904c0.65539-9.337-1.0536-9.0538-8.6714-8.7929h-37.608c-7.6308-0.26075-8.3181 0.1211-8.3181 8.5607z" fill="url(#a)" stroke="#0a3b56" stroke-width="5.1532"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

@ -11,7 +11,7 @@ import { getManager } from "./manager/man";
import { select } from "./select";
import { single } from "./single";
import { Notification } from "./notifications";
import { MASK, FASTFILTER } from "./recentlist";
import { MASK, FASTFILTER, SUBFOLDER } from "./recentlist";
import { openManager } from "./windowutils";
import { _ } from "./i18n";
@ -19,6 +19,7 @@ const MAX_BATCH = 10000;
export interface QueueOptions {
mask?: string;
subfolder?: string;
paused?: boolean;
}
@ -28,8 +29,9 @@ export const API = new class APIImpl {
}
async queue(items: BaseItem[], options: QueueOptions) {
await MASK.init();
await Promise.all([MASK.init(), SUBFOLDER.init()]);
const {mask = MASK.current} = options;
const {subfolder = SUBFOLDER.current} = options;
const {paused = false} = options;
const defaults: any = {
@ -46,6 +48,7 @@ export const API = new class APIImpl {
private: false,
postData: null,
mask,
subfolder,
date: Date.now(),
paused
};
@ -117,6 +120,10 @@ export const API = new class APIImpl {
await FASTFILTER.init();
await FASTFILTER.push(options.fast);
}
if (typeof options.subfolder === "string" && !options.subfolderOnce) {
await SUBFOLDER.init();
await SUBFOLDER.push(options.subfolder);
}
if (typeof options.type === "string") {
await Prefs.set("last-type", options.type);
}

View File

@ -19,6 +19,11 @@ import {
// eslint-disable-next-line no-unused-vars
MenuClickInfo,
CHROME,
runtime,
history,
sessions,
// eslint-disable-next-line no-unused-vars
OnInstalled,
} from "./browser";
import { Bus } from "./bus";
import { filterInSitu } from "./util";
@ -45,6 +50,9 @@ const CHROME_CONTEXTS = Object.freeze(new Set([
async function runContentJob(tab: Tab, file: string, msg: any) {
try {
if (tab && tab.incognito && msg) {
msg.private = tab.incognito;
}
const res = await tabs.executeScript(tab.id, {
file,
allFrames: true,
@ -103,7 +111,7 @@ class Handler {
discarded: false,
};
if (!CHROME) {
toptions.hidden = true;
toptions.hidden = false;
}
const selectedTabs = options.allTabs ?
await tabs.query(toptions) as any[] :
@ -129,36 +137,34 @@ class Handler {
}
}
function getMajor(version?: string) {
if (!version) {
return "";
}
const match = version.match(/^\d+\.\d+/);
if (!match) {
return "";
}
return match[0];
}
runtime.onInstalled.addListener(({reason, previousVersion}: OnInstalled) => {
const {version} = runtime.getManifest();
const major = getMajor(version);
const prevMajor = getMajor(previousVersion);
if (reason === "update" && major !== prevMajor) {
tabs.create({
url: `https://about.downthemall.org/changelog/?cur=${major}&prev=${prevMajor}`,
});
}
else if (reason === "install") {
tabs.create({
url: `https://about.downthemall.org/4.0/?cur=${major}`,
});
}
});
locale.then(() => {
new class Action extends Handler {
constructor() {
super();
this.onClicked = this.onClicked.bind(this);
action.onClicked.addListener(this.onClicked);
}
async onClicked(tab: {id: number}) {
if (!tab.id) {
return;
}
try {
await this.processResults(
true,
await runContentJob(
tab, "/bundles/content-gather.js", {
type: "DTA:gather",
selectionOnly: false,
textLinks: await Prefs.get("text-links", true),
schemes: Array.from(ALLOWED_SCHEMES.values()),
transferable: TRANSFERABLE_PROPERTIES,
}));
}
catch (ex) {
console.error(ex);
}
}
}();
const menuHandler = new class Menus extends Handler {
constructor() {
super();
@ -415,7 +421,7 @@ locale.then(() => {
}
}
async enumulate(action: string) {
async emulate(action: string) {
const tab = await tabs.query({
active: true,
currentWindow: true,
@ -537,40 +543,127 @@ locale.then(() => {
}
}();
Bus.on("do-regular", () => menuHandler.enumulate("DTARegular"));
Bus.on("do-regular-all", () => menuHandler.enumulate("DTARegularAll"));
Bus.on("do-turbo", () => menuHandler.enumulate("DTATurbo"));
Bus.on("do-turbo-all", () => menuHandler.enumulate("DTATurboAll"));
new class Action extends Handler {
constructor() {
super();
this.onClicked = this.onClicked.bind(this);
action.onClicked.addListener(this.onClicked);
Prefs.get("button-type", false).then(v => this.adjust(v));
Prefs.on("button-type", (prefs, key, value) => {
this.adjust(value);
});
}
adjust(type: string) {
action.setPopup({
popup: type !== "popup" ? "" : "/windows/popup.html"
});
let icons;
switch (type) {
case "popup":
icons = {
16: "/style/icon16.png",
32: "/style/icon32.png",
48: "/style/icon48.png",
64: "/style/icon64.png",
96: "/style/icon96.png",
128: "/style/icon128.png",
256: "/style/icon256.png"
};
break;
case "dta":
icons = {
16: "/style/button-regular.png",
32: "/style/button-regular@2x.png",
};
break;
case "turbo":
icons = {
16: "/style/button-turbo.png",
32: "/style/button-turbo@2x.png",
};
break;
case "manager":
icons = {
16: "/style/button-manager.png",
32: "/style/button-manager@2x.png",
};
break;
}
action.setIcon({path: icons});
}
async onClicked() {
switch (await Prefs.get("button-type")) {
case "popup":
break;
case "dta":
menuHandler.emulate("DTARegular");
break;
case "turbo":
menuHandler.emulate("DTATurbo");
break;
case "manager":
menuHandler.emulate("DTAManager");
break;
}
}
}();
Bus.on("do-regular", () => menuHandler.emulate("DTARegular"));
Bus.on("do-regular-all", () => menuHandler.emulate("DTARegularAll"));
Bus.on("do-turbo", () => menuHandler.emulate("DTATurbo"));
Bus.on("do-turbo-all", () => menuHandler.emulate("DTATurboAll"));
Bus.on("do-single", () => API.singleRegular(null));
Bus.on("open-manager", () => openManager(true));
Bus.on("open-prefs", () => openPrefs());
function adjustAction(globalTurbo: boolean) {
action.setPopup({
popup: globalTurbo ? "" : "/windows/popup.html"
});
action.setIcon({
path: globalTurbo ? {
16: "/style/button-turbo.png",
32: "/style/button-turbo@2x.png",
} : {
16: "/style/icon16.png",
32: "/style/icon32.png",
48: "/style/icon48.png",
64: "/style/icon64.png",
96: "/style/icon96.png",
128: "/style/icon128.png",
256: "/style/icon256.png"
}
});
}
(async function init() {
await Prefs.set("last-run", new Date());
Prefs.get("global-turbo", false).then(v => adjustAction(v));
Prefs.on("global-turbo", (prefs, key, value) => {
adjustAction(value);
const urlBase = runtime.getURL("");
history.onVisited.addListener(({url}: {url: string}) => {
if (!url || !url.startsWith(urlBase)) {
return;
}
history.deleteUrl({url});
});
const results: {url?: string}[] = await history.search({text: urlBase});
for (const {url} of results) {
if (!url) {
continue;
}
history.deleteUrl({url});
}
if (!CHROME) {
const sessionRemover = async () => {
for (const s of await sessions.getRecentlyClosed()) {
if (s.tab) {
if (s.tab.url.startsWith(urlBase)) {
await sessions.forgetClosedTab(s.tab.windowId, s.tab.sessionId);
}
continue;
}
if (!s.window || !s.window.tabs || s.window.tabs.length > 1) {
continue;
}
const [tab] = s.window.tabs;
if (tab.url.startsWith(urlBase)) {
await sessions.forgetClosedWindow(s.window.sessionId);
}
}
};
sessions.onChanged.addListener(sessionRemover);
await sessionRemover();
}
await Prefs.set("last-run", new Date());
await filters();
await getManager();
})().catch(ex => {

View File

@ -73,7 +73,7 @@ class Numeral implements Generator {
this.digits = dir ? rawpieces[0].length : rawpieces[1].length;
this.length = Math.floor(
(this.stop - this.start + (dir ? 1 : -1)) / this.step);
this.preview = this[Symbol.iterator]().next().value;
this.preview = this[Symbol.iterator]().next().value as string;
Object.freeze(this);
}
@ -93,6 +93,60 @@ class Numeral implements Generator {
}
}
class Character implements Generator {
public readonly start: number;
public readonly stop: number;
public readonly step: number;
public readonly length: number;
public readonly preview: string;
constructor(str: string) {
const rawpieces = str.split(":").map(e => e.trim());
const pieces = rawpieces.map((e, i) => {
if (i === 2) {
return reallyParseInt(e);
}
if (e.length > 1) {
throw new Error("Malformed Character sequence");
}
return e.charCodeAt(0);
});
if (pieces.length < 2) {
throw new Error("Invalid input");
}
const [start, stop, step] = pieces;
if (step === 0) {
throw new Error("Invalid step");
}
this.step = !step ? 1 : step;
const dir = this.step > 0;
if (dir && start > stop) {
throw new Error("Invalid sequence");
}
else if (!dir && start < stop) {
throw new Error("Invalid sequence");
}
this.start = start;
this.stop = stop;
this.length = Math.floor(
(this.stop - this.start + (dir ? 1 : -1)) / this.step);
this.preview = this[Symbol.iterator]().next().value as string;
Object.freeze(this);
}
*[Symbol.iterator]() {
const {start, stop, step} = this;
const dir = step > 0;
for (let i = start; (dir ? i <= stop : i >= stop); i += step) {
yield String.fromCharCode(i);
}
}
}
export class BatchGenerator implements Generator {
private readonly gens: Generator[];
@ -120,9 +174,14 @@ export class BatchGenerator implements Generator {
try {
this.gens.push(new Numeral(tok));
}
catch (ex) {
this.gens.push(new Literal(`[${tok}]`));
this.hasInvalid = true;
catch {
try {
this.gens.push(new Character(tok));
}
catch {
this.gens.push(new Literal(`[${tok}]`));
this.hasInvalid = true;
}
}
}
if (str) {

View File

@ -9,46 +9,112 @@ interface ExtensionListener {
}
export interface MessageSender {
tab?: Tab;
frameId?: number;
id?: number;
url?: string;
tlsChannelId?: string;
readonly tab?: Tab;
readonly frameId?: number;
readonly id?: number;
readonly url?: string;
readonly tlsChannelId?: string;
}
export interface Tab {
id?: number;
readonly id?: number;
readonly incognito?: boolean;
}
export interface MenuClickInfo {
menuItemId: string | number;
button?: number;
linkUrl?: string;
srcUrl?: string;
readonly menuItemId: string | number;
readonly button?: number;
readonly linkUrl?: string;
readonly srcUrl?: string;
}
export interface RawPort {
error: any;
name: string;
onDisconnect: ExtensionListener;
onMessage: ExtensionListener;
sender?: MessageSender;
readonly error: any;
readonly name: string;
readonly sender?: MessageSender;
readonly onDisconnect: ExtensionListener;
readonly onMessage: ExtensionListener;
disconnect: () => void;
postMessage: (message: any) => void;
}
export const {extension} = polyfill;
export const {notifications} = polyfill;
interface WebRequestFilter {
urls?: string[];
}
interface WebRequestListener {
addListener(
callback: Function,
filter: WebRequestFilter,
extraInfoSpec: string[]
): void;
removeListener(callback: Function): void;
}
type Header = {name: string; value: string};
export interface DownloadOptions {
conflictAction: string;
filename?: string;
saveAs: boolean;
url: string;
method?: string;
body?: string;
incognito?: boolean;
headers: Header[];
}
export interface DownloadsQuery {
id?: number;
}
interface Downloads {
download(download: DownloadOptions): Promise<number>;
open(manId: number): Promise<void>;
show(manId: number): Promise<void>;
pause(manId: number): Promise<void>;
resume(manId: number): Promise<void>;
cancel(manId: number): Promise<void>;
erase(query: DownloadsQuery): Promise<void>;
search(query: DownloadsQuery): Promise<any[]>;
getFileIcon(id: number, options?: any): Promise<string>;
setShelfEnabled(state: boolean): void;
removeFile(manId: number): Promise<void>;
readonly onCreated: ExtensionListener;
readonly onChanged: ExtensionListener;
readonly onErased: ExtensionListener;
readonly onDeterminingFilename?: ExtensionListener;
}
interface WebRequest {
readonly onBeforeSendHeaders: WebRequestListener;
readonly onSendHeaders: WebRequestListener;
readonly onHeadersReceived: WebRequestListener;
}
export interface OnInstalled {
readonly reason: string;
readonly previousVersion?: string;
readonly temporary: boolean;
}
export const {browserAction} = polyfill;
export const {contextMenus} = polyfill;
export const {downloads} = polyfill;
export const {downloads}: {downloads: Downloads} = polyfill;
export const {extension} = polyfill;
export const {history} = polyfill;
export const {menus} = polyfill;
export const {notifications} = polyfill;
export const {runtime} = polyfill;
export const {sessions} = polyfill;
export const {storage} = polyfill;
export const {tabs} = polyfill;
export const {webNavigation} = polyfill;
export const {webRequest}: {webRequest: WebRequest} = polyfill;
export const {windows} = polyfill;
export const {theme} = polyfill;
export const CHROME = navigator.appVersion.includes("Chrome/");
export const OPERA = navigator.appVersion.includes("OPR/");

View File

@ -8,32 +8,35 @@ import {runtime, tabs, RawPort, MessageSender} from "./browser";
export class Port extends EventEmitter {
private port: RawPort | null;
private disconnected = false;
constructor(port: RawPort) {
super();
this.port = port;
let disconnected = false;
const disconnect = () => {
if (disconnected) {
return;
}
disconnected = true;
this.port = null; // Break the cycle
this.emit("disconnect", this, port);
};
// Nasty firefox bug, thus listen for tab removal explicitly
if (port.sender && port.sender.tab && port.sender.tab.id) {
const otherTabId = port.sender.tab.id;
const tabListener = function(tabId: number) {
const tabListener = (tabId: number) => {
if (tabId !== otherTabId) {
return;
}
disconnect();
this.disconnect();
};
tabs.onRemoved.addListener(tabListener);
}
port.onMessage.addListener(this.onMessage.bind(this));
port.onDisconnect.addListener(disconnect);
port.onDisconnect.addListener(this.disconnect.bind(this));
}
disconnect() {
if (this.disconnected) {
return;
}
this.disconnected = true;
const {port} = this;
this.port = null; // Break the cycle
this.emit("disconnect", this, port);
}
get name() {
@ -120,6 +123,9 @@ export const Bus = new class extends EventEmitter {
port.disconnect();
return;
}
this.ports.emit(port.name, new Port(port));
const wrapped = new Port(port);
if (!this.ports.emit(port.name, wrapped)) {
wrapped.disconnect();
}
}
}();

230
lib/cdheaderparser.ts Normal file
View File

@ -0,0 +1,230 @@
/**
* (c) 2017 Rob Wu <rob@robwu.nl> (https://robwu.nl)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
/* eslint-disable max-len,no-magic-numbers */
// License: MPL-2
/**
* This typescript port was done by Nils Maier based on
* https://github.com/Rob--W/open-in-browser/blob/83248155b633ed41bc9cdb1205042653e644abd2/extension/content-disposition.js
* Special thanks goes to Rob doing all the heavy lifting and putting
* it together in a reuseable, open source'd library.
*/
const R_RFC6266 = /(?:^|;)\s*filename\*\s*=\s*([^";\s][^;\s]*|"(?:[^"\\]|\\"?)+"?)/i;
const R_RFC5987 = /(?:^|;)\s*filename\s*=\s*([^";\s][^;\s]*|"(?:[^"\\]|\\"?)+"?)/i;
function unquoteRFC2616(value: string) {
if (!value.startsWith("\"")) {
return value;
}
const parts = value.slice(1).split("\\\"");
// Find the first unescaped " and terminate there.
for (let i = 0; i < parts.length; ++i) {
const quotindex = parts[i].indexOf("\"");
if (quotindex !== -1) {
parts[i] = parts[i].slice(0, quotindex);
// Truncate and stop the iteration.
parts.length = i + 1;
}
parts[i] = parts[i].replace(/\\(.)/g, "$1");
}
value = parts.join("\"");
return value;
}
export class CDHeaderParser {
private needsFixup: boolean;
// We need to keep this per instance, because of the global flag.
// Hence we need to reset it after a use.
private R_MULTI = /(?:^|;)\s*filename\*((?!0\d)\d+)(\*?)\s*=\s*([^";\s][^;\s]*|"(?:[^"\\]|\\"?)+"?)/gi;
/**
* Parse a content-disposition header, with relaxed spec tolerance
*
* @param {string} header Header to parse
* @returns {string} Parsed header
*/
parse(header: string) {
this.needsFixup = true;
// filename*=ext-value ("ext-value" from RFC 5987, referenced by RFC 6266).
{
const match = R_RFC6266.exec(header);
if (match) {
const [, tmp] = match;
let filename = unquoteRFC2616(tmp);
filename = unescape(filename);
filename = this.decodeRFC5897(filename);
filename = this.decodeRFC2047(filename);
return this.maybeFixupEncoding(filename);
}
}
// Continuations (RFC 2231 section 3, referenced by RFC 5987 section 3.1).
// filename*n*=part
// filename*n=part
{
const tmp = this.getParamRFC2231(header);
if (tmp) {
// RFC 2047, section
const filename = this.decodeRFC2047(tmp);
return this.maybeFixupEncoding(filename);
}
}
// filename=value (RFC 5987, section 4.1).
{
const match = R_RFC5987.exec(header);
if (match) {
const [, tmp] = match;
let filename = unquoteRFC2616(tmp);
filename = this.decodeRFC2047(filename);
return this.maybeFixupEncoding(filename);
}
}
return "";
}
private maybeDecode(encoding: string, value: string) {
if (!encoding) {
return value;
}
const bytes = Array.from(value, c => c.charCodeAt(0));
if (!bytes.every(code => code <= 0xff)) {
return value;
}
try {
value = new TextDecoder(encoding, {fatal: true}).
decode(new Uint8Array(bytes));
this.needsFixup = false;
}
catch {
// TextDecoder constructor threw - unrecognized encoding.
}
return value;
}
private maybeFixupEncoding(value: string) {
if (!this.needsFixup && /[\x80-\xff]/.test(value)) {
return value;
}
// Maybe multi-byte UTF-8.
value = this.maybeDecode("utf-8", value);
if (!this.needsFixup) {
return value;
}
// Try iso-8859-1 encoding.
return this.maybeDecode("iso-8859-1", value);
}
private getParamRFC2231(value: string) {
const matches: string[][] = [];
// Iterate over all filename*n= and filename*n*= with n being an integer
// of at least zero. Any non-zero number must not start with '0'.
let match;
this.R_MULTI.lastIndex = 0;
while ((match = this.R_MULTI.exec(value)) !== null) {
const [, num, quot, part] = match;
const n = parseInt(num, 10);
if (n in matches) {
// Ignore anything after the invalid second filename*0.
if (n === 0) {
break;
}
continue;
}
matches[n] = [quot, part];
}
const parts: string[] = [];
for (let n = 0; n < matches.length; ++n) {
if (!(n in matches)) {
// Numbers must be consecutive. Truncate when there is a hole.
break;
}
const [quot, rawPart] = matches[n];
let part = unquoteRFC2616(rawPart);
if (quot) {
part = unescape(part);
if (n === 0) {
part = this.decodeRFC5897(part);
}
}
parts.push(part);
}
return parts.join("");
}
private decodeRFC2047(value: string) {
// RFC 2047-decode the result. Firefox tried to drop support for it, but
// backed out because some servers use it - https://bugzil.la/875615
// Firefox's condition for decoding is here:
// eslint-disable-next-line max-len
// https://searchfox.org/mozilla-central/rev/4a590a5a15e35d88a3b23dd6ac3c471cf85b04a8/netwerk/mime/nsMIMEHeaderParamImpl.cpp#742-748
// We are more strict and only recognize RFC 2047-encoding if the value
// starts with "=?", since then it is likely that the full value is
// RFC 2047-encoded.
// Firefox also decodes words even where RFC 2047 section 5 states:
// "An 'encoded-word' MUST NOT appear within a 'quoted-string'."
// eslint-disable-next-line no-control-regex
if (!value.startsWith("=?") || /[\x00-\x19\x80-\xff]/.test(value)) {
return value;
}
// RFC 2047, section 2.4
// encoded-word = "=?" charset "?" encoding "?" encoded-text "?="
// charset = token (but let's restrict to characters that denote a
// possibly valid encoding).
// encoding = q or b
// encoded-text = any printable ASCII character other than ? or space.
// ... but Firefox permits ? and space.
return value.replace(
/=\?([\w-]*)\?([QqBb])\?((?:[^?]|\?(?!=))*)\?=/g,
(_, charset, encoding, text) => {
if (encoding === "q" || encoding === "Q") {
// RFC 2047 section 4.2.
text = text.replace(/_/g, " ");
text = text.replace(/=([0-9a-fA-F]{2})/g,
(_: string, hex: string) => String.fromCharCode(parseInt(hex, 16)));
return this.maybeDecode(charset, text);
}
// else encoding is b or B - base64 (RFC 2047 section 4.1)
try {
text = atob(text);
}
catch {
// ignored
}
return this.maybeDecode(charset, text);
});
}
private decodeRFC5897(extValue: string) {
// Decodes "ext-value" from RFC 5987.
const extEnd = extValue.indexOf("'");
if (extEnd < 0) {
// Some servers send "filename*=" without encoding'language' prefix,
// e.g. in https://github.com/Rob--W/open-in-browser/issues/26
// Let's accept the value like Firefox (57) (Chrome 62 rejects it).
return extValue;
}
const encoding = extValue.slice(0, extEnd);
const langvalue = extValue.slice(extEnd + 1);
// Ignore language (RFC 5987 section 3.2.1, and RFC 6266 section 4.1 ).
return this.maybeDecode(encoding, langvalue.replace(/^[^']*'/, ""));
}
}

View File

@ -2,6 +2,9 @@
// eslint-disable-next-line no-unused-vars
import { BaseItem } from "./item";
// eslint-disable-next-line no-unused-vars
import { Download } from "./manager/download";
import { RUNNING, QUEUED, RETRYING } from "./manager/state";
// License: MIT
@ -69,7 +72,7 @@ export const DB = new class DB {
return await new Promise(this.getAllInternal);
}
saveItemsInternal(items: any[], resolve: Function, reject: Function) {
saveItemsInternal(items: Download[], resolve: Function, reject: Function) {
if (!items || !items.length || !this.db) {
resolve();
return;
@ -83,9 +86,13 @@ export const DB = new class DB {
if (item.private) {
continue;
}
const req = store.put(item.toJSON());
const json = item.toJSON();
if (item.state === RUNNING || item.state === RETRYING) {
json.state = QUEUED;
}
const req = store.put(json);
if (!("dbId" in item) || item.dbId < 0) {
req.onsuccess = () => item.dbId = req.result;
req.onsuccess = () => item.dbId = req.result as number;
}
}
}
@ -94,7 +101,7 @@ export const DB = new class DB {
}
}
async saveItems(items: any[]) {
async saveItems(items: Download[]) {
await this.init();
return await new Promise(this.saveItemsInternal.bind(this, items));
}

View File

@ -9,7 +9,7 @@ import { EventEmitter } from "./events";
import { TYPE_LINK, TYPE_MEDIA, TYPE_ALL } from "./constants";
// eslint-disable-next-line no-unused-vars
import { Overlayable } from "./objectoverlay";
import * as DEFAULT_FILTERS from "../data/filters.json";
import DEFAULT_FILTERS from "../data/filters.json";
import { FASTFILTER } from "./recentlist";
import { _, locale } from "./i18n";
// eslint-disable-next-line no-unused-vars

View File

@ -2,7 +2,7 @@
// License: MIT
import {memoize} from "./memoize";
import * as langs from "../_locales/all.json";
import langs from "../_locales/all.json";
import { sorted, naturalCaseCompare } from "./sorting";

247
lib/imex.ts Normal file
View File

@ -0,0 +1,247 @@
"use strict";
// License: MIT
import { getTextLinks } from "./textlinks";
// eslint-disable-next-line no-unused-vars
import { BaseItem } from "./item";
import { ALLOWED_SCHEMES } from "./constants";
export const NS_METALINK_RFC5854 = "urn:ietf:params:xml:ns:metalink";
export const NS_DTA = "http://www.downthemall.net/properties#";
function parseNum(
file: Element,
attr: string,
defaultValue: number,
ns = NS_METALINK_RFC5854) {
const val = file.getAttributeNS(ns, attr);
if (!val) {
return defaultValue + 1;
}
const num = parseInt(val, 10);
if (isFinite(num)) {
return num;
}
return defaultValue + 1;
}
function importMeta4(data: string) {
const parser = new DOMParser();
const document = parser.parseFromString(data, "text/xml");
const {documentElement} = document;
const items: BaseItem[] = [];
let batch = 0;
for (const file of documentElement.querySelectorAll("file")) {
try {
const url = Array.from(file.querySelectorAll("url")).map(u => {
try {
const {textContent} = u;
if (!textContent) {
return null;
}
const url = new URL(textContent);
if (!ALLOWED_SCHEMES.has(url.protocol)) {
return null;
}
const prio = parseNum(u, "priority", 0);
return {
url,
prio
};
}
catch {
return null;
}
}).filter(u => !!u).reduce((p, c) => {
if (!c) {
return null;
}
if (!p || p.prio < c.prio) {
return c;
}
return p;
});
if (!url) {
continue;
}
batch = parseNum(file, "num", batch, NS_DTA);
const idx = parseNum(file, "idx", 0, NS_DTA);
const item: BaseItem = {
url: url.url.toString(),
usable: decodeURIComponent(url.url.toString()),
batch,
idx
};
const ref = file.getAttributeNS(NS_DTA, "referrer");
if (ref) {
item.referrer = ref;
item.usableReferrer = decodeURIComponent(ref);
}
const mask = file.getAttributeNS(NS_DTA, "mask");
if (mask) {
item.mask = mask;
}
items.push(item);
}
catch (ex) {
console.error("Failed to import file", ex);
}
}
return items;
}
function parseKV(current: BaseItem, line: string) {
const [k, v] = line.split("=", 2);
switch (k.toLocaleLowerCase().trim()) {
case "referer": {
const rurls = getTextLinks(v);
if (rurls && rurls.length) {
current.referrer = rurls.pop();
current.usableReferrer = decodeURIComponent(current.referrer || "");
}
break;
}
}
}
export function importText(data: string) {
if (data.includes(NS_METALINK_RFC5854)) {
return importMeta4(data);
}
const splitter = /(.+)\n|(.+)$/g;
const spacer = /^\s+/;
let match;
let current: BaseItem | undefined = undefined;
let idx = 0;
const items = [];
while ((match = splitter.exec(data)) !== null) {
try {
const line = match[0].trimRight();
if (!line) {
continue;
}
if (spacer.test(line)) {
if (!current) {
continue;
}
parseKV(current, line);
continue;
}
const urls = getTextLinks(line);
if (!urls || !urls.length) {
continue;
}
current = {
url: urls[0],
usable: decodeURIComponent(urls[0]),
idx: ++idx
};
items.push(current);
}
catch (ex) {
current = undefined;
console.error("Failed to import", ex);
}
}
return items;
}
export interface Exporter {
fileName: string;
getText(items: BaseItem[]): string;
}
class TextExporter {
readonly fileName: string;
constructor() {
this.fileName = "links.txt";
}
getText(items: BaseItem[]) {
const lines = [];
for (const item of items) {
lines.push(item.url);
}
return lines.join("\n");
}
}
class Aria2Exporter {
readonly fileName: string;
constructor() {
this.fileName = "links.aria2.txt";
}
getText(items: BaseItem[]) {
const lines = [];
for (const item of items) {
lines.push(item.url);
if (item.referrer) {
lines.push(` referer=${item.referrer}`);
}
}
return lines.join("\n");
}
}
class MetalinkExporter {
readonly fileName: string;
constructor() {
this.fileName = "links.meta4";
}
getText(items: BaseItem[]) {
const document = window.document.implementation.
createDocument(NS_METALINK_RFC5854, "metalink", null);
const root = document.documentElement;
root.setAttributeNS(NS_DTA, "generator", "DownThemAll!");
root.appendChild(document.createComment(
"metalink as exported by DownThemAll!",
));
for (const item of items) {
const aitem = item as any;
const f = document.createElementNS(NS_METALINK_RFC5854, "file");
f.setAttribute("name", aitem.currentName);
if (item.batch) {
f.setAttributeNS(NS_DTA, "num", item.batch.toString());
}
if (item.idx) {
f.setAttributeNS(NS_DTA, "idx", item.idx.toString());
}
if (item.referrer) {
f.setAttributeNS(NS_DTA, "referrer", item.referrer);
}
if (item.mask) {
f.setAttributeNS(NS_DTA, "mask", item.mask);
}
if (item.description) {
const n = document.createElementNS(NS_METALINK_RFC5854, "description");
n.textContent = item.description;
f.appendChild(n);
}
const u = document.createElementNS(NS_METALINK_RFC5854, "url");
u.textContent = item.url;
f.appendChild(u);
if (aitem.totalSize > 0) {
const s = document.createElementNS(NS_METALINK_RFC5854, "size");
s.textContent = aitem.totalSize.toString();
f.appendChild(s);
}
root.appendChild(f);
}
let xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
xml += root.outerHTML;
return xml;
}
}
export const textExporter = new TextExporter();
export const aria2Exporter = new Aria2Exporter();
export const metalinkExporter = new MetalinkExporter();

4
lib/ipreg.ts Normal file
View File

@ -0,0 +1,4 @@
"use strict";
// License: MIT
export const IPReg = /^(?:(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])[.]){3}(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$|^(?:(?:(?:[0-9a-fA-F]{1,4}):){7}(?:(?:[0-9a-fA-F]{1,4})|:)|(?:(?:[0-9a-fA-F]{1,4}):){6}(?:((?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])[.]){3}(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])|:(?:[0-9a-fA-F]{1,4})|:)|(?:(?:[0-9a-fA-F]{1,4}):){5}(?::((?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])[.]){3}(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])|(:(?:[0-9a-fA-F]{1,4})){1,2}|:)|(?:(?:[0-9a-fA-F]{1,4}):){4}(?:(:(?:[0-9a-fA-F]{1,4})){0,1}:((?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])[.]){3}(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])|(:(?:[0-9a-fA-F]{1,4})){1,3}|:)|(?:(?:[0-9a-fA-F]{1,4}):){3}(?:(:(?:[0-9a-fA-F]{1,4})){0,2}:((?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])[.]){3}(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])|(:(?:[0-9a-fA-F]{1,4})){1,4}|:)|(?:(?:[0-9a-fA-F]{1,4}):){2}(?:(:(?:[0-9a-fA-F]{1,4})){0,3}:((?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])[.]){3}(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])|(:(?:[0-9a-fA-F]{1,4})){1,5}|:)|(?:(?:[0-9a-fA-F]{1,4}):){1}(?:(:(?:[0-9a-fA-F]{1,4})){0,4}:((?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])[.]){3}(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])|(:(?:[0-9a-fA-F]{1,4})){1,6}|:)|(?::((?::(?:[0-9a-fA-F]{1,4})){0,5}:((?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])[.]){3}(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])|(?::(?:[0-9a-fA-F]{1,4})){1,7}|:)))(%[0-9a-zA-Z]{1,})?$/;

View File

@ -15,6 +15,7 @@ export interface BaseItem {
batch?: number;
idx: number;
mask?: string;
subfolder?: string;
startDate?: number;
private?: boolean;
postData?: string;
@ -27,6 +28,7 @@ const OPTIONPROPS = Object.freeze([
"fileName",
"batch", "idx",
"mask",
"subfolder",
"startDate",
"private",
"postData",

View File

@ -5,6 +5,8 @@
import { parsePath, URLd } from "../util";
import { QUEUED, RUNNING, PAUSED } from "./state";
import Renamer from "./renamer";
// eslint-disable-next-line no-unused-vars
import { BaseItem } from "../item";
const SAVEDPROPS = [
"state",
@ -14,6 +16,7 @@ const SAVEDPROPS = [
"usableReferrer",
"fileName",
"mask",
"subfolder",
"date",
// batches
"batch",
@ -27,6 +30,9 @@ const SAVEDPROPS = [
"written",
// server stuff
"serverName",
"browserName",
"mime",
"prerolled",
// other options
"private",
// db
@ -39,10 +45,15 @@ const DEFAULTS = {
state: QUEUED,
error: "",
serverName: "",
browserName: "",
fileName: "",
totalSize: 0,
written: 0,
manId: 0,
mime: "",
prerolled: false,
retries: 0,
deadline: 0
};
let sessionId = 0;
@ -59,14 +70,26 @@ export class BaseDownload {
public url: string;
public usable: string;
public uReferrer: URLd;
public referrer: string;
public usableReferrer: string;
public startDate: Date;
public fileName: string;
public description?: string;
public title?: string;
public batch: number;
public idx: number;
public error: string;
public postData: any;
@ -79,10 +102,19 @@ export class BaseDownload {
public serverName: string;
public browserName: string;
public mime: string;
public mask: string;
public subfolder: string;
constructor(options: any) {
public prerolled: boolean;
public retries: number;
constructor(options: BaseItem) {
Object.assign(this, DEFAULTS);
this.assign(options);
if (this.state === RUNNING) {
@ -90,14 +122,16 @@ export class BaseDownload {
}
this.sessionId = ++sessionId;
this.renamer = new Renamer(this);
this.retries = 0;
}
assign(options: any) {
assign(options: BaseItem) {
// eslint-disable-next-line @typescript-eslint/no-this-alias
const self: any = this;
const other: any = options;
for (const prop of SAVEDPROPS) {
if (prop in options) {
self[prop] = options[prop];
self[prop] = other[prop];
}
}
this.uURL = new URL(this.url) as URLd;
@ -115,6 +149,10 @@ export class BaseDownload {
return this.serverName || this.fileName || this.urlName || "index.html";
}
get currentName() {
return this.browserName || this.dest.name || this.finalName;
}
get urlName() {
const path = parsePath(this.uURL);
if (path.name) {
@ -152,8 +190,11 @@ export class BaseDownload {
rv.destName = dest.name;
rv.destPath = dest.path;
rv.destFull = dest.full;
rv.currentName = this.browserName || rv.destName || rv.finalName;
rv.currentFull = `${dest.path}/${rv.currentName}`;
rv.error = this.error;
rv.ext = this.renamer.p_ext;
rv.retries = this.retries;
return rv;
}
}

View File

@ -1,38 +1,43 @@
"use strict";
// License: MIT
import { Prefs } from "../prefs";
import { parsePath, filterInSitu } from "../util";
import {
QUEUED, RUNNING, CANCELED, PAUSED, MISSING, DONE,
FORCABLE, PAUSABLE, CANCELABLE,
} from "./state";
import { BaseDownload } from "./basedownload";
// eslint-disable-next-line no-unused-vars
import { CHROME, downloads, DownloadOptions } from "../browser";
import { Prefs, PrefWatcher } from "../prefs";
import { PromiseSerializer } from "../pserializer";
import { filterInSitu, parsePath } from "../util";
import { BaseDownload } from "./basedownload";
// eslint-disable-next-line no-unused-vars
import { Manager } from "./man";
import { downloads, CHROME } from "../browser";
import { debounce } from "../../uikit/lib/util";
import Renamer from "./renamer";
import {
CANCELABLE,
CANCELED,
DONE,
FORCABLE,
MISSING,
PAUSABLE,
PAUSED,
QUEUED,
RUNNING,
RETRYING
} from "./state";
// eslint-disable-next-line no-unused-vars
import { Preroller, PrerollResults } from "./preroller";
function isRecoverable(error: string) {
switch (error) {
case "SERVER_FAILED":
return true;
const setShelfEnabled = downloads.setShelfEnabled || function() {
// ignored
};
const reenableShelf = debounce(() => setShelfEnabled(true), 1000, true);
type Header = {name: string; value: string};
interface Options {
conflictAction: string;
filename: string;
saveAs: boolean;
url: string;
method?: string;
body?: string;
incognito?: boolean;
headers: Header[];
default:
return error.startsWith("NETWORK_");
}
}
const RETRIES = new PrefWatcher("retries", 5);
const RETRY_TIME = new PrefWatcher("retry-time", 5);
export class Download extends BaseDownload {
public manager: Manager;
@ -44,6 +49,10 @@ export class Download extends BaseDownload {
public error: string;
public dbId: number;
public deadline: number;
constructor(manager: Manager, options: any) {
super(options);
this.manager = manager;
@ -53,6 +62,7 @@ export class Download extends BaseDownload {
}
markDirty() {
this.renamer = new Renamer(this);
this.manager.setDirty(this);
}
@ -74,22 +84,28 @@ export class Download extends BaseDownload {
if (this.manId) {
const {manId: id} = this;
try {
const state = await downloads.search({id});
if (state[0].state === "in_progress") {
const state = (await downloads.search({id})).pop() || {};
if (state.state === "in_progress" && !state.error && !state.paused) {
this.changeState(RUNNING);
this.updateStateFromBrowser();
return;
}
if (!state[0].canResume) {
if (state.state === "complete") {
this.changeState(DONE);
this.updateStateFromBrowser();
return;
}
if (!state.canResume) {
throw new Error("Cannot resume");
}
// Cannot await here
// Firefox bug: will not return until download is finished
downloads.resume(id).catch(() => {});
downloads.resume(id).catch(console.error);
this.changeState(RUNNING);
return;
}
catch (ex) {
console.error("cannot resume", ex);
this.manager.removeManId(this.manId);
this.removeFromBrowser();
}
@ -97,16 +113,31 @@ export class Download extends BaseDownload {
if (this.state !== QUEUED) {
throw new Error("invalid state");
}
console.trace("starting", this.toString(), this.toMsg());
console.log("starting", this.toString(), this.toMsg());
this.changeState(RUNNING);
// Do NOT await
this.reallyStart();
}
private async reallyStart() {
try {
const options: Options = {
if (!this.prerolled) {
await this.maybePreroll();
if (this.state !== RUNNING) {
// Aborted by preroll
return;
}
}
const options: DownloadOptions = {
conflictAction: await Prefs.get("conflict-action"),
filename: this.dest.full,
saveAs: false,
url: this.url,
headers: [],
};
if (!CHROME) {
options.filename = this.dest.full;
}
if (!CHROME && this.private) {
options.incognito = true;
}
@ -120,28 +151,28 @@ export class Download extends BaseDownload {
value: this.referrer
});
}
else if (CHROME) {
options.headers.push({
name: "X-DTA-ID",
value: this.sessionId.toString(),
});
}
if (this.manId) {
this.manager.removeManId(this.manId);
}
setShelfEnabled(false);
try {
try {
this.manager.addManId(
this.manId = await downloads.download(options), this);
}
catch (ex) {
if (!this.referrer) {
throw ex;
}
// Re-attempt without referrer
filterInSitu(options.headers, h => h.name !== "Referer");
this.manager.addManId(
this.manId = await downloads.download(options), this);
}
this.manager.addManId(
this.manId = await downloads.download(options), this);
}
finally {
reenableShelf();
catch (ex) {
if (!this.referrer) {
throw ex;
}
// Re-attempt without referrer
filterInSitu(options.headers, h => h.name !== "Referer");
this.manager.addManId(
this.manId = await downloads.download(options), this);
}
this.markDirty();
}
@ -152,6 +183,45 @@ export class Download extends BaseDownload {
}
}
private async maybePreroll() {
try {
if (this.prerolled) {
// Check again, just in case, async and all
return;
}
const roller = new Preroller(this);
if (!roller.shouldPreroll) {
return;
}
const res = await roller.roll();
if (!res) {
return;
}
this.adoptPrerollResults(res);
}
catch (ex) {
console.error("Failed to preroll", this, ex.toString(), ex.stack, ex);
}
finally {
if (this.state === RUNNING) {
this.prerolled = true;
this.markDirty();
}
}
}
adoptPrerollResults(res: PrerollResults) {
if (res.mime) {
this.mime = res.mime;
}
if (res.name) {
this.serverName = res.name;
}
if (res.error) {
this.cancelAccordingToError(res.error);
}
}
resume(forced = false) {
if (!(FORCABLE & this.state)) {
return;
@ -164,26 +234,41 @@ export class Download extends BaseDownload {
}
}
async pause() {
async pause(retry?: boolean) {
if (!(PAUSABLE & this.state)) {
return;
}
if (!retry) {
this.retries = 0;
this.deadline = 0;
}
else {
// eslint-disable-next-line no-magic-numbers
this.deadline = Date.now() + RETRY_TIME.value * 60 * 1000;
}
if (this.state === RUNNING && this.manId) {
try {
await downloads.pause(this.manId);
}
catch (ex) {
console.error("pause", ex.toString(), ex);
this.cancel();
return;
}
}
this.changeState(PAUSED);
this.changeState(retry ? RETRYING : PAUSED);
}
reset() {
this.prerolled = false;
this.manId = 0;
this.written = this.totalSize = 0;
this.serverName = "";
this.mime = this.serverName = this.browserName = "";
this.retries = 0;
this.deadline = 0;
}
async removeFromBrowser() {
@ -216,6 +301,17 @@ export class Download extends BaseDownload {
this.changeState(CANCELED);
}
async cancelAccordingToError(error: string) {
if (!isRecoverable(error) || ++this.retries > RETRIES.value) {
this.cancel();
this.error = error;
return;
}
await this.pause(true);
this.error = error;
}
setMissing() {
if (this.manId) {
this.manager.removeManId(this.manId);
@ -260,14 +356,19 @@ export class Download extends BaseDownload {
const state = (await downloads.search({id: this.manId})).pop();
const {filename, error} = state;
const path = parsePath(filename);
this.serverName = path.name;
this.browserName = path.name;
this.adoptSize(state);
if (!this.mime && state.mime) {
this.mime = state.mime;
}
this.markDirty();
switch (state.state) {
case "in_progress":
if (error) {
this.cancel();
this.error = error;
if (state.paused) {
this.changeState(PAUSED);
}
else if (error) {
this.cancelAccordingToError(error);
}
else {
this.changeState(RUNNING);
@ -278,6 +379,9 @@ export class Download extends BaseDownload {
if (state.paused) {
this.changeState(PAUSED);
}
else if (error) {
this.cancelAccordingToError(error);
}
else {
this.cancel();
this.error = error || "";
@ -294,4 +398,27 @@ export class Download extends BaseDownload {
this.setMissing();
}
}
updatefromSuggestion(state: any) {
const res: PrerollResults = {};
if (state.mime) {
res.mime = state.mime;
}
if (state.filename) {
res.name = state.filename;
}
if (state.finalUrl) {
res.finalURL = state.finalUrl;
const detected = Preroller.maybeFindNameFromSearchParams(this, res);
if (detected) {
res.name = detected;
}
}
try {
this.adoptPrerollResults(res);
}
finally {
this.markDirty();
}
}
}

View File

@ -4,11 +4,11 @@
import { EventEmitter } from "../events";
import { Notification } from "../notifications";
import { DB } from "../db";
import { QUEUED, CANCELED, RUNNING } from "./state";
import { QUEUED, CANCELED, RUNNING, RETRYING } from "./state";
// eslint-disable-next-line no-unused-vars
import { Bus, Port } from "../bus";
import { sort } from "../sorting";
import { Prefs } from "../prefs";
import { Prefs, PrefWatcher } from "../prefs";
import { _ } from "../i18n";
import { CoalescedUpdate, mapFilterInSitu, filterInSitu } from "../util";
import { PromiseSerializer } from "../pserializer";
@ -16,8 +16,9 @@ import { Download } from "./download";
import { ManagerPort } from "./port";
import { Scheduler } from "./scheduler";
import { Limits } from "./limits";
import { downloads, runtime } from "../browser";
import { downloads, runtime, webRequest, CHROME, OPERA } from "../browser";
const US = runtime.getURL("");
const AUTOSAVE_TIMEOUT = 2000;
const DIRTY_TIMEOUT = 100;
@ -25,11 +26,17 @@ const DIRTY_TIMEOUT = 100;
const MISSING_TIMEOUT = 12 * 1000;
const RELOAD_TIMEOUT = 10 * 1000;
const setShelfEnabled = downloads.setShelfEnabled || function() {
// ignored
};
const FINISH_NOTIFICATION = new PrefWatcher("finish-notification", true);
const SOUNDS = new PrefWatcher("sounds", false);
export class Manager extends EventEmitter {
private items: Download[];
private active: boolean;
public active: boolean;
private notifiedFinished: boolean;
@ -45,11 +52,18 @@ export class Manager extends EventEmitter {
private readonly running: Set<Download>;
private readonly retrying: Set<Download>;
private scheduler: Scheduler | null;
private shouldReload: boolean;
private deadlineTimer: number;
constructor() {
if (!document.location.href.includes("background")) {
throw new Error("Not on background");
}
super();
this.active = true;
this.shouldReload = false;
@ -59,16 +73,22 @@ export class Manager extends EventEmitter {
AUTOSAVE_TIMEOUT, this.save.bind(this));
this.dirty = new CoalescedUpdate(
DIRTY_TIMEOUT, this.processDirty.bind(this));
this.processDeadlines = this.processDeadlines.bind(this);
this.sids = new Map();
this.manIds = new Map();
this.ports = new Set();
this.scheduler = null;
this.running = new Set();
this.retrying = new Set();
this.startNext = PromiseSerializer.wrapNew(1, this, this.startNext);
downloads.onChanged.addListener(this.onChanged.bind(this));
downloads.onErased.addListener(this.onErased.bind(this));
if (CHROME && downloads.onDeterminingFilename) {
downloads.onDeterminingFilename.addListener(
this.onDeterminingFilename.bind(this));
}
Bus.onPort("manager", (port: Port) => {
const mport = new ManagerPort(this, port);
@ -76,10 +96,19 @@ export class Manager extends EventEmitter {
this.ports.delete(mport);
});
this.ports.add(mport);
return true;
});
Limits.on("changed", () => {
this.resetScheduler();
});
if (CHROME) {
webRequest.onBeforeSendHeaders.addListener(
this.stuffReferrer.bind(this),
{urls: ["<all_urls>"]},
["blocking", "requestHeaders", "extraHeaders"]
);
}
}
async init() {
@ -93,7 +122,10 @@ export class Manager extends EventEmitter {
}
this.items.push(rv);
});
await this.resetScheduler();
// Do not wait for the scheduler
this.resetScheduler();
this.emit("inited");
setTimeout(() => this.checkMissing(), MISSING_TIMEOUT);
runtime.onUpdateAvailable.addListener(() => {
@ -133,6 +165,20 @@ export class Manager extends EventEmitter {
this.manIds.delete(downloadId);
}
onDeterminingFilename(state: any, suggest: Function) {
const download = this.manIds.get(state.id);
if (!download) {
return;
}
try {
download.updatefromSuggestion(state);
}
finally {
const suggestion = {filename: download.dest.full};
suggest(suggestion);
}
}
async resetScheduler() {
this.scheduler = null;
await this.startNext();
@ -148,7 +194,7 @@ export class Manager extends EventEmitter {
}
const next = await this.scheduler.next(this.running);
if (!next) {
this.maybeNotifyFinished();
this.maybeRunFinishActions();
break;
}
if (this.running.has(next) || next.state !== QUEUED) {
@ -168,20 +214,18 @@ export class Manager extends EventEmitter {
async startDownload(download: Download) {
// Add to running first, so we don't confuse the scheduler and other parts
this.running.add(download);
setShelfEnabled(false);
await download.start();
this.notifiedFinished = false;
}
async maybeNotifyFinished() {
if (!(await Prefs.get("finish-notification"))) {
maybeRunFinishActions() {
if (this.running.size) {
return;
}
if (this.notifiedFinished || this.running.size) {
return;
}
this.notifiedFinished = true;
new Notification(null, _("queue-finished"));
this.maybeNotifyFinished();
if (this.shouldReload) {
this.saveQueue.trigger();
setTimeout(() => {
if (this.running.size) {
return;
@ -189,6 +233,24 @@ export class Manager extends EventEmitter {
runtime.reload();
}, RELOAD_TIMEOUT);
}
setShelfEnabled(true);
}
maybeNotifyFinished() {
if (this.notifiedFinished || this.running.size || this.retrying.size) {
return;
}
if (SOUNDS.value && !OPERA) {
const audio = new Audio(runtime.getURL("/style/done.opus"));
audio.addEventListener("canplaythrough", () => audio.play());
audio.addEventListener("ended", () => document.body.removeChild(audio));
audio.addEventListener("error", () => document.body.removeChild(audio));
document.body.appendChild(audio);
}
if (FINISH_NOTIFICATION.value) {
new Notification(null, _("queue-finished"));
}
this.notifiedFinished = true;
}
addManId(id: number, download: Download) {
@ -236,7 +298,7 @@ export class Manager extends EventEmitter {
this.emit("dirty", items);
}
save(items: Download[]) {
private save(items: Download[]) {
DB.saveItems(items.filter(i => !i.removed)).
catch(console.error);
}
@ -287,6 +349,10 @@ export class Manager extends EventEmitter {
if (oldState === RUNNING) {
this.running.delete(download);
}
else if (oldState === RETRYING) {
this.retrying.delete(download);
this.findDeadline();
}
if (newState === QUEUED) {
this.resetScheduler();
this.startNext().catch(console.error);
@ -298,10 +364,56 @@ export class Manager extends EventEmitter {
this.running.add(download);
}
else {
if (newState === RETRYING) {
this.addRetry(download);
}
this.startNext().catch(console.error);
}
}
addRetry(download: Download) {
this.retrying.add(download);
this.findDeadline();
}
private findDeadline() {
let deadline = Array.from(this.retrying).
reduce<number>((deadline, item) => {
if (deadline) {
return item.deadline ? Math.min(deadline, item.deadline) : deadline;
}
return item.deadline;
}, 0);
if (deadline <= 0) {
return;
}
deadline -= Date.now();
if (deadline <= 0) {
return;
}
if (this.deadlineTimer) {
window.clearTimeout(this.deadlineTimer);
}
this.deadlineTimer = window.setTimeout(this.processDeadlines, deadline);
}
private processDeadlines() {
this.deadlineTimer = 0;
try {
const now = Date.now();
this.items.forEach(item => {
if (item.deadline && Math.abs(item.deadline - now) < 1000) {
this.retrying.delete(item);
item.resume(false);
}
});
}
finally {
this.findDeadline();
}
}
sorted(sids: number[]) {
try {
// Construct new items
@ -361,6 +473,35 @@ export class Manager extends EventEmitter {
}
this.emit("active", this.active);
}
getMsgItems() {
return this.items.map(e => e.toMsg());
}
stuffReferrer(details: any): any {
if (details.tabId > 0 && !US.startsWith(details.initiator)) {
return undefined;
}
const sidx = details.requestHeaders.findIndex(
(e: any) => e.name.toLowerCase() === "x-dta-id");
if (sidx < 0) {
return undefined;
}
const sid = parseInt(details.requestHeaders[sidx].value, 10);
details.requestHeaders.splice(sidx, 1);
const item = this.sids.get(sid);
if (!item) {
return undefined;
}
details.requestHeaders.push({
name: "Referer",
value: (item.uReferrer || item.uURL).toString()
});
const rv: any = {
requestHeaders: details.requestHeaders
};
return rv;
}
}
let inited: Promise<Manager>;

View File

@ -5,6 +5,12 @@ import { donate, openPrefs } from "../windowutils";
import { API } from "../api";
// eslint-disable-next-line no-unused-vars
import { BaseDownload } from "./basedownload";
// eslint-disable-next-line no-unused-vars
import { Manager } from "./man";
// eslint-disable-next-line no-unused-vars
import { Port } from "../bus";
// eslint-disable-next-line no-unused-vars
import { BaseItem } from "../item";
type SID = {sid: number};
type SIDS = {
@ -13,9 +19,9 @@ type SIDS = {
};
export class ManagerPort {
private manager: any;
private manager: Manager;
private port: any;
private port: Port;
constructor(manager: any, port: any) {
this.manager = manager;
@ -38,6 +44,9 @@ export class ManagerPort {
port.on("prefs", () => {
openPrefs();
});
port.on("import", ({items}: {items: BaseItem[]}) => {
API.regular(items, []);
});
port.on("all", () => this.sendAll());
port.on("removeSids", this.onMsgRemoveSids);
port.on("showSingle", async () => {
@ -79,7 +88,6 @@ export class ManagerPort {
}
sendAll() {
this.port.post(
"all", this.manager.items.map((e: BaseDownload) => e.toMsg()));
this.port.post("all", this.manager.getMsgItems());
}
}

252
lib/manager/preroller.ts Normal file
View File

@ -0,0 +1,252 @@
"use strict";
// License: MIT
import MimeType from "whatwg-mimetype";
// eslint-disable-next-line no-unused-vars
import { Download } from "./download";
import { CHROME, webRequest } from "../browser";
import { CDHeaderParser } from "../cdheaderparser";
import { sanitizePath, parsePath } from "../util";
import { MimeDB } from "../mime";
const PREROLL_HEURISTICS = /dl|attach|download|name|file|get|retr|^n$|\.(php|asp|py|pl|action|htm|shtm)/i;
const PREROLL_HOSTS = /4cdn|chan/;
const PREROLL_TIMEOUT = 10000;
const PREROLL_NOPE = new Set<string>();
/* eslint-disable no-magic-numbers */
const NOPE_STATUSES = Object.freeze(new Set([
400,
401,
402,
405,
416,
]));
/* eslint-enable no-magic-numbers */
const PREROLL_SEARCHEXTS = Object.freeze(new Set<string>([
"php",
"asp",
"aspx",
"inc",
"py",
"pl",
"action",
"htm",
"html",
"shtml"
]));
const NAME_TESTER = /\.[a-z0-9]{1,5}$/i;
const CDPARSER = new CDHeaderParser();
export interface PrerollResults {
error?: string;
name?: string;
mime?: string;
finalURL?: string;
}
export class Preroller {
private readonly download: Download
constructor(download: Download) {
this.download = download;
}
get shouldPreroll() {
if (CHROME) {
return false;
}
const {uURL, renamer} = this.download;
const {pathname, search, host} = uURL;
if (PREROLL_NOPE.has(host)) {
return false;
}
if (!renamer.p_ext) {
return true;
}
if (search.length) {
return true;
}
if (uURL.pathname.endsWith("/")) {
return true;
}
if (PREROLL_HEURISTICS.test(pathname)) {
return true;
}
if (PREROLL_HOSTS.test(host)) {
return true;
}
return false;
}
async roll() {
try {
return await (CHROME ? this.prerollChrome() : this.prerollFirefox());
}
catch (ex) {
console.error("Failed to preroll", this, ex.toString(), ex.stack, ex);
}
return null;
}
private async prerollFirefox() {
const controller = new AbortController();
const {signal} = controller;
const {uURL, uReferrer} = this.download;
const res = await fetch(uURL.toString(), {
method: "GET",
headers: new Headers({
Range: "bytes=0-1",
}),
mode: "same-origin",
signal,
referrer: (uReferrer || uURL).toString(),
});
if (res.body) {
res.body.cancel();
}
controller.abort();
const {headers} = res;
return this.finalize(headers, res);
}
private async prerollChrome() {
let rid = "";
const {uURL, uReferrer} = this.download;
const rurl = uURL.toString();
let listener: any;
const wr = new Promise<any[]>(resolve => {
listener = (details: any) => {
const {url, requestId, statusCode} = details;
if (rid !== requestId && url !== rurl) {
return;
}
// eslint-disable-next-line no-magic-numbers
if (statusCode >= 300 && statusCode < 400) {
// Redirect, continue tracking;
rid = requestId;
return;
}
resolve(details.responseHeaders);
};
webRequest.onHeadersReceived.addListener(
listener, {urls: ["<all_urls>"]}, ["responseHeaders"]);
});
const p = Promise.race([
wr,
new Promise<any[]>((_, reject) =>
setTimeout(() => reject(new Error("timeout")), PREROLL_TIMEOUT))
]);
p.finally(() => {
webRequest.onHeadersReceived.removeListener(listener);
});
const controller = new AbortController();
const {signal} = controller;
const res = await fetch(rurl, {
method: "GET",
headers: new Headers({
"Range": "bytes=0-1",
"X-DTA-ID": this.download.sessionId.toString(),
}),
signal,
referrer: (uReferrer || uURL).toString(),
});
if (res.body) {
res.body.cancel();
}
controller.abort();
const headers = await p;
return this.finalize(
new Headers(headers.map(i => [i.name, i.value])), res);
}
private finalize(headers: Headers, res: Response): PrerollResults {
const rv: PrerollResults = {};
const type = MimeType.parse(headers.get("content-type") || "");
if (type) {
rv.mime = type.essence;
}
const dispHeader = headers.get("content-disposition");
if (dispHeader) {
const file = CDPARSER.parse(dispHeader);
// Sanitize
rv.name = sanitizePath(file.replace(/[/\\]+/g, "-"));
}
else {
const detected = Preroller.maybeFindNameFromSearchParams(
this.download, rv);
if (detected) {
rv.name = detected;
}
}
rv.finalURL = res.url;
/* eslint-disable no-magic-numbers */
const {status} = res;
if (status === 404) {
rv.error = "SERVER_BAD_CONTENT";
}
else if (status === 403) {
rv.error = "SERVER_FORBIDDEN";
}
else if (status === 402 || status === 407) {
rv.error = "SERVER_UNAUTHORIZED";
}
else if (NOPE_STATUSES.has(status)) {
PREROLL_NOPE.add(this.download.uURL.host);
if (PREROLL_NOPE.size > 1000) {
PREROLL_NOPE.delete(PREROLL_NOPE.keys().next().value);
}
}
else if (status > 400 && status < 500) {
rv.error = "SERVER_FAILED";
}
/* eslint-enable no-magic-numbers */
return rv;
}
static maybeFindNameFromSearchParams(
download: Download, res: PrerollResults) {
const {p_ext: ext} = download.renamer;
if (ext && !PREROLL_SEARCHEXTS.has(ext.toLocaleLowerCase())) {
return undefined;
}
return Preroller.findNameFromSearchParams(download.uURL, res.mime);
}
static findNameFromSearchParams(url: URL, mimetype?: string) {
const {searchParams} = url;
let detected = "";
for (const [, value] of searchParams) {
if (!NAME_TESTER.test(value)) {
continue;
}
const p = parsePath(value);
if (!p.base || !p.ext) {
continue;
}
if (!MimeDB.hasExtension(p.ext)) {
continue;
}
if (mimetype) {
const mime = MimeDB.getMime(mimetype);
if (mime && !mime.extensions.has(p.ext.toLowerCase())) {
continue;
}
}
const sanitized = sanitizePath(p.name);
if (sanitized.length <= detected.length) {
continue;
}
detected = sanitized;
}
return detected;
}
}

View File

@ -2,8 +2,12 @@
"use strict";
// License: MIT
import { parsePath, sanitizePath } from "../util";
import { _ } from "../i18n";
import { MimeDB } from "../mime";
// eslint-disable-next-line no-unused-vars
import { parsePath, PathInfo, sanitizePath } from "../util";
// eslint-disable-next-line no-unused-vars
import { BaseDownload } from "./basedownload";
const REPLACE_EXPR = /\*\w+\*/gi;
@ -22,21 +26,41 @@ const DATE_FORMATTER = new Intl.NumberFormat(undefined, {
});
export default class Renamer {
private readonly d: any;
private readonly d: BaseDownload;
constructor(download: any) {
private readonly nameinfo: PathInfo;
constructor(download: BaseDownload) {
this.d = download;
const info = parsePath(this.d.finalName);
this.nameinfo = this.fixupExtension(info);
}
get nameinfo() {
return parsePath(this.d.finalName);
private fixupExtension(info: PathInfo): PathInfo {
if (!this.d.mime) {
return info;
}
const mime = MimeDB.getMime(this.d.mime);
if (!mime) {
return info;
}
const {ext} = info;
if (mime.major === "image" || mime.major === "video") {
if (ext && mime.extensions.has(ext.toLowerCase())) {
return info;
}
return new PathInfo(info.base, mime.primary, info.path);
}
if (ext) {
return info;
}
return new PathInfo(info.base, mime.primary, info.path);
}
get ref() {
return this.d.uReferrer;
}
get p_name() {
return this.nameinfo.base;
}
@ -169,24 +193,24 @@ export default class Renamer {
}
toString() {
const {mask} = this.d;
const {mask, subfolder} = this.d;
// eslint-disable-next-line @typescript-eslint/no-this-alias
const self: any = this;
// XXX flat
return sanitizePath(mask.replace(REPLACE_EXPR, function(type: string) {
const baseMask = subfolder ? `${subfolder}/${mask}` : mask;
return sanitizePath(baseMask.replace(REPLACE_EXPR, function(type: string) {
let prop = type.substr(1, type.length - 2);
const flat = prop.startsWith("flat");
if (flat) {
prop = prop.substr(4);
}
prop = `p_${prop}`;
const rv = (prop in self) ?
let rv = (prop in self) ?
(self[prop] || "").trim() :
type;
if (flat) {
return rv.replace(/\/+/g, "-");
rv = rv.replace(/[/\\]+/g, "-");
}
return rv;
return rv.replace(/\/{2,}/g, "/");
}));
}
}

View File

@ -8,8 +8,9 @@ export const PAUSED = 1 << 3;
export const DONE = 1 << 4;
export const CANCELED = 1 << 5;
export const MISSING = 1 << 6;
export const RETRYING = 1 << 7;
export const RESUMABLE = PAUSED | CANCELED;
export const FORCABLE = PAUSED | QUEUED | CANCELED;
export const PAUSABLE = QUEUED | CANCELED | RUNNING;
export const CANCELABLE = QUEUED | RUNNING | PAUSED | DONE | MISSING;
export const RESUMABLE = PAUSED | CANCELED | RETRYING;
export const FORCABLE = PAUSED | QUEUED | CANCELED | RETRYING;
export const PAUSABLE = QUEUED | CANCELED | RUNNING | RETRYING;
export const CANCELABLE = QUEUED | RUNNING | PAUSED | DONE | MISSING | RETRYING;

65
lib/mime.ts Normal file
View File

@ -0,0 +1,65 @@
"use strict";
// License: MIT
import mime from "../data/mime.json";
export class MimeInfo {
public readonly type: string;
public readonly extensions: Set<string>;
public readonly major: string;
public readonly minor: string;
public readonly primary: string;
constructor(type: string, extensions: string[]) {
this.type = type;
const [major, minor] = type.split("/", 2);
this.major = major;
this.minor = minor;
[this.primary] = extensions;
this.extensions = new Set(extensions);
Object.freeze(this);
}
}
export const MimeDB = new class MimeDB {
private readonly mimeToExts: Map<string, MimeInfo>;
private readonly registeredExtensions: Set<string>;
constructor() {
const exts = new Map<string, string[]>();
for (const [prim, more] of Object.entries(mime.e)) {
let toadd = more;
if (!Array.isArray(toadd)) {
toadd = [toadd];
}
toadd.unshift(prim);
exts.set(prim, toadd);
}
this.mimeToExts = new Map(Array.from(
Object.entries(mime.m),
([mime, prim]) => [mime, new MimeInfo(mime, exts.get(prim) || [prim])]
));
const all = Array.from(
this.mimeToExts.values(),
m => Array.from(m.extensions, e => e.toLowerCase()));
this.registeredExtensions = new Set(all.flat());
}
getPrimary(mime: string) {
const info = this.mimeToExts.get(mime.trim().toLocaleLowerCase());
return info ? info.primary : "";
}
getMime(mime: string) {
return this.mimeToExts.get(mime.trim().toLocaleLowerCase());
}
hasExtension(ext: string) {
return this.registeredExtensions.has(ext.toLowerCase());
}
}();

View File

@ -1,9 +1,9 @@
"use strict";
// License: MIT
import * as DEFAULT_PREFS from "../data/prefs.json";
import DEFAULT_PREFS from "../data/prefs.json";
import { EventEmitter } from "./events";
import {loadOverlay} from "./objectoverlay";
import { loadOverlay } from "./objectoverlay";
import { storage } from "./browser";
const PREFS = Symbol("PREFS");
@ -99,6 +99,5 @@ export class PrefWatcher {
changed(prefs: any, key: string, value: any) {
this.value = value;
return true;
}
}

View File

@ -116,3 +116,9 @@ export const FASTFILTER = new RecentList("fastfilter", [
"*.z??, *.css, *.html"
]);
FASTFILTER.init().catch(console.error);
export const SUBFOLDER = new RecentList("subfolder", [
"",
"downthemall",
]);
SUBFOLDER.init().catch(console.error);

View File

@ -9,11 +9,12 @@ import { donate, openPrefs, openUrls } from "./windowutils";
// eslint-disable-next-line no-unused-vars
import { filters, FAST, Filter } from "./filters";
import { WindowStateTracker } from "./windowstatetracker";
import { windows } from "./browser";
import { windows, CHROME } from "./browser";
// eslint-disable-next-line no-unused-vars
import { BaseItem } from "./item";
interface BaseMatchedItem extends BaseItem {
sidx?: number;
matched?: string | null;
prevMatched?: string | null;
}
@ -28,7 +29,8 @@ function computeSelection(
items: BaseMatchedItem[],
onlyFast: boolean): ItemDelta[] {
let ws = items.map((item, idx: number) => {
item.idx = idx;
item.idx = item.idx || idx;
item.sidx = item.sidx || idx;
const {matched = null} = item;
item.prevMatched = matched;
item.matched = null;
@ -52,7 +54,7 @@ function computeSelection(
}
return items.filter(item => item.prevMatched !== item.matched).map(item => {
return {
idx: item.idx,
idx: item.sidx as number,
matched: item.matched
};
});
@ -98,9 +100,16 @@ export async function select(links: BaseItem[], media: BaseItem[]) {
type: "popup",
});
const window = await windows.create(windowOptions);
tracker.track(window.id);
try {
if (!CHROME) {
windows.update(window.id, tracker.getOptions({}));
}
const port = await Promise.race<Port>([
new Promise<Port>(resolve => Bus.oncePort("select", resolve)),
new Promise<Port>(resolve => Bus.oncePort("select", port => {
resolve(port);
return true;
})),
timeout<Port>(5 * 1000)]);
if (!port.isSelf) {
throw Error("Invalid sender connected");
@ -186,8 +195,8 @@ export async function select(links: BaseItem[], media: BaseItem[]) {
openPrefs();
});
port.on("openUrls", ({urls}) => {
openUrls(urls);
port.on("openUrls", ({urls, incognito}) => {
openUrls(urls, incognito);
});
try {

View File

@ -6,7 +6,7 @@ import { Bus, Port } from "./bus";
import { WindowStateTracker } from "./windowstatetracker";
import { Promised, timeout } from "./util";
import { donate } from "./windowutils";
import { windows } from "./browser";
import { windows, CHROME } from "./browser";
// eslint-disable-next-line no-unused-vars
import { BaseItem } from "./item";
@ -21,9 +21,16 @@ export async function single(item: BaseItem | null) {
type: "popup",
});
const window = await windows.create(windowOptions);
tracker.track(window.id);
try {
if (!CHROME) {
windows.update(window.id, tracker.getOptions({}));
}
const port: Port = await Promise.race<Port>([
new Promise<Port>(resolve => Bus.oncePort("single", resolve)),
new Promise<Port>(resolve => Bus.oncePort("single", port => {
resolve(port);
return true;
})),
timeout<Port>(5 * 1000)]);
if (!port.isSelf) {
throw Error("Invalid sender connected");

View File

@ -2,8 +2,9 @@
// License: MIT
import * as psl from "psl";
import {memoize, identity} from "./memoize";
export {debounce} from "../uikit/lib/util";
import { identity, memoize } from "./memoize";
import { IPReg } from "./ipreg";
export { debounce } from "../uikit/lib/util";
export class Promised {
private promise: Promise<any>;
@ -96,8 +97,72 @@ export const IS_WIN = typeof navigator !== "undefined" &&
export const sanitizePath = identity(
IS_WIN ? sanitizePathWindows : sanitizePathGeneric);
export class PathInfo {
private baseField: string;
private extField: string;
private pathField: string;
private nameField: string;
private fullField: string;
constructor(base: string, ext: string, path: string) {
this.baseField = base;
this.extField = ext;
this.pathField = path;
this.update();
}
get base() {
return this.baseField;
}
set base(nv) {
this.baseField = sanitizePath(nv);
this.update();
}
get ext() {
return this.extField;
}
set ext(nv) {
this.extField = sanitizePath(nv);
this.update();
}
get name() {
return this.nameField;
}
get path() {
return this.pathField;
}
set path(nv) {
this.pathField = sanitizePath(nv);
this.update();
}
get full() {
return this.fullField;
}
private update() {
this.nameField = this.extField ? `${this.baseField}.${this.extField}` : this.baseField;
this.fullField = this.pathField ? `${this.pathField}/${this.nameField}` : this.nameField;
}
clone() {
return new PathInfo(this.baseField, this.extField, this.pathField);
}
}
// XXX cleanup + test
export const parsePath = memoize(function parsePath(path: string | URL) {
export const parsePath = memoize(function parsePath(
path: string | URL): PathInfo {
if (path instanceof URL) {
path = decodeURIComponent(path.pathname);
}
@ -127,13 +192,7 @@ export const parsePath = memoize(function parsePath(path: string | URL) {
}
path = pieces.join("/");
return {
path,
name,
base,
ext,
full: path ? `${path}/${name}` : name
};
return new PathInfo(base, ext, path);
});
export class CoalescedUpdate<T> extends Set<T> {
@ -179,7 +238,10 @@ export interface URLd extends URL {
Object.defineProperty(URL.prototype, "domain", {
get() {
try {
return hostToDomain(this.host) || this.host;
const {hostname} = this;
return IPReg.test(hostname) ?
hostname :
hostToDomain(hostname) || hostname;
}
catch (ex) {
console.error(ex);
@ -299,3 +361,20 @@ export function mapFilterInSitu<TRes, T>(
export function randint(min: number, max: number) {
return Math.floor(Math.random() * (max - min)) + min;
}
export function validateSubFolder(folder: string) {
if (!folder) {
return;
}
folder = folder.replace(/[/\\]+/g, "/");
if (folder.startsWith("/")) {
throw new Error("error.noabsolutepath");
}
if (/^[a-z]:\//i.test(folder)) {
throw new Error("error.noabsolutepath");
}
if (/^\.+\/|\/\.+\/|\/\.+$/g.test(folder)) {
throw new Error("error.nodotsinpath");
}
}

View File

@ -3,6 +3,8 @@
import { Prefs } from "./prefs";
import { windows } from "./browser";
// eslint-disable-next-line no-unused-vars
import { Port } from "./bus";
const VALID_WINDOW_STATES = Object.freeze(new Set(["normal", "maximized"]));
@ -55,13 +57,15 @@ export class WindowStateTracker {
getOptions(options: any) {
const result = Object.assign(options, {
width: this.width,
height: this.height,
state: this.state,
});
if (this.top >= 0) {
result.top = this.top;
result.left = this.left;
if (result.state !== "maximized") {
result.width = this.width;
result.height = this.height;
if (this.top >= 0) {
result.top = this.top;
result.left = this.left;
}
}
return result;
}
@ -78,34 +82,48 @@ export class WindowStateTracker {
if (!this.windowId) {
return;
}
const window = await windows.get(this.windowId);
if (!VALID_WINDOW_STATES.has(window.state)) {
return;
try {
const window = await windows.get(this.windowId);
if (!VALID_WINDOW_STATES.has(window.state)) {
return;
}
const previous = JSON.stringify(this);
this.width = window.width;
this.height = window.height;
this.left = window.left;
this.top = window.top;
this.state = window.state;
this.validate();
if (previous === JSON.stringify(this)) {
// Nothing changed
return;
}
await this.save();
}
const previous = JSON.stringify(this);
this.width = window.width;
this.height = window.height;
this.left = window.left;
this.top = window.top;
this.state = window.state;
this.validate();
if (previous === JSON.stringify(this)) {
// Nothing changed
return;
catch {
// ignored
}
await this.save();
}
track(windowId: number, port: any) {
track(windowId: number, port?: Port) {
if (port) {
port.on("resized", this.update);
port.on("unload", e => this.finalize(e));
port.on("disconnect", this.finalize.bind(this));
}
this.windowId = windowId;
}
async finalize() {
async finalize(state?: any) {
if (state) {
this.left = state.left;
this.top = state.top;
}
await this.update();
this.windowId = 0;
if (state) {
await this.save();
}
}
async save() {

View File

@ -1,44 +1,61 @@
"use strict";
// License: MIT
import { windows, tabs, runtime } from "../lib/browser";
import {getManager} from "./manager/man";
import * as DEFAULT_ICONS from "../data/icons.json";
import { windows, tabs, runtime, CHROME } from "../lib/browser";
import { getManager } from "./manager/man";
import DEFAULT_ICONS from "../data/icons.json";
import { Prefs } from "./prefs";
import { _ } from "./i18n";
import { WindowStateTracker } from "./windowstatetracker";
// eslint-disable-next-line no-unused-vars
import { Port, Bus } from "./bus";
import { timeout } from "./util";
const DONATE_URL = "https://www.downthemall.org/howto/donate/";
const DONATE_LANG_URLS = Object.freeze(new Map([
["de", "https://www.downthemall.org/howto/donate/spenden/"],
]));
const MANAGER_URL = "/windows/manager.html";
export async function mostRecentBrowser(): Promise<any> {
export async function mostRecentBrowser(incognito: boolean): Promise<any> {
let window;
try {
window = await windows.getCurrent({windowTypes: ["normal"]});
window = await windows.getCurrent();
if (window.type !== "normal") {
throw new Error("not a normal window");
}
if (incognito && !window.incognito) {
throw new Error("Not incognito");
}
}
catch {
try {
window = await windows.getlastFocused({windowTypes: ["normal"]});
window = await windows.getlastFocused();
if (window.type !== "normal") {
throw new Error("not a normal window");
}
if (incognito && !window.incognito) {
throw new Error("Not incognito");
}
}
catch {
window = Array.from(await windows.getAll({windowTypes: ["normal"]})).
filter((w: any) => w.type === "normal").pop();
filter(
(w: any) => w.type === "normal" && !!w.incognito === !!incognito).
pop();
}
}
if (!window) {
window = await windows.create({
url: DONATE_URL,
incognito: !!incognito,
type: "normal",
});
}
return window;
}
export async function openInTab(url: string) {
const window = await mostRecentBrowser();
export async function openInTab(url: string, incognito: boolean) {
const window = await mostRecentBrowser(incognito);
await tabs.create({
active: true,
url,
@ -47,7 +64,7 @@ export async function openInTab(url: string) {
await windows.update(window.id, {focused: true});
}
export async function openInTabOrFocus(url: string) {
export async function openInTabOrFocus(url: string, incognito: boolean) {
const etabs = await tabs.query({
url
});
@ -57,21 +74,22 @@ export async function openInTabOrFocus(url: string) {
await windows.update(tab.windowId, {focused: true});
return;
}
await openInTab(url);
await openInTab(url, incognito);
}
export async function maybeOpenInTab(url: string) {
export async function maybeOpenInTab(url: string, incognito: boolean) {
const etabs = await tabs.query({
url
});
if (etabs.length) {
return;
}
await openInTab(url);
await openInTab(url, incognito);
}
export async function donate() {
await openInTab(DONATE_URL);
const url = DONATE_LANG_URLS.get(_("language_code")) || DONATE_URL;
await openInTab(url, false);
}
export async function openPrefs() {
@ -85,16 +103,64 @@ export async function openManager(focus = true) {
catch (ex) {
console.error(ex.toString(), ex);
}
const url = runtime.getURL(MANAGER_URL);
const openInPopup = await Prefs.get("manager-in-popup");
if (openInPopup) {
const etabs = await tabs.query({
url
});
if (etabs.length) {
if (!focus) {
return;
}
const tab = etabs.pop();
await tabs.update(tab.id, {active: true});
await windows.update(tab.windowId, {focused: true});
return;
}
const tracker = new WindowStateTracker("manager", {
minWidth: 700,
minHeight: 500,
});
await tracker.init();
const windowOptions = tracker.getOptions({
url,
type: "popup",
});
const window = await windows.create(windowOptions);
tracker.track(window.id);
try {
if (!CHROME) {
windows.update(window.id, tracker.getOptions({}));
}
const port = await Promise.race<Port>([
new Promise<Port>(resolve => Bus.oncePort("manager", port => {
resolve(port);
return true;
})),
timeout<Port>(5 * 1000)]);
if (!port.isSelf) {
throw Error("Invalid sender connected");
}
tracker.track(window.id, port);
}
catch (ex) {
console.error("couldn't track manager", ex);
}
return;
}
if (focus) {
await openInTabOrFocus(await runtime.getURL(MANAGER_URL));
await openInTabOrFocus(runtime.getURL(MANAGER_URL), false);
}
else {
await maybeOpenInTab(await runtime.getURL(MANAGER_URL));
await maybeOpenInTab(runtime.getURL(MANAGER_URL), false);
}
}
export async function openUrls(urls: string) {
const window = await mostRecentBrowser();
export async function openUrls(urls: string, incognito: boolean) {
const window = await mostRecentBrowser(incognito);
for (const url of urls) {
try {
await tabs.create({

View File

@ -1,7 +1,7 @@
{
"manifest_version": 2,
"name": "DownThemAll!",
"version": "4.0.8",
"version": "4.2.4",
"description": "__MSG_extensionDescription__",
"homepage_url": "https://downthemall.org/",
@ -9,7 +9,7 @@
"default_locale": "en",
"content_security_policy": "script-src 'self'; style-src 'self' 'unsafe-inline'; img-src data: blob: 'self'; connect-src data: blob: 'self'; default-src 'self'",
"content_security_policy": "script-src 'self'; style-src 'self' 'unsafe-inline'; img-src data: blob: 'self'; connect-src data: blob: http: https: 'self'; default-src 'self'",
"icons": {
"16": "style/icon16.png",
@ -24,14 +24,19 @@
"permissions": [
"<all_urls>",
"contextMenus",
"menus",
"downloads",
"downloads.open",
"downloads.shelf",
"history",
"menus",
"notifications",
"sessions",
"storage",
"tabs",
"webNavigation"
"theme",
"webNavigation",
"webRequest",
"webRequestBlocking"
],
"background": {

View File

@ -18,22 +18,24 @@
"author": "Nils Maier",
"license": "MIT",
"devDependencies": {
"@types/node": "^12.7.2",
"@typescript-eslint/eslint-plugin": "^2.0.0",
"@typescript-eslint/parser": "^2.0.0",
"@types/node": "^12.7.8",
"@typescript-eslint/eslint-plugin": "^2.3.2",
"@typescript-eslint/parser": "^2.3.2",
"chai": "^4.1.2",
"eslint": "^6.2.2",
"mocha": "^6.2.0",
"ts-loader": "^6.0.4",
"ts-node": "^8.3.0",
"typescript": "^3.5.3",
"webpack": "^4.39.3",
"webpack-cli": "^3.3.7",
"eslint": "^6.5.1",
"mocha": "^6.2.1",
"ts-loader": "^6.2.0",
"ts-node": "^8.4.1",
"typescript": "^3.6.3",
"webpack": "^4.41.0",
"webpack-cli": "^3.3.9",
"xregexp": "^4.2.4"
},
"dependencies": {
"@types/psl": "^1.1.0",
"psl": "^1.3.0",
"webextension-polyfill": "^0.4.0"
"@types/whatwg-mimetype": "^2.1.0",
"psl": "^1.4.0",
"webextension-polyfill": "^0.5.0",
"whatwg-mimetype": "^2.3.0"
}
}

View File

@ -77,6 +77,8 @@ function urlToUsable(e: any, u: string) {
}
class Gatherer {
private: boolean;
textLinks: boolean;
selectionOnly: boolean;
@ -88,6 +90,7 @@ class Gatherer {
transferable: string[];
constructor(options: any) {
this.private = !!options.private;
this.textLinks = options.textLinks;
this.selectionOnly = options.selectionOnly;
this.selection = options.selectionOnly ? getSelection() : null;
@ -118,30 +121,43 @@ class Gatherer {
*collectImageInternal(img: HTMLImageElement) {
try {
const src = img.currentSrc || img.src;
const item = this.makeItem(src, img);
if (item) {
item.fileName = "";
item.description = item.title;
yield item;
}
const {srcset} = img;
if (!srcset) {
return;
}
const imgs = srcset.split(",").flatMap(e => {
const idx = e.lastIndexOf(" ");
return (idx > 0 ? e.slice(0, idx) : e).trim();
});
for (const i of imgs) {
const item = this.makeItem(i, img);
{
const {src} = img;
const item = this.makeItem(src, img);
if (item) {
item.fileName = "";
item.description = item.title;
yield item;
}
}
{
const {currentSrc} = img;
const item = this.makeItem(currentSrc, img);
if (item) {
item.fileName = "";
item.description = item.title;
yield item;
}
}
{
const {srcset} = img;
if (!srcset) {
return;
}
const imgs = srcset.split(",").flatMap(e => {
const idx = e.lastIndexOf(" ");
return (idx > 0 ? e.slice(0, idx) : e).trim();
});
for (const i of imgs) {
const item = this.makeItem(i, img);
if (item) {
item.fileName = "";
item.description = item.title;
yield item;
}
}
}
}
catch (ex) {
console.error("oops image", ex.toString(), ex.stack, ex);
@ -255,6 +271,7 @@ class Gatherer {
return {
url: url.href,
title,
private: this.private
};
}
catch (ex) {
@ -295,7 +312,7 @@ class Gatherer {
function gather(msg: any, sender: any, callback: Function) {
try {
if (!msg || msg.type !== "DTA:gather" || !callback) {
return;
return Promise.resolve(null);
}
const gatherer = new Gatherer(msg);
const result = {
@ -313,10 +330,11 @@ function gather(msg: any, sender: any, callback: Function) {
),
};
urlToUsable(result, result.baseURL);
callback(result);
return Promise.resolve(result);
}
catch (ex) {
console.error(ex.toString(), ex.stack, ex);
return Promise.resolve(null);
}
}

BIN
sounds/done.wav Normal file

Binary file not shown.

BIN
sounds/error.wav Normal file

Binary file not shown.

View File

@ -2,14 +2,29 @@
/* License: gpl-v2 */
:root {
--general-color: #2a2a2e;
--general-bgcolor: rgb(249, 249, 250);
--general-border-color: lightgray;
--general-input-color: black;
--general-input-bgcolor: white;
--general-button-color: black;
--general-button-bgcolor: rgb(246, 246, 246);
--general-button-bgcolor-hover: white;
--general-button-shadow: 0px 0px 5px 1px rgba(128, 128, 128, 0.5);
--menu-bgcolor: white;
--menu-bgcolor-hover: #2283fb;
--table-bgcolor: white;
--table-head-bgcolor: white;
--toolbar-bg-color: rgb(248, 134, 6);
--toolbar-active-border-color: #478de7;
--toolbar-hover-border-color: red;
--toolbar-hover-background: rgb(247, 149, 37);
--toolbar-border-width: 2px;
--toolbar-border: 1px solid rgba(255, 255, 255, 0.5);
--add-color: navy;
--queue-color: gray;
--pause-color: #ffa318;
--retry-color: rgb(0, 112, 204);
--error-color: rgb(160, 13, 42);
--running-color: #aae061;
--finishing-color: #57cc12;
@ -18,100 +33,274 @@
--folder-color: rgb(214, 165, 4);
--maskbutton-color: rgb(236, 185, 16);
--missing-color: rgb(0, 82, 204);
--open-color: rgba(236, 185, 16, 0.8);
--status-icon-color: #363636;
--status-icon-color-hover: #6e6d6d;
--tile-url: url(tile.png);
--file-icon-image-color: rgb(17, 107, 163);
--popup-bgcolor: #fff;
--popup-color: #0c0c0d;
--modal-color: black;
--modal-bgcolor: white;
}
html.dark {
--add-color: lightblue;
--general-bgcolor: #2a2a2e;
--general-border-color: rgb(85, 85, 85);
--general-button-bgcolor-hover: black;
--general-button-bgcolor: rgb(36, 36, 36);
--general-button-color: white;
--general-color: rgb(249, 249, 250);
--menu-bgcolor: black;
--menu-bgcolor-hover: #1a6bce;
--table-bgcolor: #1a1a1e;
--table-head-bgcolor: #3a3a3e;
--toolbar-bg-color: rgb(202, 108, 0);
--status-icon-color: #b9b9b9;
--status-icon-color-hover: #e2e2e2;
--tile-url: url(tile-dark.png?3);
--toolbar-border: 1px solid rgba(30, 30, 30, 0.5);
--file-icon-image-color: rgb(21, 130, 197);
--popup-bgcolor: #4a4a4f;
--popup-color: rgb(249, 249, 250);
--general-button-shadow: 0px 0px 7px 1px rgba(128, 128, 128, 0.8);
--modal-color: white;
--modal-bgcolor: #333;
scrollbar-color: rgba(249, 249, 250, 0.4) rgba(20, 20, 25, 0.3);
}
html.dark a {
color: lightblue;
}
html.dark ::-webkit-scrollbar {
background: rgba(20, 20, 25, 0.3);
}
html.dark ::-webkit-scrollbar-thumb {
background: rgba(249, 249, 250, 0.4);
}
html.dark ::-webkit-scrollbar-corner {
background: #000;
}
html[data-platform="mac"] {
--folder-color: rgb(4, 102, 214);
}
html,
body {
font-size: 10pt !important;
}
@font-face {
font-family: 'downthemall';
src: url('downthemall.woff2?75791791') format('woff2');
font-family: "downthemall";
src: url("downthemall.woff2?75791791") format("woff2");
font-weight: normal;
font-style: normal;
}
[class^="icon-"]:before, [class*=" icon-"]:before {
[class^="icon-"]:before,
[class*=" icon-"]:before {
font-family: "downthemall";
font-style: normal;
font-weight: normal;
display: inline-block;
text-decoration: inherit;
width: 1em;
text-align: center;
font-variant: normal;
text-transform: none;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-add:before { content: '\e800'; } /* '' */
.icon-addsegment:before { content: '\e801'; } /* '' */
.icon-bottom:before { content: '\e802'; } /* '' */
.icon-picture:before { content: '\e803'; } /* '' */
.icon-circle:before { content: '\e804'; } /* '' */
.icon-delete:before { content: '\e805'; } /* '' */
.icon-done:before { content: '\e806'; } /* '' */
.icon-down:before { content: '\e807'; } /* '' */
.icon-download:before { content: '\e808'; } /* '' */
.icon-dupe:before { content: '\e809'; } /* '' */
.icon-error:before { content: '\e80a'; } /* '' */
.icon-failed:before { content: '\e80b'; } /* '' */
.icon-file:before { content: '\e80c'; } /* '' */
.icon-find:before { content: '\e80d'; } /* '' */
.icon-folder:before { content: '\e80e'; } /* '' */
.icon-force:before { content: '\e80f'; } /* '' */
.icon-go:before { content: '\e810'; } /* '' */
.icon-import:before { content: '\e811'; } /* '' */
.icon-info:before { content: '\e812'; } /* '' */
.icon-launch:before { content: '\e813'; } /* '' */
.icon-missing:before { content: '\e814'; } /* '' */
.icon-network-off:before { content: '\e815'; } /* '' */
.icon-network-on:before { content: '\e816'; } /* '' */
.icon-pause:before { content: '\e817'; } /* '' */
.icon-remsegment:before { content: '\e818'; } /* '' */
.icon-rename:before { content: '\e819'; } /* '' */
.icon-save:before { content: '\e81a'; } /* '' */
.icon-settings:before { content: '\e81b'; } /* '' */
.icon-top:before { content: '\e81c'; } /* '' */
.icon-unchecked:before { content: '\e81d'; } /* '' */
.icon-unlimited:before { content: '\e81e'; } /* '' */
.icon-link:before { content: '\e81f'; } /* '' */
.icon-up:before { content: '\e820'; } /* '' */
.icon-privacy:before { content: '\e821'; } /* '' */
.icon-tags:before { content: '\e822'; } /* '' */
.icon-attention:before { content: '\e823'; } /* '' */
.icon-notification:before { content: '\e824'; } /* '' */
.icon-file-video:before { content: '\e825'; } /* '' */
.icon-file-generic:before { content: '\e826'; } /* '' */
.icon-question-dark:before { content: '\e827'; } /* '' */
.icon-filter:before { content: '\f0b0'; } /* '' */
.icon-donate:before { content: '\f0d6'; } /* '' */
.icon-file-doc:before { content: '\f0f6'; } /* '' */
.icon-interface:before { content: '\f108'; } /* '' */
.icon-folder-1:before { content: '\f115'; } /* '' */
.icon-sort-asc:before { content: '\f15d'; } /* '' */
.icon-sort-desc:before { content: '\f15e'; } /* '' */
.icon-file-pdf:before { content: '\f1c1'; } /* '' */
.icon-file-word:before { content: '\f1c2'; } /* '' */
.icon-file-image:before { content: '\f1c5'; } /* '' */
.icon-file-archive:before { content: '\f1c6'; } /* '' */
.icon-file-audio:before { content: '\f1c7'; } /* '' */
.icon-toggle:before { content: '\f205'; } /* '' */
.icon-server:before { content: '\f233'; } /* '' */
.icon-question-light:before { content: '\f29c'; } /* '' */
.icon-add:before {
content: "\e800";
} /* '' */
.icon-addsegment:before {
content: "\e801";
} /* '' */
.icon-bottom:before {
content: "\e802";
} /* '' */
.icon-picture:before {
content: "\e803";
} /* '' */
.icon-circle:before {
content: "\e804";
} /* '' */
.icon-delete:before {
content: "\e805";
} /* '' */
.icon-done:before {
content: "\e806";
} /* '' */
.icon-down:before {
content: "\e807";
} /* '' */
.icon-download:before {
content: "\e808";
} /* '' */
.icon-dupe:before {
content: "\e809";
} /* '' */
.icon-error:before {
content: "\e80a";
} /* '' */
.icon-failed:before {
content: "\e80b";
} /* '' */
.icon-file:before {
content: "\e80c";
} /* '' */
.icon-find:before {
content: "\e80d";
} /* '' */
.icon-folder:before {
content: "\e80e";
} /* '' */
.icon-force:before {
content: "\e80f";
} /* '' */
.icon-go:before {
content: "\e810";
} /* '' */
.icon-import:before {
content: "\e811";
} /* '' */
.icon-info:before {
content: "\e812";
} /* '' */
.icon-launch:before {
content: "\e813";
} /* '' */
.icon-missing:before {
content: "\e814";
} /* '' */
.icon-network-off:before {
content: "\e815";
} /* '' */
.icon-network-on:before {
content: "\e816";
} /* '' */
.icon-pause:before {
content: "\e817";
} /* '' */
.icon-remsegment:before {
content: "\e818";
} /* '' */
.icon-rename:before {
content: "\e819";
} /* '' */
.icon-save:before {
content: "\e81a";
} /* '' */
.icon-settings:before {
content: "\e81b";
} /* '' */
.icon-top:before {
content: "\e81c";
} /* '' */
.icon-unchecked:before {
content: "\e81d";
} /* '' */
.icon-unlimited:before {
content: "\e81e";
} /* '' */
.icon-link:before {
content: "\e81f";
} /* '' */
.icon-up:before {
content: "\e820";
} /* '' */
.icon-privacy:before {
content: "\e821";
} /* '' */
.icon-tags:before {
content: "\e822";
} /* '' */
.icon-attention:before {
content: "\e823";
} /* '' */
.icon-notification:before {
content: "\e824";
} /* '' */
.icon-file-video:before {
content: "\e825";
} /* '' */
.icon-file-generic:before {
content: "\e826";
} /* '' */
.icon-question-dark:before {
content: "\e827";
} /* '' */
.icon-forward:before {
content: "\e828";
} /* '' */
.icon-filter:before {
content: "\f0b0";
} /* '' */
.icon-donate:before {
content: "\f0d6";
} /* '' */
.icon-file-doc:before {
content: "\f0f6";
} /* '' */
.icon-interface:before {
content: "\f108";
} /* '' */
.icon-folder-1:before {
content: "\f115";
} /* '' */
.icon-sort-asc:before {
content: "\f15d";
} /* '' */
.icon-sort-desc:before {
content: "\f15e";
} /* '' */
.icon-file-pdf:before {
content: "\f1c1";
} /* '' */
.icon-file-word:before {
content: "\f1c2";
} /* '' */
.icon-file-image:before {
content: "\f1c5";
} /* '' */
.icon-file-archive:before {
content: "\f1c6";
} /* '' */
.icon-file-audio:before {
content: "\f1c7";
} /* '' */
.icon-toggle-off:before {
content: "\f204";
} /* '' */
.icon-toggle-on:before {
content: "\f205";
} /* '' */
.icon-server:before {
content: "\f233";
} /* '' */
.icon-question-light:before {
content: "\f29c";
} /* '' */
@media (min-resolution: 144dpi) {
[class^="icon-file-"]:before, [class*=" icon-file-"]:before {
[class^="icon-file-"]:before,
[class*=" icon-file-"]:before {
font-weight: bold !important;
}
}
.icon-file-image {
color: rgb(17, 107, 163);
color: var(--file-icon-image-color);
}
.icon-file-pdf,
@ -132,18 +321,29 @@ html[data-platform="mac"] {
color: rgb(202, 81, 198);
}
body, html {
background: #F6F6F8;
color: #0C0C0D;
body,
html {
font: message-box;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Ubuntu', 'Helvetica Neue', sans-serif;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Ubuntu",
"Helvetica Neue", sans-serif;
height: 100%;
margin: 0;
padding: 0;
width: 100%;
color: var(--general-color);
background: var(--general-bgcolor);
}
h1, h2, h3, h4 {
html#popup,
html#popup > body {
color: var(--popup-color);
background: var(--popup-bgcolor);
}
h1,
h2,
h3,
h4 {
font: caption;
font-weight: bold;
}
@ -183,7 +383,11 @@ section {
}
.virtualtable-column:active {
background-image: linear-gradient(to top, rgba(0,0,0,0.03), rgba(128,128,128,0.1));
background-image: linear-gradient(
to top,
rgba(0, 0, 0, 0.03),
rgba(128, 128, 128, 0.1)
);
}
th.virtualtable {
@ -210,8 +414,12 @@ td.virtualtable {
font-size: 12px;
align-items: stretch;
justify-items: center;
background: linear-gradient(to bottom, rgba(128,128,128,0.1) 0%,rgba(0,0,0,0) 100%);
border-top: 1px solid rgba(128,128,128,0.6);
background: linear-gradient(
to bottom,
rgba(128, 128, 128, 0.1) 0%,
rgba(0, 0, 0, 0) 100%
);
border-top: 1px solid rgba(128, 128, 128, 0.6);
display: flex;
margin-bottom: 1ex;
overflow: auto;
@ -238,15 +446,15 @@ td.virtualtable {
flex-grow: 3;
margin-right: 2ex;
padding-right: 1ex;
border-right: 1px dotted rgba(128,128,128,0.6);
border-right: 1px dotted rgba(128, 128, 128, 0.6);
}
#statusPrefs {
cursor: pointer;
color: #363636;
color: var(--status-icon-color);
}
#statusPrefs:hover {
color: #6e6d6d;
color: var(--status-icon-color-hover);
}
.dropdown {
@ -264,13 +472,14 @@ td.virtualtable {
outline: none;
position: absolute;
top: 0;
width:100%;
width: 100%;
}
.dropdown input {
-moz-appearance: none;
-webkit-appearance: none;
appearance: none;
color: black;
background: white;
border: none;
bottom: 2px;
@ -293,7 +502,6 @@ td.virtualtable {
padding-bottom: 1ex;
}
@supports (not (-moz-appearance: none)) {
.dropdown select {
background: white;
@ -362,4 +570,55 @@ td.virtualtable {
#maskButton {
color: var(--maskbutton-color);
}
}
table.virtualtable,
.virtualtable-body {
color: var(--general-color);
background: var(--table-bgcolor);
}
.virtualtable-head,
.virtualtable-head > table {
background: var(--table-head-bgcolor) !important;
}
.virtualtable-column {
border-right: 1px solid var(--general-border-color);
}
.virtualtable-cell {
border-right: 1px dotted var(--general-border-color);
}
.virtualtable-head,
.virtualtable-body {
border-bottom: 1px solid var(--general-border-color);
}
ul.context-menu,
ul.context-menu ul {
color: var(--general-color);
background: var(--menu-bgcolor);
}
.context-menu-item:hover:not(.context-menu-seperator),
.context-menu-item:hover:not(.context-menu-seperator) > * {
background: var(--menu-bgcolor-hover);
}
html.dark .context-menu-item.disabled,
html.dark .context-menu-item.disabled > * {
opacity: 0.7;
}
input {
color: var(--general-input-color);
background: var(--general-input-bgcolor);
border: inherit;
padding: 2px;
}
.modal-dialog {
color: var(--modal-color);
background: var(--modal-bgcolor);
}

BIN
style/done.opus Normal file

Binary file not shown.

BIN
style/downthemall.woff2 Normal file → Executable file

Binary file not shown.

BIN
style/error.opus Normal file

Binary file not shown.

View File

@ -16,7 +16,7 @@ body > * {
#toolbar {
display: flex;
margin: 0;
background: var(--toolbar-bg-color) url(tile.png) repeat-x;
background: var(--toolbar-bg-color) var(--tile-url) repeat-x;
}
#toolbar .spacer {
@ -42,9 +42,9 @@ body > * {
justify-content: center;
align-items: center;
cursor: pointer;
box-shadow: 0px 0px 5px 1px rgba(128,128,128,0.5);
background: rgb(246,246,246);
color: black;
box-shadow: var(--general-button-shadow);
background: var(--general-button-bgcolor);
color: var(--general-button-color);
transition: box-shadow 0.5s, background 1s;
font-size: 24px;
line-height: 24px;
@ -60,7 +60,7 @@ body > * {
}
#toolbar > .button:hover:not(.disabled) {
background: white;
background: var(--general-button-bgcolor-hover);
box-shadow: 0px 0px 7px 2px rgba(70,70,70,0.75);
}
@ -88,14 +88,14 @@ body > * {
flex: 1 1 auto;
overflow: hidden;
display: grid;
background: white;
background: var(--general-bgcolor);
}
#loading {
display: flex;
justify-content: center;
align-items: center;
background: rgba(255,255,255,0.9);
background: var(--general-button-bgcolor);
font-weight: bolder;
font-size: 200%;
z-index: 10;
@ -108,11 +108,11 @@ body > * {
}
#colURL {
width: 38%;
width: 42%;
}
#colPercent {
width: 3em;
width: 4em;
min-width: 3em;
}
@ -121,11 +121,11 @@ body > * {
}
#colSize {
width: 15em;
width: 14em;
}
#colSpeed {
width: 6em;
width: 7em;
}
#colDomain,
@ -154,6 +154,14 @@ body > * {
height: 26px;
}
.virtualtable-row.opening {
background: var(--open-color) !important;
}
.virtualtable-progress-container {
border-radius: 2px;
}
.virtualtable-progress-bar {
height: 14px;
}
@ -194,6 +202,23 @@ body > * {
);
}
.retrying .virtualtable-column-2 .virtualtable-icon {
color: var(--retry-color);
}
.retrying .virtualtable-column-2 .virtualtable-progress-bar {
background: var(--retry-color);
}
.retrying .virtualtable-column-2 .virtualtable-progress-undetermined {
background: repeating-linear-gradient(
45deg,
var(--retry-color),
var(--retry-color) 6px,
transparent 6px,
transparent 12px
);
}
.missing .virtualtable-column-2 .virtualtable-icon,
.canceled .virtualtable-column-2 .virtualtable-icon {
color: var(--error-color);
@ -262,6 +287,7 @@ body > * {
}
.virtualtable-column-6,
.virtualtable-column-4,
.virtualtable-column-3 {
text-align: right;
}
@ -285,7 +311,7 @@ body > * {
color: crimson;
}
#statusNetwork.icon-network-on {
color: navy;
color: var(--add-color);
}
#statusFilter {
@ -318,6 +344,7 @@ body > * {
height: 16px;
-moz-appearance: none;
border: 0;
outline: 0;
background: transparent;
width: calc(100% - 28px);
}
@ -377,7 +404,7 @@ body > * {
font-size: 10pt !important;
}
#nagging {
border-top: 1px solid lightgray;
border-top: 1px solid var(--general-border-color);
display: grid;
grid-template-columns: 1fr auto auto auto;
align-content: center;
@ -430,6 +457,8 @@ body > * {
justify-items: stretch;
border-radius: 4px;
box-shadow: 2px 2px 6px black;
-webkit-user-select: none;
user-select: none;
}
#tooltip-infos {
@ -500,4 +529,24 @@ body > * {
height: 100%;
width: 100%;
background: var(--done-color);
}
#tooltip-eta.single {
font-weight: bold;
grid-column-end: span 2;
}
.deletefiles-list {
padding-left: 1ex;
padding-right: 1.5ex;
border: 1px solid lightgray;
border-radius: 6px;
background-color: rgba(128,128,128,0.1);
max-height: 8em;
overflow-y: auto;
}
.deletefiles-list > li {
list-style-type: none;
padding: 0;
margin: 0;
}

View File

@ -1,8 +1,8 @@
/* License: gpl-v2 */
@import 'common.css';
@import "common.css";
html, body {
background: transparent !important;
html,
body {
width: 100%;
height: 100%;
}
@ -19,9 +19,10 @@ article {
#tabs {
display: flex;
background: url(icon64.png) 1em 50%/32px 32px no-repeat, url(tile.png) repeat-x, var(--toolbar-bg-color);
background: url(icon64.png) 1em 50%/32px 32px no-repeat,
var(--tile-url) repeat-x, var(--toolbar-bg-color);
padding-left: calc(2em + 32px);
color: white;
color: var(--general-bgcolor);
}
input.tab {
@ -54,9 +55,10 @@ input.tab {
#tabsel-general:checked ~ #tabs #tabel-general,
#tabsel-filters:checked ~ #tabs #tabel-filters,
#tabsel-network:checked ~ #tabs #tabel-network {
color: black !important;
background: white;
border-top: var(--toolbar-border-width) solid var(--toolbar-active-border-color);
color: var(--general-color) !important;
background: var(--general-bgcolor);
border-top: var(--toolbar-border-width) solid
var(--toolbar-active-border-color);
}
#tabs > label {
@ -64,13 +66,14 @@ input.tab {
border-top: var(--toolbar-border-width) solid transparent;
border-left: 1px solid transparent;
border-right: 1px solid transparent;
border-left: 1px solid rgba(255, 255, 255, 0.5);
border-right: 1px solid rgba(255, 255, 255, 0.5);
border-left: var(--toolbar-border);
border-right: var(--toolbar-border);
background: var(--toolbar-bg-color);
}
#tabs > label:hover:not(:checked) {
border-top: var(--toolbar-border-width) solid var(--toolbar-hover-border-color);
border-top: var(--toolbar-border-width) solid
var(--toolbar-hover-border-color);
background: var(--toolbar-hover-background);
}
@ -102,7 +105,7 @@ input.tab {
text-align: center;
}
.buttons > button{
.buttons > button {
margin: 0 2em;
}
@ -113,15 +116,27 @@ input.tab {
fieldset {
display: flex;
margin-bottom: 1em;
border: 1px solid lightgray;
border: 1px solid var(--general-border-color);
border-radius: 6px;
box-shadow: 1px 1px 6px lightgray;
box-shadow: 1px 1px 6px var(--general-border-color);
background: rgba(128, 128, 128, 0.05);
flex-direction: column;
max-width: 60em;
padding: 1.2em;
}
.optiongroups,
fieldset > label {
display: flex;
align-items: center;
}
fieldset > label > input,
fieldset > label > select {
margin-left: 1ex;
margin-right: 1ex;
}
legend {
font-weight: bold;
font-size: 120%;
@ -134,8 +149,36 @@ legend {
}
.virtualtable-container {
border: 1px solid lightgray;
border: 1px solid var(--general-border-color);
border-radius: 6px;
background: rgba(128, 128, 128, 0.05);
box-shadow: 1px 1px 6px lightgray;
}
box-shadow: 1px 1px 6px var(--general-border-color);
}
#network-general {
display: grid;
grid-template-columns: auto 1fr;
grid-column-gap: 1em;
grid-row-gap: 1ex;
}
.optiongroups {
display: grid;
grid-template-columns: auto 1fr;
grid-column-gap: 1em;
grid-row-gap: 1ex;
}
.optiongroups > div,
.optiongroups > div > label {
display: flex;
align-items: center;
}
.optiongroups input {
margin-left: 1em;
margin-right: 0.7ex;
}
hr {
width: 100%;
}

View File

@ -107,7 +107,7 @@ body > * {
padding: 0;
padding-left: calc(2em + 32px);
color: black;
background: url(icon32.png) 1em 0/32px 32px no-repeat, url(tile.png) repeat-x, var(--toolbar-bg-color);
background: url(icon32.png) 1em 0/32px 32px no-repeat, var(--tile-url) repeat-x, var(--toolbar-bg-color);
font: caption;
font-size: 150%;
font-weight: bold;
@ -117,7 +117,7 @@ body > * {
}
@media (-webkit-min-device-pixel-ratio: 1.3), (min-resolution: 124.8dpi) {
#tabs {
background: url(icon64.png) 1em 50%/32px 32px no-repeat, url(tile.png) repeat-x, var(--toolbar-bg-color);
background: url(icon64.png) 1em 50%/32px 32px no-repeat, var(--tile-url) repeat-x, var(--toolbar-bg-color);
}
}
@ -145,27 +145,27 @@ body > * {
-webkit-user-select: none;
user-select: none;
background: var(--toolbar-bg-color);
color: white;
color: var(--general-color);
min-width: 10em;
padding: 1ex;
padding-left: 1em;
cursor: pointer;
border: 0;
border-top: var(--toolbar-border-width) solid transparent;
border-left: 1px solid rgba(255,255,255,0.3);
border-right: 1px solid rgba(255,255,255,0.3);
border-left: var(--toolbar-border);
border-right: var(--toolbar-border);
transition: border 1s;
}
.tab:not(.active):not(.disabled):hover {
border-top: var(--toolbar-border-width) solid var(--toolbar-hover-border-color);
color: rgb(255, 226, 167);
color: var(--general-color);
background: var(--toolbar-hover-background);
}
.tab.active {
color: black;
background: white;
color: var(--general-color);
background: var(--table-head-bgcolor);
border-top: var(--toolbar-border-width) solid var(--toolbar-active-border-color);
border-left: 1px solid transparent;
border-right: 1px solid transparent;
@ -232,3 +232,7 @@ body > * {
#maskButton {
justify-self: flex-start;
}
#btnDownload {
font-weight: bold;
}

View File

@ -63,6 +63,7 @@ p.example {
align-items: center;
}
#options > #subfolderOptions,
#options > #maskOptions {
display: grid;
grid-template-columns: 2fr auto auto;
@ -81,3 +82,7 @@ h3 {
font-weight: normal;
font-style: italic;
}
#btnDownload {
font-weight: bold;
}

BIN
style/tile-dark.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

10
tests/.editorconfig Normal file
View File

@ -0,0 +1,10 @@
root = true
[*]
charset = utf-8
end_of_line = lf
indent_size = 2
indent_style = space
insert_final_newline = true
tab_width = 2
trim_trailing_whitespace = true

View File

@ -113,4 +113,29 @@ describe("BatchGenerator", function() {
expect(items[0]).to.equal(gen.preview);
expect(gen.hasInvalid).to.be.true;
});
it("characters", function() {
const gen = new BatchGenerator("abc[a:c].lol[1].b");
const items = Array.from(gen);
expect(items).to.deep.equal([
"abca.lol[1].b",
"abcb.lol[1].b",
"abcc.lol[1].b",
]);
expect(items.length).to.equal(gen.length);
expect(items[0]).to.equal(gen.preview);
});
it("characters two", function() {
const gen = new BatchGenerator("abc[D:G].lol[1].b");
const items = Array.from(gen);
expect(items).to.deep.equal([
"abcD.lol[1].b",
"abcE.lol[1].b",
"abcF.lol[1].b",
"abcG.lol[1].b",
]);
expect(items.length).to.equal(gen.length);
expect(items[0]).to.equal(gen.preview);
});
});

Some files were not shown because too many files have changed in this diff Show More