move zoom tile creation into seperate worker thread

This commit is contained in:
HF 2022-04-04 05:07:27 +02:00
parent 12f2862769
commit 258fd42e68
8 changed files with 437 additions and 400 deletions

View File

@ -3,53 +3,53 @@ msgstr ""
"Content-Type: text/plain; charset=utf-8\n" "Content-Type: text/plain; charset=utf-8\n"
"Plural-Forms: nplurals=2; plural=(n!=1);\n" "Plural-Forms: nplurals=2; plural=(n!=1);\n"
#: src/core/ChatProvider.js:350 #: src/core/ChatProvider.js:370
msgid "You can not send chat messages with proxy" msgid "You can not send chat messages with proxy"
msgstr "" msgstr ""
#: src/core/ChatProvider.js:364 #: src/core/ChatProvider.js:384
#, javascript-format #, javascript-format
msgid "You are sending messages too fast, you have to wait ${ waitTime }s :(" msgid "You are sending messages too fast, you have to wait ${ waitTime }s :("
msgstr "" msgstr ""
#: src/core/ChatProvider.js:368 #: src/core/ChatProvider.js:388
msgid "You don't have access to this channel" msgid "You don't have access to this channel"
msgstr "" msgstr ""
#: src/core/ChatProvider.js:384 #: src/core/ChatProvider.js:404
msgid "Your mail has to be verified in order to chat" msgid "Your mail has to be verified in order to chat"
msgstr "" msgstr ""
#: src/core/ChatProvider.js:389 #: src/core/ChatProvider.js:409
msgid "You are permanently muted, join our guilded to apppeal the mute" msgid "You are permanently muted, join our guilded to apppeal the mute"
msgstr "" msgstr ""
#: src/core/ChatProvider.js:394 #: src/core/ChatProvider.js:414
#, javascript-format #, javascript-format
msgid "You are muted for another ${ timeMin } minutes" msgid "You are muted for another ${ timeMin } minutes"
msgstr "" msgstr ""
#: src/core/ChatProvider.js:396 #: src/core/ChatProvider.js:416
msgid "You are muted for another ${ muted } seconds" msgid "You are muted for another ${ muted } seconds"
msgstr "" msgstr ""
#: src/core/ChatProvider.js:404 #: src/core/ChatProvider.js:424
msgid "Ow no! Spam protection decided to mute you" msgid "Ow no! Spam protection decided to mute you"
msgstr "" msgstr ""
#: src/core/ChatProvider.js:415 #: src/core/ChatProvider.js:435
msgid "You can't send a message this long :(" msgid "You can't send a message this long :("
msgstr "" msgstr ""
#: src/core/ChatProvider.js:419 #: src/core/ChatProvider.js:439
msgid "Please use int channel" msgid "Please use int channel"
msgstr "" msgstr ""
#: src/core/ChatProvider.js:423 #: src/core/ChatProvider.js:443
msgid "Your country is temporary muted from chat" msgid "Your country is temporary muted from chat"
msgstr "" msgstr ""
#: src/core/ChatProvider.js:431 #: src/core/ChatProvider.js:451
msgid "Stop flooding." msgid "Stop flooding."
msgstr "" msgstr ""
@ -245,15 +245,15 @@ msgstr ""
msgid "Server error occured" msgid "Server error occured"
msgstr "" msgstr ""
#: src/routes/api/modtools.js:50 #: src/routes/api/modtools.js:52
msgid "You are not logged in" msgid "You are not logged in"
msgstr "" msgstr ""
#: src/routes/api/modtools.js:62 #: src/routes/api/modtools.js:64
msgid "You are not allowed to access this page" msgid "You are not allowed to access this page"
msgstr "" msgstr ""
#: src/routes/api/modtools.js:128 #: src/routes/api/modtools.js:166
msgid "Just admins can do that" msgid "Just admins can do that"
msgstr "" msgstr ""
@ -282,7 +282,7 @@ msgid "Name can't be empty."
msgstr "" msgstr ""
#: src/utils/validation.js:31 #: src/utils/validation.js:31
msgid "Name must be at least 4 characters long" msgid "Name must be at least 2 characters long"
msgstr "" msgstr ""
#: src/utils/validation.js:32 #: src/utils/validation.js:32

View File

@ -3,6 +3,48 @@ msgstr ""
"Content-Type: text/plain; charset=utf-8\n" "Content-Type: text/plain; charset=utf-8\n"
"Plural-Forms: nplurals=2; plural=(n!=1);\n" "Plural-Forms: nplurals=2; plural=(n!=1);\n"
#: src/controls/keypress.js:41
#, javascript-format
msgid "Switched to ${ canvasName }"
msgstr ""
#: src/controls/keypress.js:64
msgid "Grid ON"
msgstr ""
#: src/controls/keypress.js:65
msgid "Grid OFF"
msgstr ""
#: src/controls/keypress.js:75
msgid "Pixel Notify ON"
msgstr ""
#: src/controls/keypress.js:76
msgid "Pixel Notify OFF"
msgstr ""
#: src/controls/keypress.js:81
msgid "Muted Sound"
msgstr ""
#: src/controls/keypress.js:82
msgid "Unmuted Sound"
msgstr ""
#: src/components/CoordinatesBox.jsx:29
#: src/controls/keypress.js:88
msgid "Copied!"
msgstr ""
#: src/controls/keypress.js:94
msgid "Show Hidden Canvases"
msgstr ""
#: src/controls/keypress.js:95
msgid "Hide Hidden Canvases"
msgstr ""
#: src/ui/placePixel.js:53 #: src/ui/placePixel.js:53
msgid "Error :(" msgid "Error :("
msgstr "" msgstr ""
@ -104,48 +146,6 @@ msgstr ""
msgid "Error ${ retCode }" msgid "Error ${ retCode }"
msgstr "" msgstr ""
#: src/controls/keypress.js:41
#, javascript-format
msgid "Switched to ${ canvasName }"
msgstr ""
#: src/controls/keypress.js:64
msgid "Grid ON"
msgstr ""
#: src/controls/keypress.js:65
msgid "Grid OFF"
msgstr ""
#: src/controls/keypress.js:75
msgid "Pixel Notify ON"
msgstr ""
#: src/controls/keypress.js:76
msgid "Pixel Notify OFF"
msgstr ""
#: src/controls/keypress.js:81
msgid "Muted Sound"
msgstr ""
#: src/controls/keypress.js:82
msgid "Unmuted Sound"
msgstr ""
#: src/components/CoordinatesBox.jsx:29
#: src/controls/keypress.js:88
msgid "Copied!"
msgstr ""
#: src/controls/keypress.js:94
msgid "Show Hidden Canvases"
msgstr ""
#: src/controls/keypress.js:95
msgid "Hide Hidden Canvases"
msgstr ""
#: src/ui/renderer.js:36 #: src/ui/renderer.js:36
msgid "Canvas Error" msgid "Canvas Error"
msgstr "" msgstr ""
@ -170,6 +170,11 @@ msgstr ""
msgid "Look at past Canvases" msgid "Look at past Canvases"
msgstr "" msgstr ""
#: src/components/Converter.jsx:559
#: src/components/CoordinatesBox.jsx:32
msgid "Copy to Clipboard"
msgstr ""
#: src/components/OnlineBox.jsx:41 #: src/components/OnlineBox.jsx:41
msgid "Online Users on Canvas" msgid "Online Users on Canvas"
msgstr "" msgstr ""
@ -182,13 +187,8 @@ msgstr ""
msgid "Pixels placed" msgid "Pixels placed"
msgstr "" msgstr ""
#: src/components/Converter.jsx:559
#: src/components/CoordinatesBox.jsx:32
msgid "Copy to Clipboard"
msgstr ""
#: src/components/ModalRoot.jsx:69 #: src/components/ModalRoot.jsx:69
#: src/components/Modtools.jsx:224 #: src/components/Modtools.jsx:318
#: src/components/Window.jsx:138 #: src/components/Window.jsx:138
#: src/components/contextmenus/ChannelContextMenu.jsx:67 #: src/components/contextmenus/ChannelContextMenu.jsx:67
msgid "Close" msgid "Close"
@ -198,27 +198,6 @@ msgstr ""
msgid "Restore" msgid "Restore"
msgstr "" msgstr ""
#: src/components/buttons/ChatButton.jsx:92
msgid "Close Chat"
msgstr ""
#: src/components/buttons/ChatButton.jsx:92
msgid "Open Chat"
msgstr ""
#: src/components/buttons/CanvasSwitchButton.jsx:22
#: src/components/windows/index.js:19
msgid "Canvas Selection"
msgstr ""
#: src/components/buttons/ExpandMenuButton.jsx:23
msgid "Close Menu"
msgstr ""
#: src/components/buttons/ExpandMenuButton.jsx:23
msgid "Open Menu"
msgstr ""
#: src/actions/fetch.js:39 #: src/actions/fetch.js:39
msgid "You made too many requests" msgid "You made too many requests"
msgstr "" msgstr ""
@ -248,8 +227,25 @@ msgstr ""
msgid "Server answered with gibberish :(" msgid "Server answered with gibberish :("
msgstr "" msgstr ""
#: src/components/buttons/GlobeButton.jsx:35 #: src/components/buttons/ChatButton.jsx:92
msgid "Globe View" msgid "Close Chat"
msgstr ""
#: src/components/buttons/ChatButton.jsx:92
msgid "Open Chat"
msgstr ""
#: src/components/buttons/CanvasSwitchButton.jsx:22
#: src/components/windows/index.js:19
msgid "Canvas Selection"
msgstr ""
#: src/components/buttons/ExpandMenuButton.jsx:23
msgid "Close Menu"
msgstr ""
#: src/components/buttons/ExpandMenuButton.jsx:23
msgid "Open Menu"
msgstr "" msgstr ""
#: src/components/HistorySelect.jsx:144 #: src/components/HistorySelect.jsx:144
@ -260,33 +256,6 @@ msgstr ""
msgid "Select Date above" msgid "Select Date above"
msgstr "" msgstr ""
#: src/components/buttons/PalselButton.jsx:31
msgid "Close Palette"
msgstr ""
#: src/components/buttons/PalselButton.jsx:31
msgid "Open Palette"
msgstr ""
#: src/components/buttons/HelpButton.jsx:23
#: src/components/windows/index.js:13
msgid "Help"
msgstr ""
#: src/components/buttons/SettingsButton.jsx:23
#: src/components/windows/index.js:14
msgid "Settings"
msgstr ""
#: src/components/buttons/DownloadButton.jsx:37
msgid "Make Screenshot"
msgstr ""
#: src/components/buttons/LogInButton.jsx:23
#: src/components/windows/index.js:15
msgid "User Area"
msgstr ""
#: src/components/Window.jsx:117 #: src/components/Window.jsx:117
msgid "Clone" msgid "Clone"
msgstr "" msgstr ""
@ -303,22 +272,53 @@ msgstr ""
msgid "Resize" msgid "Resize"
msgstr "" msgstr ""
#: src/components/contextmenus/UserContextMenu.jsx:53 #: src/components/buttons/SettingsButton.jsx:23
msgid "Ping" #: src/components/windows/index.js:14
msgid "Settings"
msgstr "" msgstr ""
#: src/components/contextmenus/UserContextMenu.jsx:78 #: src/components/buttons/HelpButton.jsx:23
msgid "DM" #: src/components/windows/index.js:13
msgid "Help"
msgstr "" msgstr ""
#: src/components/contextmenus/UserContextMenu.jsx:88 #: src/components/buttons/LogInButton.jsx:23
msgid "Block" #: src/components/windows/index.js:15
msgid "User Area"
msgstr ""
#: src/components/buttons/DownloadButton.jsx:37
msgid "Make Screenshot"
msgstr ""
#: src/components/buttons/GlobeButton.jsx:35
msgid "Globe View"
msgstr ""
#: src/components/buttons/PalselButton.jsx:31
msgid "Close Palette"
msgstr ""
#: src/components/buttons/PalselButton.jsx:31
msgid "Open Palette"
msgstr "" msgstr ""
#: src/components/contextmenus/ChannelContextMenu.jsx:55 #: src/components/contextmenus/ChannelContextMenu.jsx:55
msgid "Mute" msgid "Mute"
msgstr "" msgstr ""
#: src/components/contextmenus/UserContextMenu.jsx:55
msgid "Ping"
msgstr ""
#: src/components/contextmenus/UserContextMenu.jsx:80
msgid "DM"
msgstr ""
#: src/components/contextmenus/UserContextMenu.jsx:90
msgid "Block"
msgstr ""
#: src/components/windows/index.js:16 #: src/components/windows/index.js:16
msgid "Registration" msgid "Registration"
msgstr "" msgstr ""
@ -631,6 +631,73 @@ msgstr ""
msgid "Select Language" msgid "Select Language"
msgstr "" msgstr ""
#: src/components/windows/UserArea.jsx:27
msgid "Profile"
msgstr ""
#: src/components/windows/UserArea.jsx:30
msgid "Ranking"
msgstr ""
#: src/components/windows/UserArea.jsx:33
msgid "Converter"
msgstr ""
#: src/components/windows/UserArea.jsx:39
msgid "Modtools"
msgstr ""
#: src/components/windows/UserArea.jsx:40
msgid "Loading..."
msgstr ""
#: src/components/windows/UserArea.jsx:47
msgid "Consider joining us on Guilded:"
msgstr ""
#: src/components/windows/Register.jsx:85
msgid "Register new account here"
msgstr ""
#: src/components/windows/Register.jsx:90
#: src/components/windows/Register.jsx:96
msgid "Name"
msgstr ""
#: src/components/windows/ForgotPassword.jsx:82
#: src/components/windows/Register.jsx:98
#: src/components/windows/Register.jsx:104
msgid "Email"
msgstr ""
#: src/components/ChangeMail.jsx:80
#: src/components/DeleteAccount.jsx:62
#: src/components/LogInForm.jsx:83
#: src/components/windows/Register.jsx:106
#: src/components/windows/Register.jsx:112
msgid "Password"
msgstr ""
#: src/components/windows/Register.jsx:114
#: src/components/windows/Register.jsx:120
msgid "Confirm Password"
msgstr ""
#: src/components/windows/Register.jsx:122
msgid "Captcha"
msgstr ""
#: src/components/Modtools.jsx:405
#: src/components/Modtools.jsx:486
#: src/components/Modtools.jsx:561
#: src/components/Modtools.jsx:653
#: src/components/Modtools.jsx:715
#: src/components/Modtools.jsx:798
#: src/components/windows/ForgotPassword.jsx:86
#: src/components/windows/Register.jsx:125
msgid "Submit"
msgstr ""
#: src/components/windows/CanvasSelect.jsx:33 #: src/components/windows/CanvasSelect.jsx:33
msgid "" msgid ""
"Select the canvas you want to use. Every canvas is unique and has " "Select the canvas you want to use. Every canvas is unique and has "
@ -683,88 +750,22 @@ msgstr ""
msgid "Enter your mail address and we will send you a new password:" msgid "Enter your mail address and we will send you a new password:"
msgstr "" msgstr ""
#: src/components/windows/ForgotPassword.jsx:82 #: src/components/windows/Chat.jsx:133
#: src/components/windows/Register.jsx:98
#: src/components/windows/Register.jsx:104
msgid "Email"
msgstr ""
#: src/components/Modtools.jsx:311
#: src/components/Modtools.jsx:392
#: src/components/Modtools.jsx:467
#: src/components/Modtools.jsx:512
#: src/components/Modtools.jsx:595
#: src/components/windows/ForgotPassword.jsx:86
#: src/components/windows/Register.jsx:125
msgid "Submit"
msgstr ""
#: src/components/windows/Chat.jsx:146
msgid "Channel settings" msgid "Channel settings"
msgstr "" msgstr ""
#: src/components/windows/Chat.jsx:161 #: src/components/windows/Chat.jsx:150
msgid "Start chatting here" msgid "Start chatting here"
msgstr "" msgstr ""
#: src/components/windows/Chat.jsx:198 #: src/components/windows/Chat.jsx:192
msgid "Chat here" msgid "Chat here"
msgstr "" msgstr ""
#: src/components/windows/Chat.jsx:221 #: src/components/windows/Chat.jsx:214
msgid "You must be logged in to chat" msgid "You must be logged in to chat"
msgstr "" msgstr ""
#: src/components/windows/UserArea.jsx:27
msgid "Profile"
msgstr ""
#: src/components/windows/UserArea.jsx:30
msgid "Ranking"
msgstr ""
#: src/components/windows/UserArea.jsx:33
msgid "Converter"
msgstr ""
#: src/components/windows/UserArea.jsx:39
msgid "Modtools"
msgstr ""
#: src/components/windows/UserArea.jsx:40
msgid "Loading..."
msgstr ""
#: src/components/windows/UserArea.jsx:47
msgid "Consider joining us on Guilded:"
msgstr ""
#: src/components/windows/Register.jsx:85
msgid "Register new account here"
msgstr ""
#: src/components/windows/Register.jsx:90
#: src/components/windows/Register.jsx:96
msgid "Name"
msgstr ""
#: src/components/ChangeMail.jsx:80
#: src/components/DeleteAccount.jsx:62
#: src/components/LogInForm.jsx:83
#: src/components/windows/Register.jsx:106
#: src/components/windows/Register.jsx:112
msgid "Password"
msgstr ""
#: src/components/windows/Register.jsx:114
#: src/components/windows/Register.jsx:120
msgid "Confirm Password"
msgstr ""
#: src/components/windows/Register.jsx:122
msgid "Captcha"
msgstr ""
#: src/components/Captcha.jsx:50 #: src/components/Captcha.jsx:50
#: src/components/Captcha.jsx:105 #: src/components/Captcha.jsx:105
msgid "Could not load captcha" msgid "Could not load captcha"
@ -823,7 +824,7 @@ msgid "Name can't be empty."
msgstr "" msgstr ""
#: src/utils/validation.js:31 #: src/utils/validation.js:31
msgid "Name must be at least 4 characters long" msgid "Name must be at least 2 characters long"
msgstr "" msgstr ""
#: src/utils/validation.js:32 #: src/utils/validation.js:32
@ -853,49 +854,28 @@ msgstr ""
msgid "Save" msgid "Save"
msgstr "" msgstr ""
#: src/components/CanvasItem.jsx:30 #: src/components/LogInArea.jsx:21
msgid "Online Users" msgid "Login to access more features and stats."
msgstr "" msgstr ""
#: src/components/CanvasItem.jsx:35 #: src/components/LogInArea.jsx:23
msgid "Cooldown" msgid "Login with Name or Mail:"
msgstr "" msgstr ""
#: src/components/CanvasItem.jsx:41 #: src/components/LogInArea.jsx:30
msgid "Stacking till" msgid "I forgot my Password."
msgstr "" msgstr ""
#: src/components/CanvasItem.jsx:43 #: src/components/LogInArea.jsx:31
msgid "Ranked" msgid "or login with:"
msgstr "" msgstr ""
#: src/components/CanvasItem.jsx:45 #: src/components/LogInArea.jsx:72
msgid "Yes" msgid "or register here:"
msgstr "" msgstr ""
#: src/components/CanvasItem.jsx:45 #: src/components/LogInArea.jsx:79
msgid "No" msgid "Register"
msgstr ""
#: src/components/CanvasItem.jsx:51
msgid "Requirements"
msgstr ""
#: src/components/CanvasItem.jsx:54
msgid "User Account"
msgstr ""
#: src/components/CanvasItem.jsx:56
#, javascript-format
msgid "and ${ canvas.req } Pixels set"
msgstr ""
#: src/components/CanvasItem.jsx:59
msgid "Top 10 Daily Ranking"
msgstr ""
#: src/components/CanvasItem.jsx:65
msgid "Dimensions"
msgstr "" msgstr ""
#: src/components/UserAreaContent.jsx:63 #: src/components/UserAreaContent.jsx:63
@ -955,81 +935,126 @@ msgstr ""
msgid "Ranking updates every 5 min. Daily rankings get reset at midnight UTC." msgid "Ranking updates every 5 min. Daily rankings get reset at midnight UTC."
msgstr "" msgstr ""
#: src/components/Modtools.jsx:184 #: src/components/Modtools.jsx:246
msgid "Build image on canvas." msgid "Build image on canvas."
msgstr "" msgstr ""
#: src/components/Modtools.jsx:187 #: src/components/Modtools.jsx:249
msgid "Build image and set it to protected." msgid "Build image and set it to protected."
msgstr "" msgstr ""
#: src/components/Modtools.jsx:190 #: src/components/Modtools.jsx:252
msgid "Build image, but reset cooldown to unset-pixel cd." msgid "Build image, but reset cooldown to unset-pixel cd."
msgstr "" msgstr ""
#: src/components/Modtools.jsx:253 #: src/components/Modtools.jsx:262
msgid "Clean spare pixels that are surrounded by unset pixels"
msgstr ""
#: src/components/Modtools.jsx:266
msgid ""
"Clean spare pixels that are surrounded by unset pixels and up to 1 other "
"set pixels"
msgstr ""
#: src/components/Modtools.jsx:270
msgid ""
"Clean spare pixels that are surrounded by a single other color or unset "
"pixels (VERY AGGRESSIVE ON CANVASES THAT ALLOW UNSET PIXELS (where there "
"are two cooldowns)!)"
msgstr ""
#: src/components/Modtools.jsx:292
msgid "Status: Not running"
msgstr ""
#: src/components/Modtools.jsx:347
msgid "Image Upload" msgid "Image Upload"
msgstr "" msgstr ""
#: src/components/Modtools.jsx:254 #: src/components/Modtools.jsx:348
msgid "Upload images to canvas" msgid "Upload images to canvas"
msgstr "" msgstr ""
#: src/components/Modtools.jsx:256 #: src/components/Modtools.jsx:350
msgid "File" msgid "File"
msgstr "" msgstr ""
#: src/components/Modtools.jsx:276 #: src/components/Modtools.jsx:370
msgid "Coordinates in X_Y format:" msgid "Coordinates in X_Y format:"
msgstr "" msgstr ""
#: src/components/Modtools.jsx:316 #: src/components/Modtools.jsx:410
msgid "Pixel Protection" msgid "Pixel Protection"
msgstr "" msgstr ""
#: src/components/Modtools.jsx:318 #: src/components/Modtools.jsx:412
msgid "" msgid ""
"Set protection of areas (if you need finer grained control, " "Set protection of areas (if you need finer grained control, "
"use protect with image upload and alpha layers)" "use protect with image upload and alpha layers)"
msgstr "" msgstr ""
#: src/components/Modtools.jsx:398 #: src/components/Modtools.jsx:432
#: src/components/Modtools.jsx:507
#: src/components/Modtools.jsx:591
msgid "Top-left corner"
msgstr ""
#: src/components/Modtools.jsx:450
#: src/components/Modtools.jsx:525
#: src/components/Modtools.jsx:609
msgid "Bottom-right corner"
msgstr ""
#: src/components/Modtools.jsx:492
msgid "Rollback to Date" msgid "Rollback to Date"
msgstr "" msgstr ""
#: src/components/Modtools.jsx:400 #: src/components/Modtools.jsx:494
msgid "Rollback an area of the canvas to a set date (00:00 UTC)" msgid "Rollback an area of the canvas to a set date (00:00 UTC)"
msgstr "" msgstr ""
#: src/components/Modtools.jsx:475 #: src/components/Modtools.jsx:567
msgid "Canvas Cleaner"
msgstr ""
#: src/components/Modtools.jsx:569
msgid "Apply a filter to clean trash in large canvas areas."
msgstr ""
#: src/components/Modtools.jsx:671
msgid "Stop Cleaner"
msgstr ""
#: src/components/Modtools.jsx:678
msgid "IP Actions" msgid "IP Actions"
msgstr "" msgstr ""
#: src/components/Modtools.jsx:477 #: src/components/Modtools.jsx:680
msgid "Do stuff with IPs (one IP per line)" msgid "Do stuff with IPs (one IP per line)"
msgstr "" msgstr ""
#: src/components/Modtools.jsx:516 #: src/components/Modtools.jsx:719
msgid "Manage Moderators" msgid "Manage Moderators"
msgstr "" msgstr ""
#: src/components/Modtools.jsx:518 #: src/components/Modtools.jsx:721
msgid "Remove Moderator" msgid "Remove Moderator"
msgstr "" msgstr ""
#: src/components/Modtools.jsx:550 #: src/components/Modtools.jsx:753
msgid "There are no mods" msgid "There are no mods"
msgstr "" msgstr ""
#: src/components/Modtools.jsx:555 #: src/components/Modtools.jsx:758
msgid "Assign new Mod" msgid "Assign new Mod"
msgstr "" msgstr ""
#: src/components/Modtools.jsx:558 #: src/components/Modtools.jsx:761
msgid "Enter UserName of new Mod" msgid "Enter UserName of new Mod"
msgstr "" msgstr ""
#: src/components/Modtools.jsx:567 #: src/components/Modtools.jsx:770
msgid "User Name" msgid "User Name"
msgstr "" msgstr ""
@ -1111,42 +1136,49 @@ msgstr ""
msgid "Download Template" msgid "Download Template"
msgstr "" msgstr ""
#: src/components/LogInArea.jsx:21 #: src/components/CanvasItem.jsx:30
msgid "Login to access more features and stats." msgid "Online Users"
msgstr "" msgstr ""
#: src/components/LogInArea.jsx:23 #: src/components/CanvasItem.jsx:35
msgid "Login with Name or Mail:" msgid "Cooldown"
msgstr "" msgstr ""
#: src/components/LogInArea.jsx:30 #: src/components/CanvasItem.jsx:41
msgid "I forgot my Password." msgid "Stacking till"
msgstr "" msgstr ""
#: src/components/LogInArea.jsx:31 #: src/components/CanvasItem.jsx:43
msgid "or login with:" msgid "Ranked"
msgstr "" msgstr ""
#: src/components/LogInArea.jsx:72 #: src/components/CanvasItem.jsx:45
msgid "or register here:" msgid "Yes"
msgstr "" msgstr ""
#: src/components/LogInArea.jsx:79 #: src/components/CanvasItem.jsx:45
msgid "Register" msgid "No"
msgstr "" msgstr ""
#: src/components/UserMessages.jsx:28 #: src/components/CanvasItem.jsx:51
msgid "" msgid "Requirements"
"Please verify your mail address \n"
"or your account could get deleted after a few days."
msgstr "" msgstr ""
#: src/components/UserMessages.jsx:49 #: src/components/CanvasItem.jsx:54
msgid "A new verification mail is getting sent to you." msgid "User Account"
msgstr "" msgstr ""
#: src/components/UserMessages.jsx:53 #: src/components/CanvasItem.jsx:56
msgid "Click here to request a new verification mail." #, javascript-format
msgid "and ${ canvas.req } Pixels set"
msgstr ""
#: src/components/CanvasItem.jsx:59
msgid "Top 10 Daily Ranking"
msgstr ""
#: src/components/CanvasItem.jsx:65
msgid "Dimensions"
msgstr "" msgstr ""
#: src/components/ChangePassword.jsx:22 #: src/components/ChangePassword.jsx:22
@ -1173,6 +1205,28 @@ msgstr ""
msgid "New Username" msgid "New Username"
msgstr "" msgstr ""
#: src/components/UserMessages.jsx:28
msgid ""
"Please verify your mail address \n"
"or your account could get deleted after a few days."
msgstr ""
#: src/components/UserMessages.jsx:49
msgid "A new verification mail is getting sent to you."
msgstr ""
#: src/components/UserMessages.jsx:53
msgid "Click here to request a new verification mail."
msgstr ""
#: src/components/LogInForm.jsx:76
msgid "Name or Email"
msgstr ""
#: src/components/LogInForm.jsx:87
msgid "LogIn"
msgstr ""
#: src/components/ChangeMail.jsx:59 #: src/components/ChangeMail.jsx:59
msgid "" msgid ""
"Changed Mail successfully. We sent you a verification mail, " "Changed Mail successfully. We sent you a verification mail, "
@ -1183,6 +1237,10 @@ msgstr ""
msgid "New Mail" msgid "New Mail"
msgstr "" msgstr ""
#: src/components/DeleteAccount.jsx:66
msgid "Yes, Delete My Account!"
msgstr ""
#: src/components/SocialSettings.jsx:38 #: src/components/SocialSettings.jsx:38
msgid "Block all Private Messages" msgid "Block all Private Messages"
msgstr "" msgstr ""
@ -1195,18 +1253,6 @@ msgstr ""
msgid "You have no users blocked" msgid "You have no users blocked"
msgstr "" msgstr ""
#: src/components/DeleteAccount.jsx:66
msgid "Yes, Delete My Account!"
msgstr ""
#: src/components/LogInForm.jsx:76
msgid "Name or Email"
msgstr ""
#: src/components/LogInForm.jsx:87
msgid "LogIn"
msgstr ""
#: src/components/windows/Help.jsx:14 #: src/components/windows/Help.jsx:14
#: src/components/windows/Settings.jsx:134 #: src/components/windows/Settings.jsx:134
msgctxt "keybinds" msgctxt "keybinds"

View File

@ -1,14 +1,17 @@
/* /*
* * basic functions for creating zommed tiles * basic functions for creating zommed tiles
* Used by tilewriter worker thread, so dont import too much.
*
* */ * */
/* eslint-disable no-console */
// Tile creation is allowed to be slow // Tile creation is allowed to be slow
/* eslint-disable no-await-in-loop */ /* eslint-disable no-await-in-loop */
import sharp from 'sharp'; import sharp from 'sharp';
import fs from 'fs'; import fs from 'fs';
import logger from './logger';
import { getMaxTiledZoom } from './utils'; import { getMaxTiledZoom } from './utils';
import { TILE_SIZE, TILE_ZOOM_LEVEL } from './constants'; import { TILE_SIZE, TILE_ZOOM_LEVEL } from './constants';
@ -171,7 +174,7 @@ export async function createZoomTileFromChunk(
.resize(TILE_SIZE) .resize(TILE_SIZE)
.png({ options: { compressionLevel: 6 } }) .png({ options: { compressionLevel: 6 } })
.toFile(filename); .toFile(filename);
logger.info( console.log(
// eslint-disable-next-line max-len // eslint-disable-next-line max-len
`Tiling: Created Tile ${filename} with ${na.length} empty chunks in ${Date.now() - startTime}ms`, `Tiling: Created Tile ${filename} with ${na.length} empty chunks in ${Date.now() - startTime}ms`,
); );
@ -228,7 +231,7 @@ export async function createZoomedTile(
}, },
}, },
).resize(TILE_SIZE).toFile(filename); ).resize(TILE_SIZE).toFile(filename);
logger.info( console.log(
// eslint-disable-next-line max-len // eslint-disable-next-line max-len
`Tiling: Created tile ${filename} with ${na.length} empty subtiles in ${Date.now() - startTime}ms.`, `Tiling: Created tile ${filename} with ${na.length} empty subtiles in ${Date.now() - startTime}ms.`,
); );
@ -269,7 +272,7 @@ export async function createEmptyTile(
}) })
.png({ options: { compressionLevel: 6 } }) .png({ options: { compressionLevel: 6 } })
.toFile(filename); .toFile(filename);
logger.info(`Tiling: Created empty tile at ${filename}`); console.log(`Tiling: Created empty tile at ${filename}`);
} }
/* /*
@ -343,7 +346,7 @@ export async function createTexture(
}, },
}, },
).toFile(filename); ).toFile(filename);
logger.info( console.log(
`Tiling: Created texture in ${(Date.now() - startTime) / 1000}s.`, `Tiling: Created texture in ${(Date.now() - startTime) / 1000}s.`,
); );
} }
@ -365,7 +368,7 @@ export async function initializeTiles(
palette, palette,
force: boolean = false, force: boolean = false,
) { ) {
logger.info( console.log(
`Tiling: Initializing tiles in ${canvasTileFolder}, forceint = ${force}`, `Tiling: Initializing tiles in ${canvasTileFolder}, forceint = ${force}`,
); );
const startTime = Date.now(); const startTime = Date.now();
@ -375,7 +378,7 @@ export async function initializeTiles(
// base zoomlevel // base zoomlevel
let zoom = maxTiledZoom - 1; let zoom = maxTiledZoom - 1;
let zoomDir = `${canvasTileFolder}/${zoom}`; let zoomDir = `${canvasTileFolder}/${zoom}`;
logger.info(`Tiling: Checking zoomlevel ${zoomDir}`); console.log(`Tiling: Checking zoomlevel ${zoomDir}`);
if (!fs.existsSync(zoomDir)) fs.mkdirSync(zoomDir); if (!fs.existsSync(zoomDir)) fs.mkdirSync(zoomDir);
let cnt = 0; let cnt = 0;
let cnts = 0; let cnts = 0;
@ -399,7 +402,7 @@ export async function initializeTiles(
} }
} }
} }
logger.info( console.log(
`Tiling: Created ${cnts} / ${cnt} tiles for basezoom of canvas${canvasId}`, `Tiling: Created ${cnts} / ${cnt} tiles for basezoom of canvas${canvasId}`,
); );
// zoomlevels that are created from other zoomlevels // zoomlevels that are created from other zoomlevels
@ -407,7 +410,7 @@ export async function initializeTiles(
cnt = 0; cnt = 0;
cnts = 0; cnts = 0;
zoomDir = `${canvasTileFolder}/${zoom}`; zoomDir = `${canvasTileFolder}/${zoom}`;
logger.info(`Tiling: Checking zoomlevel ${zoomDir}`); console.log(`Tiling: Checking zoomlevel ${zoomDir}`);
if (!fs.existsSync(zoomDir)) fs.mkdirSync(zoomDir); if (!fs.existsSync(zoomDir)) fs.mkdirSync(zoomDir);
const maxZ = TILE_ZOOM_LEVEL ** zoom; const maxZ = TILE_ZOOM_LEVEL ** zoom;
for (let cx = 0; cx < maxZ; cx += 1) { for (let cx = 0; cx < maxZ; cx += 1) {
@ -426,7 +429,7 @@ export async function initializeTiles(
} }
} }
} }
logger.info( console.log(
// eslint-disable-next-line max-len // eslint-disable-next-line max-len
`Tiling: Created ${cnts} / ${cnt} tiles for zoom ${zoom} for canvas${canvasId}`, `Tiling: Created ${cnts} / ${cnt} tiles for zoom ${zoom} for canvas${canvasId}`,
); );
@ -440,7 +443,7 @@ export async function initializeTiles(
palette, palette,
); );
//-- //--
logger.info( console.log(
// eslint-disable-next-line max-len // eslint-disable-next-line max-len
`Tiling: Elapsed Time: ${Math.round((Date.now() - startTime) / 1000)} for canvas${canvasId}`, `Tiling: Elapsed Time: ${Math.round((Date.now() - startTime) / 1000)} for canvas${canvasId}`,
); );

View File

@ -1,9 +1,7 @@
/* /*
* draw pixel on canvas * draw pixel on canvas
*/ */
import { using } from 'bluebird';
import { redlock } from '../data/redis';
import { import {
getPixelFromChunkOffset, getPixelFromChunkOffset,
} from './utils'; } from './utils';
@ -375,76 +373,3 @@ export async function drawByCoords(
coolDownSeconds: coolDown / 1000, coolDownSeconds: coolDown / 1000,
}; };
} }
/**
* This function is a wrapper for draw. It fixes race condition exploits
* It permits just placing one pixel at a time per user.
*
* @param user
* @param canvasId
* @param color
* @param x
* @param y
* @param z (optional for 3d canvas)
*/
export function drawSafeByCoords(
user,
canvasId,
color,
x,
y,
z = null,
) {
// can just check for one unique occurence,
// we use ip, because id for logged out users is
// always null
const userId = user.ip;
return new Promise((resolve) => {
using(
redlock.disposer(`locks:${userId}`, 5000, logger.error),
async () => {
const ret = await drawByCoords(user, canvasId, color, x, y, z);
resolve(ret);
},
); // <-- unlock is automatically handled by bluebird
});
}
/**
* This function is a wrapper for draw. It fixes race condition exploits
* It permits just placing one pixel at a time per user.
*
* @param user
* @param canvasId
* @param i Chunk coordinates
* @param j
* @param pixels Array of indiviual pixels within the chunk, with:
* [[offset, color], [offset2, color2],...]
* Offset is the offset of the pixel within the chunk
* @return Promise<Object>
*/
export function drawSafeByOffsets(
user,
canvasId,
i,
j,
pixels,
) {
// can just check for one unique occurence,
// we use ip, because id for logged out users is
// always null
const userId = user.ip;
return new Promise((resolve) => {
using(
redlock.disposer(`locks:${userId}`, 5000, logger.error),
async () => {
const ret = await drawByOffsets(user, canvasId, i, j, pixels);
resolve(ret);
},
); // <-- unlock is automatically handled by bluebird
});
}

View File

@ -1,5 +1,5 @@
/* /*
* creation of tiles * creation of zoom tiles
* *
*/ */
@ -16,18 +16,16 @@ import {
TILE_SIZE, TILE_SIZE,
TILE_ZOOM_LEVEL, TILE_ZOOM_LEVEL,
} from './constants'; } from './constants';
import {
createZoomTileFromChunk,
createZoomedTile,
createTexture,
initializeTiles,
} from './Tile';
import { mod, getMaxTiledZoom } from './utils'; import { mod, getMaxTiledZoom } from './utils';
// Array that holds cells of all changed base zoomlevel tiles
const CanvasUpdaters = {}; const CanvasUpdaters = {};
/*
* worker thread
*/
const worker = new Worker('./workers/tilewriter.js');
class CanvasUpdater { class CanvasUpdater {
TileLoadingQueues; TileLoadingQueues;
palette; palette;
@ -63,30 +61,37 @@ class CanvasUpdater {
const cy = Math.floor(tile / width); const cy = Math.floor(tile / width);
if (zoom === this.maxTiledZoom - 1) { if (zoom === this.maxTiledZoom - 1) {
await createZoomTileFromChunk( worker.postMessage({
RedisCanvas, task: 'createZoomTileFromChunk',
this.canvas.size, args: [
this.id, this.canvas.size,
this.canvasTileFolder, this.id,
this.palette, this.canvasTileFolder,
[cx, cy], this.palette,
); [cx, cy],
],
});
} else if (zoom !== this.maxTiledZoom) { } else if (zoom !== this.maxTiledZoom) {
await createZoomedTile( worker.postMessage({
this.canvasTileFolder, task: 'createZoomedTile',
this.palette, args: [
[zoom, cx, cy], this.canvasTileFolder,
); this.palette,
[zoom, cx, cy],
],
});
} }
if (zoom === 0) { if (zoom === 0) {
createTexture( worker.postMessage({
RedisCanvas, task: 'createTexture',
this.id, args: [
this.canvas.size, this.id,
this.canvasTileFolder, this.canvas.size,
this.palette, this.canvasTileFolder,
); this.palette,
],
});
} else { } else {
const [ucx, ucy] = [cx, cy].map((z) => Math.floor(z / 4)); const [ucx, ucy] = [cx, cy].map((z) => Math.floor(z / 4));
const upperTile = ucx + ucy * (TILE_ZOOM_LEVEL ** (zoom - 1)); const upperTile = ucx + ucy * (TILE_ZOOM_LEVEL ** (zoom - 1));
@ -115,6 +120,28 @@ class CanvasUpdater {
); );
} }
initializeTiles() {
return new Promise((resolve) => {
worker.postMessage({
task: 'initializeTiles',
args: [
this.canvas.size,
this.id,
this.canvasTileFolder,
this.palette,
false,
],
});
worker.once('message', (msg) => {
logger.info(
// eslint-disable-next-line max-len
`Tiling: Worker thread finished initializing Tiles with message ${msg}`,
);
resolve();
});
});
}
/* /*
* initialize queues and start loops for updating tiles * initialize queues and start loops for updating tiles
*/ */
@ -127,14 +154,7 @@ class CanvasUpdater {
logger.warn( logger.warn(
'Tiling: tiledir empty, will initialize it, this can take some time', 'Tiling: tiledir empty, will initialize it, this can take some time',
); );
await initializeTiles( await this.initializeTiles();
RedisCanvas,
this.canvas.size,
this.id,
this.canvasTileFolder,
this.palette,
false,
);
} }
for (let c = 0; c < this.maxTiledZoom; c += 1) { for (let c = 0; c < this.maxTiledZoom; c += 1) {
this.TileLoadingQueues.push([]); this.TileLoadingQueues.push([]);

View File

@ -8,7 +8,6 @@ import {
} from '../../core/constants'; } from '../../core/constants';
// eslint-disable-next-line import/no-unresolved // eslint-disable-next-line import/no-unresolved
import canvases from './canvases.json'; import canvases from './canvases.json';
import logger from '../../core/logger';
import redis from '../redis'; import redis from '../redis';
@ -48,7 +47,8 @@ class RedisCanvas {
static async setChunk(i: number, j: number, chunk: Uint8Array, static async setChunk(i: number, j: number, chunk: Uint8Array,
canvasId: number) { canvasId: number) {
if (chunk.length !== TILE_SIZE * TILE_SIZE) { if (chunk.length !== TILE_SIZE * TILE_SIZE) {
logger.error(`Tried to set chunk with invalid length ${chunk.length}!`); // eslint-disable-next-line no-console
console.error(`Tried to set chunk with invalid length ${chunk.length}!`);
return false; return false;
} }
const key = `ch:${canvasId}:${i}:${j}`; const key = `ch:${canvasId}:${i}:${j}`;

42
src/workers/tilewriter.js Normal file
View File

@ -0,0 +1,42 @@
/*
* worker thread for ..core/tileserver.js
*/
/* eslint-disable no-console */
import { isMainThread, parentPort } from 'worker_threads';
import RedisCanvas from '../data/models/RedisCanvas';
import {
createZoomTileFromChunk,
createZoomedTile,
createTexture,
initializeTiles,
} from '../core/Tile';
if (isMainThread) {
throw new Error(
'Tilewriter is run as a worker thread, not as own process',
);
}
parentPort.on('message', async (msg) => {
const { task, args } = msg;
switch (task) {
case 'createZoomTileFromChunk':
createZoomTileFromChunk(RedisCanvas, ...args);
break;
case 'createZoomedTile':
createZoomedTile(...args);
break;
case 'createTexture':
createTexture(RedisCanvas, ...args);
break;
case 'initializeTiles':
await initializeTiles(RedisCanvas, ...args);
parentPort.postMessage('Done!');
break;
default:
console.warn(`Tiling: Main thread requested unknown task ${task}`);
}
});

View File

@ -51,6 +51,7 @@ export default ({
entry: { entry: {
server: [path.resolve(__dirname, 'src', 'server.js')], server: [path.resolve(__dirname, 'src', 'server.js')],
backup: [path.resolve(__dirname, 'src', 'backup.js')], backup: [path.resolve(__dirname, 'src', 'backup.js')],
'workers/tilewriter': [path.resolve(__dirname, 'src', 'workers', 'tilewriter.js')],
captchaserver: [path.resolve(__dirname, 'src', 'captchaserver.js')], captchaserver: [path.resolve(__dirname, 'src', 'captchaserver.js')],
}, },