Switch from p-throttle to p-queue

pull/1317/head
Lim Chee Aun 2025-10-13 13:31:56 +08:00
rodzic 22ae402631
commit 6b347fa88b
8 zmienionych plików z 303 dodań i 215 usunięć

32
package-lock.json wygenerowano
Wyświetl plik

@ -32,8 +32,8 @@
"lz-string": "~1.5.0",
"masto": "~7.2.0",
"moize": "~6.1.6",
"p-queue": "~9.0.0",
"p-retry": "~7.1.0",
"p-throttle": "~8.0.0",
"preact": "10.27.2",
"punycode": "~2.3.1",
"react-hotkeys-hook": "~5.1.0",
@ -6094,6 +6094,12 @@
"node": ">=0.10.0"
}
},
"node_modules/eventemitter3": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz",
"integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==",
"license": "MIT"
},
"node_modules/events-to-async": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/events-to-async/-/events-to-async-2.0.1.tgz",
@ -7976,6 +7982,22 @@
"node": ">=8"
}
},
"node_modules/p-queue": {
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/p-queue/-/p-queue-9.0.0.tgz",
"integrity": "sha512-KO1RyxstL9g1mK76530TExamZC/S2Glm080Nx8PE5sTd7nlduDQsAfEl4uXX+qZjLiwvDauvzXavufy3+rJ9zQ==",
"license": "MIT",
"dependencies": {
"eventemitter3": "^5.0.1",
"p-timeout": "^7.0.0"
},
"engines": {
"node": ">=20"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/p-retry": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/p-retry/-/p-retry-7.1.0.tgz",
@ -7991,10 +8013,10 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/p-throttle": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/p-throttle/-/p-throttle-8.0.0.tgz",
"integrity": "sha512-kvpi14SZClZqNTLevyhCNQano1LH4clozDZoOdxnxyvEl17kjEKxkgD6to7mQMcWE4fMKAwbH0rLqm6Gjj7b2Q==",
"node_modules/p-timeout": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-7.0.1.tgz",
"integrity": "sha512-AxTM2wDGORHGEkPCt8yqxOTMgpfbEHqF51f/5fJCmwFC3C/zNcGT63SymH2ttOAaiIws2zVg4+izQCjrakcwHg==",
"license": "MIT",
"engines": {
"node": ">=20"

Wyświetl plik

@ -45,8 +45,8 @@
"lz-string": "~1.5.0",
"masto": "~7.2.0",
"moize": "~6.1.6",
"p-queue": "~9.0.0",
"p-retry": "~7.1.0",
"p-throttle": "~8.0.0",
"preact": "10.27.2",
"punycode": "~2.3.1",
"react-hotkeys-hook": "~5.1.0",

Wyświetl plik

@ -1,4 +1,4 @@
import pThrottle from 'p-throttle';
import PQueue from 'p-queue';
import { useEffect, useState } from 'preact/hooks';
import { getGifFirstFrame } from '../utils/get-gif-first-frame';
@ -6,10 +6,14 @@ import mem from '../utils/mem';
import CustomEmoji from './custom-emoji';
const throttledFetch = pThrottle({
limit: 2,
const fetchQueue = new PQueue({
concurrency: 2,
interval: 1000,
})(fetch);
intervalCap: 2,
});
const throttledFetch = (signal, ...args) =>
fetchQueue.add(() => fetch(...args), { signal });
const SHORTCODES_REGEX = /(\:(\w|\+|\-)+\:)(?=|[\!\.\?]|$)/g;
@ -35,12 +39,18 @@ function EmojiText({ text, emojis = [], staticEmoji, resolverURL }) {
setLoading(true);
const abortController = new AbortController();
(async () => {
try {
const response = await throttledFetch(resolverURL, {
headers: { accept: 'application/activity+json' },
referrerPolicy: 'no-referrer',
});
const response = await throttledFetch(
abortController.signal,
resolverURL,
{
headers: { accept: 'application/activity+json' },
referrerPolicy: 'no-referrer',
},
);
const data = await response.json();
const emojiTags = data.tag?.filter((t) => t.type === 'Emoji') || [];
@ -64,11 +74,17 @@ function EmojiText({ text, emojis = [], staticEmoji, resolverURL }) {
setResolvedEmojis(emojis);
} catch (error) {
console.error('Failed to resolve emojis:', error);
if (error.name !== 'AbortError') {
console.error('Failed to resolve emojis:', error);
}
} finally {
setLoading(false);
}
})();
return () => {
abortController.abort();
};
}, [resolverURL, text, emojis?.length]);
if (!text) return '';

Wyświetl plik

@ -65,21 +65,28 @@ function StatusCard({ card, selfReferential, selfAuthor, instance }) {
const [cardStatusURL, setCardStatusURL] = useState(null);
// const [cardStatusID, setCardStatusID] = useState(null);
useEffect(() => {
if (hasText && image && !selfReferential && isMastodonLinkMaybe(url)) {
unfurlMastodonLink(instance, url).then((result) => {
if (!result) return;
const { id, url } = result;
setCardStatusURL('#' + url);
// NOTE: This is for quote post
// (async () => {
// const { masto } = api({ instance });
// const status = await masto.v1.statuses.$select(id).fetch();
// saveStatus(status, instance);
// setCardStatusID(id);
// })();
});
if (!hasText || !image || selfReferential || !isMastodonLinkMaybe(url)) {
return;
}
const abortController = new AbortController();
unfurlMastodonLink(instance, url, abortController.signal).then((result) => {
if (!result) return;
const { id, url } = result;
setCardStatusURL('#' + url);
// NOTE: This is for quote post
// (async () => {
// const { masto } = api({ instance });
// const status = await masto.v1.statuses.$select(id).fetch();
// saveStatus(status, instance);
// setCardStatusID(id);
// })();
});
return () => {
abortController.abort();
};
}, [hasText, image, selfReferential]);
// if (cardStatusID) {

Wyświetl plik

@ -4,7 +4,7 @@ import { msg, plural } from '@lingui/core/macro';
import { Plural, Trans, useLingui } from '@lingui/react/macro';
import { ControlledMenu, MenuDivider, MenuItem } from '@szhsin/react-menu';
import { shallowEqual } from 'fast-equals';
import pThrottle from 'p-throttle';
import PQueue from 'p-queue';
import { Fragment } from 'preact';
import { memo } from 'preact/compat';
import {
@ -83,14 +83,17 @@ import TranslationBlock from './translation-block';
const SHOW_COMMENT_COUNT_LIMIT = 280;
const INLINE_TRANSLATE_LIMIT = 140;
const throttle = pThrottle({
limit: 1,
const accountQueue = new PQueue({
concurrency: 1,
interval: 1000,
intervalCap: 1,
});
function fetchAccount(id, masto) {
return masto.v1.accounts.$select(id).fetch();
function fetchAccount(id, masto, signal) {
return accountQueue.add(() => masto.v1.accounts.$select(id).fetch(), {
signal,
});
}
const memFetchAccount = pmem(throttle(fetchAccount));
const memFetchAccount = pmem(fetchAccount);
const isIOS =
window.ontouchstart !== undefined &&
@ -520,19 +523,27 @@ function Status({
inReplyToAccountRef = { url: accountURL, username, displayName };
}
const [inReplyToAccount, setInReplyToAccount] = useState(inReplyToAccountRef);
if (!withinContext && !inReplyToAccount && inReplyToAccountId) {
const account = states.accounts[inReplyToAccountId];
if (account) {
setInReplyToAccount(account);
} else {
memFetchAccount(inReplyToAccountId, masto)
useEffect(() => {
if (!withinContext && !inReplyToAccount && inReplyToAccountId) {
const account = states.accounts[inReplyToAccountId];
if (account) {
setInReplyToAccount(account);
return;
}
const abortController = new AbortController();
memFetchAccount(inReplyToAccountId, masto, abortController.signal)
.then((account) => {
setInReplyToAccount(account);
states.accounts[account.id] = account;
})
.catch((e) => {});
return () => {
abortController.abort();
};
}
}
}, [withinContext, inReplyToAccount, inReplyToAccountId]);
const mentionSelf =
(inReplyToAccountId && inReplyToAccountId === currentAccount) ||
mentions?.find((mention) => mention.id === currentAccount);

Wyświetl plik

@ -1,8 +1,8 @@
import './translation-block.css';
import { Trans, useLingui } from '@lingui/react/macro';
import PQueue from 'p-queue';
import pRetry from 'p-retry';
import pThrottle from 'p-throttle';
import { useEffect, useRef, useState } from 'preact/hooks';
import languages from '../data/translang-languages';
@ -28,9 +28,10 @@ const TRANSLANG_INSTANCES = PHANPY_TRANSLANG_INSTANCES
? PHANPY_TRANSLANG_INSTANCES.split(/\s+/)
: [];
const throttle = pThrottle({
limit: 1,
const translationQueue = new PQueue({
concurrency: 1,
interval: 2000,
intervalCap: 1,
});
const TRANSLATED_MAX_AGE = 1000 * 60 * 60; // 1 hour
@ -98,12 +99,21 @@ function _translangTranslate(text, source, target) {
const translangTranslate = pmem(_translangTranslate, {
maxAge: TRANSLATED_MAX_AGE,
});
const throttledTranslangTranslate = pmem(throttle(translangTranslate), {
// I know, this is double-layered memoization
maxAge: TRANSLATED_MAX_AGE,
});
const throttledTranslangTranslate = pmem(
({ signal, text, source, target }) =>
translationQueue.add(() => translangTranslate(text, source, target), {
signal,
}),
{
// I know, this is double-layered memoization
maxAge: TRANSLATED_MAX_AGE,
},
);
const throttledBrowserTranslate = throttle(browserTranslate);
const throttledBrowserTranslate = ({ text, source, target, signal }) =>
translationQueue.add(() => browserTranslate(text, source, target), {
signal,
});
function TranslationBlock({
forceTranslate,
@ -120,6 +130,7 @@ function TranslationBlock({
const [translatedContent, setTranslatedContent] = useState(null);
const [detectedLang, setDetectedLang] = useState(null);
const detailsRef = useRef();
const abortControllerRef = useRef();
const sourceLangText = sourceLanguage
? localeCode2Text(sourceLanguage)
@ -128,16 +139,21 @@ function TranslationBlock({
const apiSourceLang = useRef('auto');
if (!onTranslate) {
onTranslate = async (...args) => {
onTranslate = async ({ text, source, target, signal }) => {
if (supportsBrowserTranslator) {
const result = await throttledBrowserTranslate(...args);
const result = await throttledBrowserTranslate({
text,
source,
target,
signal,
});
if (result && !result.error) {
return result;
}
}
return mini
? await throttledTranslangTranslate(...args)
: await translangTranslate(...args);
? await throttledTranslangTranslate({ signal, text, source, target })
: await translangTranslate(text, source, target);
};
}
@ -145,7 +161,12 @@ function TranslationBlock({
setUIState('loading');
try {
const { content, detectedSourceLanguage, provider, error, ...props } =
await onTranslate(text, apiSourceLang.current, targetLang);
await onTranslate({
text,
source: apiSourceLang.current,
target: targetLang,
signal: abortControllerRef.current?.signal,
});
if (content) {
if (detectedSourceLanguage) {
const detectedLangText = localeCode2Text(detectedSourceLanguage);
@ -171,8 +192,10 @@ function TranslationBlock({
setUIState('error');
}
} catch (e) {
console.error(e);
setUIState('error');
if (e.name !== 'AbortError') {
console.error(e);
setUIState('error');
}
}
};
@ -182,6 +205,13 @@ function TranslationBlock({
}
}, [forceTranslate]);
useEffect(() => {
abortControllerRef.current = new AbortController();
return () => {
abortControllerRef.current.abort();
};
}, []);
if (mini) {
if (
!!translatedContent &&

308
src/locales/en.po wygenerowano
Wyświetl plik

@ -34,7 +34,7 @@ msgstr ""
#: src/components/account-block.jsx:177
#: src/components/account-info.jsx:683
#: src/components/status.jsx:569
#: src/components/status.jsx:580
msgid "Group"
msgstr ""
@ -115,11 +115,11 @@ msgstr ""
#: src/components/media-attachment.jsx:397
#: src/components/media-modal.jsx:363
#: src/components/related-actions.jsx:238
#: src/components/status.jsx:2114
#: src/components/status.jsx:2131
#: src/components/status.jsx:2267
#: src/components/status.jsx:2955
#: src/components/status.jsx:2958
#: src/components/status.jsx:2125
#: src/components/status.jsx:2142
#: src/components/status.jsx:2278
#: src/components/status.jsx:2966
#: src/components/status.jsx:2969
#: src/pages/account-statuses.jsx:544
#: src/pages/accounts.jsx:118
#: src/pages/hashtag.jsx:203
@ -232,7 +232,7 @@ msgid "Original"
msgstr ""
#: src/components/account-info.jsx:978
#: src/components/status.jsx:2684
#: src/components/status.jsx:2695
#: src/pages/catchup.jsx:71
#: src/pages/catchup.jsx:1463
#: src/pages/catchup.jsx:2106
@ -289,8 +289,8 @@ msgstr "View post stats"
#: src/components/shortcuts-settings.jsx:230
#: src/components/shortcuts-settings.jsx:583
#: src/components/shortcuts-settings.jsx:783
#: src/components/status.jsx:3199
#: src/components/status.jsx:3411
#: src/components/status.jsx:3210
#: src/components/status.jsx:3422
#: src/components/translated-bio-sheet.jsx:21
#: src/pages/accounts.jsx:45
#: src/pages/catchup.jsx:1600
@ -509,7 +509,7 @@ msgid "Attachment #{i} failed"
msgstr "Attachment #{i} failed"
#: src/components/compose.jsx:1418
#: src/components/status.jsx:2451
#: src/components/status.jsx:2462
#: src/components/timeline.jsx:1009
msgid "Content warning"
msgstr ""
@ -549,21 +549,21 @@ msgstr "Posting on <0/>"
#: src/components/compose.jsx:1867
#: src/components/quote-settings-sheet.jsx:73
#: src/components/status.jsx:313
#: src/components/status.jsx:316
#: src/pages/settings.jsx:381
msgid "Anyone can quote"
msgstr "Anyone can quote"
#: src/components/compose.jsx:1870
#: src/components/quote-settings-sheet.jsx:76
#: src/components/status.jsx:314
#: src/components/status.jsx:317
#: src/pages/settings.jsx:384
msgid "Your followers can quote"
msgstr "Your followers can quote"
#: src/components/compose.jsx:1873
#: src/components/quote-settings-sheet.jsx:79
#: src/components/status.jsx:315
#: src/components/status.jsx:318
#: src/pages/settings.jsx:387
msgid "Only you can quote"
msgstr "Only you can quote"
@ -588,7 +588,7 @@ msgid "Quiet public"
msgstr "Quiet public"
#: src/components/compose.jsx:1921
#: src/components/status.jsx:2331
#: src/components/status.jsx:2342
#: src/utils/visibility-text.jsx:8
msgid "Private mention"
msgstr ""
@ -599,14 +599,14 @@ msgstr "Schedule"
#: src/components/compose.jsx:1975
#: src/components/keyboard-shortcuts-help.jsx:155
#: src/components/status.jsx:1062
#: src/components/status.jsx:1096
#: src/components/status.jsx:2080
#: src/components/status.jsx:2081
#: src/components/status.jsx:2093
#: src/components/status.jsx:2094
#: src/components/status.jsx:2812
#: src/components/status.jsx:2824
#: src/components/status.jsx:1073
#: src/components/status.jsx:1107
#: src/components/status.jsx:2091
#: src/components/status.jsx:2092
#: src/components/status.jsx:2104
#: src/components/status.jsx:2105
#: src/components/status.jsx:2823
#: src/components/status.jsx:2835
msgid "Reply"
msgstr ""
@ -679,7 +679,7 @@ msgstr ""
#: src/components/drafts.jsx:126
#: src/components/list-add-edit.jsx:188
#: src/components/status.jsx:1604
#: src/components/status.jsx:1615
#: src/pages/filters.jsx:603
#: src/pages/scheduled-posts.jsx:368
msgid "Delete…"
@ -721,7 +721,7 @@ msgstr ""
#: src/components/drafts.jsx:270
#: src/components/keyboard-shortcuts-help.jsx:184
#: src/components/status.jsx:725
#: src/components/status.jsx:736
msgid "Quote"
msgstr ""
@ -994,9 +994,9 @@ msgid "<0>l</0> or <1>f</1>"
msgstr ""
#: src/components/keyboard-shortcuts-help.jsx:176
#: src/components/status.jsx:1132
#: src/components/status.jsx:2854
#: src/components/status.jsx:2909
#: src/components/status.jsx:1143
#: src/components/status.jsx:2865
#: src/components/status.jsx:2920
msgid "Boost"
msgstr ""
@ -1005,9 +1005,9 @@ msgid "<0>Shift</0> + <1>b</1>"
msgstr ""
#: src/components/keyboard-shortcuts-help.jsx:188
#: src/components/status.jsx:1234
#: src/components/status.jsx:2934
#: src/components/status.jsx:2935
#: src/components/status.jsx:1245
#: src/components/status.jsx:2945
#: src/components/status.jsx:2946
msgid "Bookmark"
msgstr ""
@ -1090,14 +1090,14 @@ msgid "Media description"
msgstr ""
#: src/components/media-alt-modal.jsx:67
#: src/components/status.jsx:1289
#: src/components/status.jsx:1298
#: src/components/translation-block.jsx:239
#: src/components/status.jsx:1300
#: src/components/status.jsx:1309
#: src/components/translation-block.jsx:269
msgid "Translate"
msgstr ""
#: src/components/media-alt-modal.jsx:78
#: src/components/status.jsx:1319
#: src/components/status.jsx:1330
msgid "Speak"
msgstr ""
@ -1224,8 +1224,8 @@ msgstr ""
#: src/components/media-post.jsx:133
#: src/components/status-compact.jsx:70
#: src/components/status.jsx:3337
#: src/components/status.jsx:3415
#: src/components/status.jsx:3348
#: src/components/status.jsx:3426
#: src/components/timeline.jsx:998
#: src/pages/catchup.jsx:76
#: src/pages/catchup.jsx:1921
@ -1554,8 +1554,8 @@ msgid "[Unknown notification type: {type}]"
msgstr ""
#: src/components/notification.jsx:463
#: src/components/status.jsx:1248
#: src/components/status.jsx:1258
#: src/components/status.jsx:1259
#: src/components/status.jsx:1269
msgid "Boosted/Liked by…"
msgstr ""
@ -1581,19 +1581,19 @@ msgid "View #Wrapstodon"
msgstr "View #Wrapstodon"
#: src/components/notification.jsx:813
#: src/components/status.jsx:276
#: src/components/status.jsx:279
msgid "Read more →"
msgstr ""
#: src/components/open-link-sheet.jsx:30
#: src/components/related-actions.jsx:492
#: src/components/status.jsx:1410
#: src/components/status.jsx:1421
msgid "Link copied"
msgstr ""
#: src/components/open-link-sheet.jsx:33
#: src/components/related-actions.jsx:495
#: src/components/status.jsx:1413
#: src/components/status.jsx:1424
msgid "Unable to copy link"
msgstr ""
@ -1605,13 +1605,13 @@ msgstr "Open link?"
#: src/components/post-embed-modal.jsx:232
#: src/components/related-actions.jsx:501
#: src/components/shortcuts-settings.jsx:1059
#: src/components/status.jsx:1419
#: src/components/status.jsx:1430
msgid "Copy"
msgstr ""
#: src/components/open-link-sheet.jsx:82
#: src/components/related-actions.jsx:522
#: src/components/status.jsx:1441
#: src/components/status.jsx:1452
msgid "Share…"
msgstr ""
@ -1679,7 +1679,7 @@ msgid "Ending"
msgstr "Ending"
#: src/components/post-embed-modal.jsx:201
#: src/components/status.jsx:1454
#: src/components/status.jsx:1465
msgid "Embed post"
msgstr ""
@ -1908,7 +1908,7 @@ msgstr "Show featured profiles"
#: src/components/related-actions.jsx:516
#: src/components/shortcuts-settings.jsx:1077
#: src/components/status.jsx:1435
#: src/components/status.jsx:1446
msgid "Sharing doesn't seem to work."
msgstr ""
@ -2246,7 +2246,7 @@ msgid "Move down"
msgstr ""
#: src/components/shortcuts-settings.jsx:379
#: src/components/status.jsx:1566
#: src/components/status.jsx:1577
#: src/pages/list.jsx:195
msgid "Edit"
msgstr ""
@ -2445,348 +2445,348 @@ msgstr ""
msgid "Import/export settings from/to instance server (Very experimental)"
msgstr ""
#: src/components/status.jsx:305
#: src/components/status.jsx:308
msgid "Private posts cannot be quoted"
msgstr "Private posts cannot be quoted"
#: src/components/status.jsx:306
#: src/components/status.jsx:309
msgid "Request to quote"
msgstr "Request to quote"
#: src/components/status.jsx:307
#: src/components/status.jsx:310
msgid "Author will manually review"
msgstr "Author will manually review"
#: src/components/status.jsx:308
#: src/components/status.jsx:311
msgid "Only followers can quote this post"
msgstr "Only followers can quote this post"
#: src/components/status.jsx:309
#: src/components/status.jsx:312
msgid "You are not allowed to quote this post"
msgstr "You are not allowed to quote this post"
#: src/components/status.jsx:593
#: src/components/status.jsx:604
msgid "<0/> <1>boosted</1>"
msgstr "<0/> <1>boosted</1>"
#: src/components/status.jsx:699
#: src/components/status.jsx:710
msgid "Sorry, your current logged-in instance can't interact with this post from another instance."
msgstr ""
#. placeholder {0}: username || acct
#: src/components/status.jsx:888
#: src/components/status.jsx:899
msgid "Unliked @{0}'s post"
msgstr ""
#. placeholder {0}: username || acct
#: src/components/status.jsx:889
#: src/components/status.jsx:900
msgid "Liked @{0}'s post"
msgstr "Liked @{0}'s post"
#. placeholder {0}: username || acct
#: src/components/status.jsx:928
#: src/components/status.jsx:939
msgid "Unbookmarked @{0}'s post"
msgstr "Unbookmarked @{0}'s post"
#. placeholder {0}: username || acct
#: src/components/status.jsx:929
#: src/components/status.jsx:940
msgid "Bookmarked @{0}'s post"
msgstr "Bookmarked @{0}'s post"
#: src/components/status.jsx:1033
#: src/components/status.jsx:1044
msgid "Some media have no descriptions."
msgstr ""
#. placeholder {0}: rtf.format(-statusMonthsAgo, 'month')
#: src/components/status.jsx:1040
#: src/components/status.jsx:1051
msgid "Old post (<0>{0}</0>)"
msgstr ""
#: src/components/status.jsx:1061
#: src/components/status.jsx:1072
msgid "Reply…"
msgstr "Reply…"
#: src/components/status.jsx:1070
#: src/components/status.jsx:1079
#: src/components/status.jsx:1081
#: src/components/status.jsx:1090
msgid "Reply all"
msgstr "Reply all"
#: src/components/status.jsx:1073
#: src/components/status.jsx:1084
msgid "{mentionsCount, plural, other {# mentions}}"
msgstr "{mentionsCount, plural, other {# mentions}}"
#. placeholder {0}: mentionsCount - 1
#. placeholder {1}: username || acct
#: src/components/status.jsx:1082
#: src/components/status.jsx:1093
msgid "{0, plural, other {<0>@{1}</0> first, # others below}}"
msgstr "{0, plural, other {<0>@{1}</0> first, # others below}}"
#. placeholder {0}: username || acct
#: src/components/status.jsx:1099
#: src/components/status.jsx:1110
msgid "Only <0>@{0}</0>"
msgstr "Only <0>@{0}</0>"
#: src/components/status.jsx:1132
#: src/components/status.jsx:1209
#: src/components/status.jsx:2854
#: src/components/status.jsx:2907
#: src/components/status.jsx:1143
#: src/components/status.jsx:1220
#: src/components/status.jsx:2865
#: src/components/status.jsx:2918
msgid "Unboost"
msgstr ""
#: src/components/status.jsx:1171
#: src/components/status.jsx:2892
#: src/components/status.jsx:1182
#: src/components/status.jsx:2903
msgid "Quote with link"
msgstr "Quote with link"
#. placeholder {0}: username || acct
#: src/components/status.jsx:1188
#: src/components/status.jsx:1755
#: src/components/status.jsx:1199
#: src/components/status.jsx:1766
msgid "Unboosted @{0}'s post"
msgstr "Unboosted @{0}'s post"
#. placeholder {0}: username || acct
#: src/components/status.jsx:1189
#: src/components/status.jsx:1756
#: src/components/status.jsx:1200
#: src/components/status.jsx:1767
msgid "Boosted @{0}'s post"
msgstr "Boosted @{0}'s post"
#: src/components/status.jsx:1211
#: src/components/status.jsx:2906
#: src/components/status.jsx:1222
#: src/components/status.jsx:2917
msgid "Boost/Quote…"
msgstr "Boost/Quote…"
#: src/components/status.jsx:1212
#: src/components/status.jsx:2906
#: src/components/status.jsx:1223
#: src/components/status.jsx:2917
msgid "Boost…"
msgstr ""
#: src/components/status.jsx:1224
#: src/components/status.jsx:2104
#: src/components/status.jsx:2922
#: src/components/status.jsx:1235
#: src/components/status.jsx:2115
#: src/components/status.jsx:2933
msgid "Unlike"
msgstr ""
#: src/components/status.jsx:1225
#: src/components/status.jsx:2104
#: src/components/status.jsx:2105
#: src/components/status.jsx:2922
#: src/components/status.jsx:2923
#: src/components/status.jsx:1236
#: src/components/status.jsx:2115
#: src/components/status.jsx:2116
#: src/components/status.jsx:2933
#: src/components/status.jsx:2934
msgid "Like"
msgstr ""
#: src/components/status.jsx:1234
#: src/components/status.jsx:2934
#: src/components/status.jsx:1245
#: src/components/status.jsx:2945
msgid "Unbookmark"
msgstr ""
#: src/components/status.jsx:1269
#: src/components/status.jsx:1280
msgid "View Quotes"
msgstr "View Quotes"
#: src/components/status.jsx:1336
#: src/components/status.jsx:1347
msgid "Post text copied"
msgstr "Post text copied"
#: src/components/status.jsx:1339
#: src/components/status.jsx:1350
msgid "Unable to copy post text"
msgstr "Unable to copy post text"
#: src/components/status.jsx:1345
#: src/components/status.jsx:1356
msgid "Copy post text"
msgstr "Copy post text"
#. placeholder {0}: username || acct
#: src/components/status.jsx:1363
#: src/components/status.jsx:1374
msgid "View post by <0>@{0}</0>"
msgstr ""
#: src/components/status.jsx:1384
#: src/components/status.jsx:1395
msgid "Show Edit History"
msgstr ""
#: src/components/status.jsx:1387
#: src/components/status.jsx:1398
msgid "Edited: {editedDateText}"
msgstr ""
#: src/components/status.jsx:1470
#: src/components/status.jsx:1481
msgid "Conversation unmuted"
msgstr ""
#: src/components/status.jsx:1470
#: src/components/status.jsx:1481
msgid "Conversation muted"
msgstr ""
#: src/components/status.jsx:1476
#: src/components/status.jsx:1487
msgid "Unable to unmute conversation"
msgstr ""
#: src/components/status.jsx:1477
#: src/components/status.jsx:1488
msgid "Unable to mute conversation"
msgstr ""
#: src/components/status.jsx:1486
#: src/components/status.jsx:1497
msgid "Unmute conversation"
msgstr ""
#: src/components/status.jsx:1493
#: src/components/status.jsx:1504
msgid "Mute conversation"
msgstr ""
#: src/components/status.jsx:1509
#: src/components/status.jsx:1520
msgid "Post unpinned from profile"
msgstr ""
#: src/components/status.jsx:1510
#: src/components/status.jsx:1521
msgid "Post pinned to profile"
msgstr ""
#: src/components/status.jsx:1515
#: src/components/status.jsx:1526
msgid "Unable to unpin post"
msgstr ""
#: src/components/status.jsx:1515
#: src/components/status.jsx:1526
msgid "Unable to pin post"
msgstr ""
#: src/components/status.jsx:1524
#: src/components/status.jsx:1535
msgid "Unpin from profile"
msgstr ""
#: src/components/status.jsx:1531
#: src/components/status.jsx:1542
msgid "Pin to profile"
msgstr ""
#: src/components/status.jsx:1544
#: src/components/status.jsx:1555
#: src/pages/settings.jsx:338
msgid "Quote settings"
msgstr "Quote settings"
#: src/components/status.jsx:1577
#: src/components/status.jsx:1588
msgid "Delete this post?"
msgstr ""
#: src/components/status.jsx:1593
#: src/components/status.jsx:1604
msgid "Post deleted"
msgstr ""
#: src/components/status.jsx:1596
#: src/components/status.jsx:1607
msgid "Unable to delete post"
msgstr ""
#. placeholder {0}: username || acct
#: src/components/status.jsx:1621
#: src/components/status.jsx:1632
msgid "Remove my post from <0>@{0}</0>'s post?"
msgstr "Remove my post from <0>@{0}</0>'s post?"
#: src/components/status.jsx:1642
#: src/components/status.jsx:1653
msgid "Quote removed"
msgstr "Quote removed"
#: src/components/status.jsx:1646
#: src/components/status.jsx:1657
msgid "Unable to remove quote"
msgstr "Unable to remove quote"
#: src/components/status.jsx:1652
#: src/components/status.jsx:1663
msgid "Remove quote…"
msgstr "Remove quote…"
#: src/components/status.jsx:1666
#: src/components/status.jsx:1677
msgid "Report post…"
msgstr ""
#: src/components/status.jsx:2105
#: src/components/status.jsx:2141
#: src/components/status.jsx:2923
#: src/components/status.jsx:2116
#: src/components/status.jsx:2152
#: src/components/status.jsx:2934
msgid "Liked"
msgstr ""
#: src/components/status.jsx:2138
#: src/components/status.jsx:2909
#: src/components/status.jsx:2149
#: src/components/status.jsx:2920
msgid "Boosted"
msgstr ""
#: src/components/status.jsx:2148
#: src/components/status.jsx:2935
#: src/components/status.jsx:2159
#: src/components/status.jsx:2946
msgid "Bookmarked"
msgstr ""
#: src/components/status.jsx:2152
#: src/components/status.jsx:2163
msgid "Pinned"
msgstr ""
#: src/components/status.jsx:2209
#: src/components/status.jsx:2692
#: src/components/status.jsx:2220
#: src/components/status.jsx:2703
msgid "Deleted"
msgstr ""
#: src/components/status.jsx:2250
#: src/components/status.jsx:2261
msgid "{repliesCount, plural, one {# reply} other {# replies}}"
msgstr ""
#: src/components/status.jsx:2414
#: src/components/status.jsx:2476
#: src/components/status.jsx:2582
#: src/components/status.jsx:2425
#: src/components/status.jsx:2487
#: src/components/status.jsx:2593
msgid "Show less"
msgstr ""
#: src/components/status.jsx:2414
#: src/components/status.jsx:2476
#: src/components/status.jsx:2425
#: src/components/status.jsx:2487
msgid "Show content"
msgstr ""
#. placeholder {0}: filterInfo.titlesStr
#. placeholder {0}: filterInfo?.titlesStr
#: src/components/status.jsx:2578
#: src/components/status.jsx:2589
#: src/pages/catchup.jsx:1920
msgid "Filtered: {0}"
msgstr "Filtered: {0}"
#: src/components/status.jsx:2582
#: src/components/status.jsx:2593
msgid "Show media"
msgstr ""
#: src/components/status.jsx:2727
#: src/components/status.jsx:2738
msgid "Edited"
msgstr ""
#: src/components/status.jsx:2813
#: src/components/status.jsx:2825
#: src/components/status.jsx:2824
#: src/components/status.jsx:2836
msgid "Comments"
msgstr ""
#: src/components/status.jsx:3075
#: src/components/status.jsx:3086
msgid "Post hidden by your filters"
msgstr "Post hidden by your filters"
#: src/components/status.jsx:3076
#: src/components/status.jsx:3087
msgid "Post pending"
msgstr "Post pending"
#: src/components/status.jsx:3077
#: src/components/status.jsx:3078
#: src/components/status.jsx:3079
#: src/components/status.jsx:3088
#: src/components/status.jsx:3089
#: src/components/status.jsx:3090
msgid "Post unavailable"
msgstr "Post unavailable"
#: src/components/status.jsx:3080
#: src/components/status.jsx:3091
msgid "Post removed by author"
msgstr "Post removed by author"
#: src/components/status.jsx:3204
#: src/components/status.jsx:3215
msgid "Edit History"
msgstr ""
#: src/components/status.jsx:3208
#: src/components/status.jsx:3219
msgid "Failed to load history"
msgstr ""
#: src/components/status.jsx:3213
#: src/components/status.jsx:3224
#: src/pages/annual-report.jsx:45
msgid "Loading…"
msgstr ""
#. [Name] [Visibility icon] boosted
#: src/components/status.jsx:3345
#: src/components/status.jsx:3356
msgid "<0/> <1/> boosted"
msgstr "<0/> <1/> boosted"
@ -2847,28 +2847,28 @@ msgstr ""
msgid "Translated Bio"
msgstr ""
#: src/components/translation-block.jsx:196
#: src/components/translation-block.jsx:226
msgid "Auto-translated from {sourceLangText}"
msgstr ""
#: src/components/translation-block.jsx:234
#: src/components/translation-block.jsx:264
msgid "Translating…"
msgstr ""
#: src/components/translation-block.jsx:237
#: src/components/translation-block.jsx:267
msgid "Translate from {sourceLangText} (auto-detected)"
msgstr ""
#: src/components/translation-block.jsx:238
#: src/components/translation-block.jsx:268
msgid "Translate from {sourceLangText}"
msgstr ""
#. placeholder {0}: detectedLang ?? '…'
#: src/components/translation-block.jsx:266
#: src/components/translation-block.jsx:296
msgid "Auto ({0})"
msgstr ""
#: src/components/translation-block.jsx:279
#: src/components/translation-block.jsx:309
msgid "Failed to translate"
msgstr ""

Wyświetl plik

@ -1,13 +1,14 @@
import pThrottle from 'p-throttle';
import PQueue from 'p-queue';
import { snapshot } from 'valtio/vanilla';
import { api } from './api';
import getDomain from './get-domain';
import states, { saveStatus } from './states';
export const throttle = pThrottle({
limit: 1,
export const unfurlQueue = new PQueue({
concurrency: 1,
interval: 1000,
intervalCap: 1,
});
const STATUS_ID_REGEXES = [
@ -156,5 +157,6 @@ function _unfurlMastodonLink(instance, url) {
}
}
const unfurlMastodonLink = throttle(_unfurlMastodonLink);
const unfurlMastodonLink = (instance, url, signal) =>
unfurlQueue.add(() => _unfurlMastodonLink(instance, url), { signal });
export default unfurlMastodonLink;