mirror of
https://github.com/fluxerapp/fluxer
synced 2026-10-12 13:38:31 +09:00
Compare commits
10
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c17091768c | ||
|
|
e0640d68ff | ||
|
|
3292dc5f89 | ||
|
|
86e29b61e3 | ||
|
|
f8d3c70a91 | ||
|
|
74c6fad260 | ||
|
|
bcb30eea88 | ||
|
|
d59ddc2214 | ||
|
|
e87b593f46 | ||
|
|
5a2d81ebbb |
No files matched your search
Generated
+2
-1
@@ -11107,7 +11107,7 @@
|
||||
"category": {"type": "string"},
|
||||
"scope": {"type": "string"},
|
||||
"isToggle": {"type": "boolean"},
|
||||
"unit": {"type": "string", "enum": ["bytes", "count"]},
|
||||
"unit": {"type": "string", "enum": ["bytes", "count", "bps"]},
|
||||
"min": {"type": "number"},
|
||||
"max": {"type": "number"}
|
||||
},
|
||||
@@ -11154,6 +11154,7 @@
|
||||
"max_private_channels_per_user",
|
||||
"max_reactions_per_message",
|
||||
"max_relationships",
|
||||
"max_screen_share_bitrate",
|
||||
"max_users_per_message_reaction",
|
||||
"max_voice_message_duration",
|
||||
"max_webhooks_per_channel",
|
||||
|
||||
@@ -12,6 +12,11 @@ pub fn limit_key_hint(key: &str) -> Option<Hint<'static>> {
|
||||
"Community creation policy",
|
||||
)),
|
||||
}),
|
||||
"max_screen_share_bitrate" => Some(Hint {
|
||||
name: Some("Max Screen Share Bitrate"),
|
||||
body: "In bits per second, so 9000000 is 9 Mbps. Raising it also raises the automatic bitrate of every screen share quality. Accounts with Higher Video Quality can pick their own bitrate up to this value.",
|
||||
link: None,
|
||||
}),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
@@ -28,6 +28,7 @@ const CATEGORY_ORDER: &[&str] = &[
|
||||
"expressions",
|
||||
"files",
|
||||
"social",
|
||||
"media",
|
||||
];
|
||||
|
||||
pub fn limit_config_page(
|
||||
|
||||
@@ -8,7 +8,11 @@ import {HTTP_STATUS} from '@app/api/test/TestConstants';
|
||||
import {createBuilder} from '@app/api/test/TestRequestBuilder';
|
||||
import {AdminACLs} from '@fluxer/constants/src/AdminACLs';
|
||||
import {APIErrorCodes} from '@fluxer/constants/src/ApiErrorCodes';
|
||||
import {MAX_BIO_LENGTH} from '@fluxer/constants/src/LimitConstants';
|
||||
import {
|
||||
MAX_BIO_LENGTH,
|
||||
MAX_SCREEN_SHARE_BITRATE_CEILING,
|
||||
MIN_SCREEN_SHARE_BITRATE_CEILING,
|
||||
} from '@fluxer/constants/src/LimitConstants';
|
||||
import type {LimitConfigGetResponse} from '@fluxer/schema/src/domains/admin/AdminSchemas';
|
||||
import {afterAll, beforeAll, beforeEach, describe, expect, it} from 'vitest';
|
||||
import type {z} from 'zod';
|
||||
@@ -59,6 +63,30 @@ describe('limit config allowed ranges', () => {
|
||||
expect(saved.metadata.max_bio_length).toMatchObject({min: 0, max: MAX_BIO_LENGTH});
|
||||
});
|
||||
|
||||
it('keeps a screen share bitrate ceiling inside its allowed range', async () => {
|
||||
const admin = await createAdmin();
|
||||
const rule = (bitrate: number) => ({
|
||||
id: 'vip',
|
||||
filters: {traits: ['vip']},
|
||||
limits: {max_screen_share_bitrate: bitrate},
|
||||
});
|
||||
for (const bitrate of [MIN_SCREEN_SHARE_BITRATE_CEILING - 1, MAX_SCREEN_SHARE_BITRATE_CEILING + 1]) {
|
||||
await createBuilder(harness, admin.token)
|
||||
.put('/admin/limit-config')
|
||||
.body({limit_config: {traitDefinitions: ['vip'], rules: [rule(bitrate)]}})
|
||||
.expect(HTTP_STATUS.BAD_REQUEST, APIErrorCodes.INVALID_FORM_BODY)
|
||||
.execute();
|
||||
}
|
||||
const saved = await createBuilder<LimitConfigResponse>(harness, admin.token)
|
||||
.put('/admin/limit-config')
|
||||
.body({limit_config: {traitDefinitions: ['vip'], rules: [rule(25_000_000)]}})
|
||||
.execute();
|
||||
expect(saved.limit_config.rules.find((entry) => entry.id === 'vip')?.limits).toEqual({
|
||||
max_screen_share_bitrate: 25_000_000,
|
||||
});
|
||||
expect(saved.defaults.default?.max_screen_share_bitrate).toBe(9_000_000);
|
||||
});
|
||||
|
||||
it('reads a stored bio length above the profile maximum as the maximum', async () => {
|
||||
const admin = await createAdmin();
|
||||
await getInstanceConfigRepository().setLimitConfig({traitDefinitions: ['vip'], rules: [vipRule(1000)]});
|
||||
|
||||
@@ -9,7 +9,7 @@ export function getGiftTrialMetadataKey(giftCode: string): string {
|
||||
return `${GIFT_TRIAL_KEY_PREFIX}${giftCode}`;
|
||||
}
|
||||
|
||||
function isGiftTrialRunning(subscription: Stripe.Subscription, nowMs: number): boolean {
|
||||
export function isGiftTrialRunning(subscription: Stripe.Subscription, nowMs: number): boolean {
|
||||
return subscription.trial_end != null && subscription.trial_end * 1000 > nowMs;
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,11 @@ import {addGiftCodeDuration} from '@app/api/models/GiftCode';
|
||||
import type {User} from '@app/api/models/User';
|
||||
import type {StoreEntitlementService} from '@app/api/store_billing/StoreEntitlementService';
|
||||
import type {ProductInfo, RecurringBillingCycle} from '@app/api/stripe/ProductRegistry';
|
||||
import {buildGiftTrialMetadata, getGiftTrialPaidUntil} from '@app/api/stripe/StripeGiftTrialMetadata';
|
||||
import {
|
||||
buildGiftTrialMetadata,
|
||||
getGiftTrialPaidUntil,
|
||||
isGiftTrialRunning,
|
||||
} from '@app/api/stripe/StripeGiftTrialMetadata';
|
||||
import {
|
||||
getPrimarySubscriptionItem,
|
||||
getSubscriptionEntitlementPeriodEndUnix,
|
||||
@@ -1293,7 +1297,8 @@ export class StripeSubscriptionService {
|
||||
const currentTrialEnd = subscription.trial_end;
|
||||
const item = getPrimarySubscriptionItem(subscription);
|
||||
const currentPeriodEnd = getSubscriptionItemPeriodEndUnix(item);
|
||||
const baseUnix = currentTrialEnd ?? currentPeriodEnd;
|
||||
const nowMs = Date.now();
|
||||
const baseUnix = isGiftTrialRunning(subscription, nowMs) ? currentTrialEnd : currentPeriodEnd;
|
||||
Logger.debug(
|
||||
{
|
||||
userId: user.id,
|
||||
@@ -1331,7 +1336,7 @@ export class StripeSubscriptionService {
|
||||
{
|
||||
trial_end: newTrialEndUnix,
|
||||
proration_behavior: 'none',
|
||||
metadata: buildGiftTrialMetadata(subscription, idempotencyKey, baseUnix, newTrialEndUnix, Date.now()),
|
||||
metadata: buildGiftTrialMetadata(subscription, idempotencyKey, baseUnix, newTrialEndUnix, nowMs),
|
||||
},
|
||||
{idempotencyKey: stripeIdempotencyKey},
|
||||
);
|
||||
|
||||
@@ -749,5 +749,45 @@ describe('gift time around a Stripe subscription', () => {
|
||||
const afterWebhook = await findUser(account.userId);
|
||||
expect(afterWebhook.premiumGiftExtensionEndsAt?.getTime()).toBe(trialEnd.getTime());
|
||||
});
|
||||
|
||||
test('stacks from the paid period end when an earlier gift trial has ended', async () => {
|
||||
const subscriptionId = 'sub_shift_stale_trial';
|
||||
const periodEnd = Math.floor((Date.now() + ms('20 days')) / 1000);
|
||||
const staleTrialEnd = periodEnd - 60 * 24 * 60 * 60;
|
||||
useStripe({
|
||||
subscriptions: {
|
||||
[subscriptionId]: {
|
||||
current_period_start: periodEnd - 30 * 24 * 60 * 60,
|
||||
current_period_end: periodEnd,
|
||||
trial_end: staleTrialEnd,
|
||||
metadata: giftTrialMetadata('OLDGIFT', 30, staleTrialEnd - 30 * 24 * 60 * 60),
|
||||
},
|
||||
},
|
||||
});
|
||||
const {account} = await createUser({
|
||||
premium_type: UserPremiumTypes.SUBSCRIPTION,
|
||||
stripe_subscription_id: subscriptionId,
|
||||
stripe_customer_id: 'cus_test_1',
|
||||
premium_billing_cycle: 'monthly',
|
||||
premium_until: new Date(periodEnd * 1000),
|
||||
});
|
||||
const gifter = await createTestAccount(harness);
|
||||
await createBuilder(harness, gifter.token)
|
||||
.post('/test/gifts/SHIFTSTALEGIFT')
|
||||
.body({duration_type: 'days', duration_quantity: 30, created_by_user_id: gifter.userId})
|
||||
.execute();
|
||||
|
||||
await createBuilder(harness, account.token).post('/gifts/SHIFTSTALEGIFT/redeem').expect(204).execute();
|
||||
|
||||
const update = stripeHandlers.spies.updatedSubscriptions[0]?.params;
|
||||
expect(Number(update?.trial_end)).toBe(periodEnd + 30 * 24 * 60 * 60);
|
||||
expect(update?.metadata).toEqual({
|
||||
gtrial_OLDGIFT: '',
|
||||
gtrial_paid_until: String(periodEnd),
|
||||
gtrial_SHIFTSTALEGIFT: String(30 * 24 * 60 * 60),
|
||||
});
|
||||
const redeemed = await findUser(account.userId);
|
||||
expect(redeemed.premiumUntil?.getTime()).toBe((periodEnd + 30 * 24 * 60 * 60) * 1000);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -9,6 +9,13 @@ import {getDefaultLandingPath} from '@app/features/navigation/utils/DefaultLandi
|
||||
import {createRootRoute, createRoute} from '@app/features/platform/components/router/RouterBuilder';
|
||||
import {Redirect} from '@app/features/platform/components/router/RouterTypes';
|
||||
|
||||
const enterDefaultLanding = afterSessionInitialization(() => {
|
||||
if (readAuthenticatedRuntimeContext() === null) {
|
||||
return new Redirect(Routes.LOGIN);
|
||||
}
|
||||
return new Redirect(getDefaultLandingPath());
|
||||
});
|
||||
|
||||
export const rootRoute = createRootRoute({
|
||||
layout: ({children}) => (
|
||||
<RootComponent data-flx="app.router.root-routes.layout.root-component">{children}</RootComponent>
|
||||
@@ -23,16 +30,11 @@ export const homeRoute = createRoute({
|
||||
getParentRoute: () => rootRoute,
|
||||
id: 'home',
|
||||
path: '/',
|
||||
onEnter: afterSessionInitialization(() => {
|
||||
if (readAuthenticatedRuntimeContext() === null) {
|
||||
return new Redirect(Routes.LOGIN);
|
||||
}
|
||||
return new Redirect(getDefaultLandingPath());
|
||||
}),
|
||||
onEnter: enterDefaultLanding,
|
||||
});
|
||||
export const appRoute = createRoute({
|
||||
getParentRoute: () => rootRoute,
|
||||
id: 'app',
|
||||
path: Routes.APP,
|
||||
onEnter: () => new Redirect(getDefaultLandingPath()),
|
||||
onEnter: enterDefaultLanding,
|
||||
});
|
||||
+20
-6
@@ -1005,6 +1005,11 @@ msgstr "يفضّل {authorNickname} أن تتم الإشارة إليه بـ @
|
||||
msgid "{backgroundCount} / {maxBackgroundImages} {backgroundCount, plural, one {custom background} other {custom backgrounds}}"
|
||||
msgstr "{backgroundCount} / {maxBackgroundImages} {backgroundCount, plural, zero {خلفية مخصصة} one {خلفية مخصصة} two {خلفيتان مخصصتان} few {خلفيات مخصصة} many {خلفية مخصصة} other {خلفية مخصصة}}"
|
||||
|
||||
#. Option label of the screen share bitrate select in the video tab. bitrate is a formatted number of megabits per second. Mbps is a technical unit token.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
msgid "{bitrate} Mbps"
|
||||
msgstr "{bitrate} ميجابت في الثانية"
|
||||
|
||||
#. Accessible label for a category row in the Discovery search sidebar. {categoryLabel} is the category name and {count} is how many communities match the current search in it. Both are inserted by code.
|
||||
#: src/features/discovery/discovery/DiscoverySearchFilters.tsx
|
||||
msgid "{categoryLabel}, {count, plural, one {# community} other {# communities}}"
|
||||
@@ -5411,6 +5416,7 @@ msgid "Autocomplete suggestion: {label}, {selectedOptionPosition} of {resultCoun
|
||||
msgstr "اقتراح الإكمال التلقائي: {label}، {selectedOptionPosition} من {resultCount}"
|
||||
|
||||
#. Channel overview settings tab label, control, or validation message (name, topic, slowmode, voice region, mature content gate).
|
||||
#. Default option of the screen share bitrate select in the video tab.
|
||||
#. Option label for a WebRTC content hint select.
|
||||
#. Option label for an SVC mode select.
|
||||
#. Option label for an encoder path select.
|
||||
@@ -5420,6 +5426,7 @@ msgstr "اقتراح الإكمال التلقائي: {label}، {selectedOptionP
|
||||
#: src/features/app/components/setup/SetupWizardSteps.tsx
|
||||
#: src/features/channel/components/modals/channel_tabs/channel_overview_tab/RtcRegionSelect.tsx
|
||||
#: src/features/user/components/modals/tabs/advanced_settings_tab/AdvancedVideoControls.tsx
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
#: src/features/user/components/settings_utils/section_registry/NotificationsSections.ts
|
||||
#: src/features/voice/components/VoiceSettingsMenus.tsx
|
||||
msgid "Automatic"
|
||||
@@ -5983,7 +5990,9 @@ msgid "Biometrics"
|
||||
msgstr "المقاييس الحيوية"
|
||||
|
||||
#. Settings search synonym. Used to match this term when the user types it in the settings search bar.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
#. Short label in the video tab for the screen share video bitrate select. Keep it concise.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
#: src/features/user/components/settings_utils/section_registry/VoiceVideoSections.ts
|
||||
msgid "Bitrate"
|
||||
msgstr "معدل البت"
|
||||
|
||||
@@ -14552,16 +14561,16 @@ msgstr "مفعّل"
|
||||
msgid "Encoder path"
|
||||
msgstr "مسار المُرمِّز"
|
||||
|
||||
#. Settings search entry description. One-line summary of what the settings search entry controls.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
msgid "Encoder path, SVC mode, and content hint"
|
||||
msgstr "مسار المُرمّز، وضع SVC، وتلميح المحتوى"
|
||||
|
||||
#. Description for the encoder path select.
|
||||
#: src/features/user/components/modals/tabs/advanced_settings_tab/AdvancedVideoControlsState.ts
|
||||
msgid "Encoder preference for new screen shares."
|
||||
msgstr "تفضيل المُرمِّز لعمليات مشاركة الشاشة الجديدة."
|
||||
|
||||
#. Settings search entry description. One-line summary of what the settings search entry controls.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
msgid "Encoder, SVC, and bitrate presets"
|
||||
msgstr "المُرمّز، SVC، وإعدادات البت المسبقة"
|
||||
|
||||
#. Label for the choice of how the SMTP connection is encrypted.
|
||||
#: src/features/app/components/setup/SetupWizardSteps.tsx
|
||||
msgid "Encryption"
|
||||
@@ -40429,6 +40438,11 @@ msgstr "مع {PREMIUM_PRODUCT_NAME}، يمكنك استخدام صور رمزي
|
||||
msgid "With {premiumProductName}, your per-file upload limit increases to {fileSizeLimit}. You also get animated avatars, longer messages, and many other {premiumProductName} perks."
|
||||
msgstr "باستخدام {premiumProductName}، يزداد الحد الأقصى لحجم الملف الواحد إلى {fileSizeLimit}. كما تحصل على صور رمزية متحركة ورسائل أطول والعديد من مزايا {premiumProductName} الأخرى."
|
||||
|
||||
#. Description under the screen share bitrate select in the video tab. Automatic is the label of the default option.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
msgid "With Automatic, the bitrate follows your resolution and frame rate. Higher values keep fast motion sharper and use more upload bandwidth."
|
||||
msgstr "مع تلقائي، يتبع معدل البت دقة الشاشة ومعدل الإطارات لديك. القيم الأعلى تحافظ على حدة الحركة السريعة وتستخدم المزيد من نطاق التحميل."
|
||||
|
||||
#. Label in the messages tab.
|
||||
#: src/features/user/components/modals/tabs/appearance_tab/MessagesTab.tsx
|
||||
msgid "With different display modes available"
|
||||
|
||||
@@ -55,6 +55,7 @@
|
||||
"WebAuthn",
|
||||
"Win",
|
||||
"YubiKey",
|
||||
"{bitrate} Mbps",
|
||||
"{context} · {accountName}",
|
||||
"{desktopChannel} Desktop {desktopVersion}",
|
||||
"{fps} FPS",
|
||||
@@ -128,6 +129,7 @@
|
||||
"YubiKey",
|
||||
"emoji {emojiName}",
|
||||
"online",
|
||||
"{bitrate} Mbps",
|
||||
"{context} · {accountName}",
|
||||
"{desktopChannel} Desktop {desktopVersion}",
|
||||
"{formattedPresenceCount} online",
|
||||
@@ -312,6 +314,7 @@
|
||||
"online",
|
||||
"spoiler",
|
||||
"{actor} stopped following an announcement channel in {channel}",
|
||||
"{bitrate} Mbps",
|
||||
"{context} · {accountName}",
|
||||
"{desktopChannel} Desktop {desktopVersion}",
|
||||
"{formattedPresenceCount} online",
|
||||
@@ -618,6 +621,7 @@
|
||||
"Webhook {currentName}",
|
||||
"Win",
|
||||
"YubiKey",
|
||||
"{bitrate} Mbps",
|
||||
"{context} · {accountName}",
|
||||
"{desktopChannel} Desktop {desktopVersion}",
|
||||
"{fps} FPS",
|
||||
@@ -936,6 +940,7 @@
|
||||
"Enable emoji and sticker cloning shortcuts",
|
||||
"Enable previews",
|
||||
"Enable the integrations whose credentials you have configured. Only available services are shown.",
|
||||
"Encoder path, SVC mode, and content hint",
|
||||
"Encryption",
|
||||
"Ensures file messages appear in the order you sent them",
|
||||
"Enter a community name between 1 and 100 characters.",
|
||||
@@ -1659,6 +1664,7 @@
|
||||
"Who can join",
|
||||
"Who can message you",
|
||||
"Who can message you?",
|
||||
"With Automatic, the bitrate follows your resolution and frame rate. Higher values keep fast motion sharper and use more upload bandwidth.",
|
||||
"With {PREMIUM_PRODUCT_NAME}, you can use animated avatars ({ANIMATED_AVATAR_FORMATS}) and profile banners, and unlock many other {PREMIUM_PRODUCT_NAME} perks.",
|
||||
"Without this permission, push-to-talk is required in this channel.",
|
||||
"Wordmark",
|
||||
@@ -1765,6 +1771,7 @@
|
||||
"{appName} will close, install the update and open again.",
|
||||
"{appName} will reload to finish updating.",
|
||||
"{appName} {version} is available.",
|
||||
"{bitrate} Mbps",
|
||||
"{channelHeading}, {mentionCount, plural, one {# mention} other {# mentions}}",
|
||||
"{context} · {accountName}",
|
||||
"{count, plural, =0 {∞ No limit} one {# participant} other {# participants}}",
|
||||
@@ -1894,6 +1901,7 @@
|
||||
"emoji {emojiName}",
|
||||
"spoiler",
|
||||
"sticker",
|
||||
"{bitrate} Mbps",
|
||||
"{context} · {accountName}",
|
||||
"{count, plural, one {# video} other {# videos}}",
|
||||
"{fps} FPS",
|
||||
@@ -2007,6 +2015,7 @@
|
||||
"Zoom",
|
||||
"emoji {emojiName}",
|
||||
"spoiler",
|
||||
"{bitrate} Mbps",
|
||||
"{context} · {accountName}",
|
||||
"{fps} FPS",
|
||||
"{frameRate} FPS",
|
||||
@@ -2278,6 +2287,7 @@
|
||||
"message",
|
||||
"spoiler",
|
||||
"sticker",
|
||||
"{bitrate} Mbps",
|
||||
"{channelHeading}, {mentionCount, plural, one {# mention} other {# mentions}}",
|
||||
"{context} · {accountName}",
|
||||
"{count, plural, one {# image} other {# images}}",
|
||||
@@ -2469,6 +2479,7 @@
|
||||
"Win",
|
||||
"YubiKey",
|
||||
"emoji {emojiName}",
|
||||
"{bitrate} Mbps",
|
||||
"{context} · {accountName}",
|
||||
"{desktopChannel} Desktop {desktopVersion}",
|
||||
"{fps} FPS",
|
||||
@@ -2576,6 +2587,7 @@
|
||||
"link",
|
||||
"online",
|
||||
"spoiler",
|
||||
"{bitrate} Mbps",
|
||||
"{context} · {accountName}",
|
||||
"{formattedPresenceCount} online",
|
||||
"{fps} FPS",
|
||||
@@ -2745,6 +2757,7 @@
|
||||
"emoji {emojiName}",
|
||||
"online",
|
||||
"spoiler",
|
||||
"{bitrate} Mbps",
|
||||
"{context} · {accountName}",
|
||||
"{desktopChannel} Desktop {desktopVersion}",
|
||||
"{formattedPresenceCount} online",
|
||||
@@ -2916,6 +2929,7 @@
|
||||
"online",
|
||||
"spoiler",
|
||||
"sticker",
|
||||
"{bitrate} Mbps",
|
||||
"{context} · {accountName}",
|
||||
"{desktopChannel} Desktop {desktopVersion}",
|
||||
"{formattedPresenceCount} online",
|
||||
@@ -3013,6 +3027,7 @@
|
||||
"WebAuthn",
|
||||
"Win",
|
||||
"YubiKey",
|
||||
"{bitrate} Mbps",
|
||||
"{context} · {accountName}",
|
||||
"{fps} FPS",
|
||||
"{frameRate} FPS",
|
||||
@@ -3099,6 +3114,7 @@
|
||||
"WebAuthn",
|
||||
"Win",
|
||||
"YubiKey",
|
||||
"{bitrate} Mbps",
|
||||
"{context} · {accountName}",
|
||||
"{fps} FPS",
|
||||
"{frameRate} FPS",
|
||||
@@ -3270,6 +3286,7 @@
|
||||
"spoiler",
|
||||
"sticker",
|
||||
"{appName} is up to date.",
|
||||
"{bitrate} Mbps",
|
||||
"{context} · {accountName}",
|
||||
"{count, plural, one {# passkey} other {# passkeys}}",
|
||||
"{formattedPresenceCount} online",
|
||||
@@ -3424,6 +3441,7 @@
|
||||
"Zoom",
|
||||
"emoji {emojiName}",
|
||||
"spoiler",
|
||||
"{bitrate} Mbps",
|
||||
"{context} · {accountName}",
|
||||
"{fps} FPS",
|
||||
"{kilobits} kbps",
|
||||
@@ -3545,6 +3563,7 @@
|
||||
"link",
|
||||
"online",
|
||||
"spoiler",
|
||||
"{bitrate} Mbps",
|
||||
"{context} · {accountName}",
|
||||
"{formattedPresenceCount} online",
|
||||
"{onlineCount} online",
|
||||
@@ -3673,6 +3692,7 @@
|
||||
"link",
|
||||
"online",
|
||||
"spoiler",
|
||||
"{bitrate} Mbps",
|
||||
"{context} · {accountName}",
|
||||
"{desktopChannel} Desktop {desktopVersion}",
|
||||
"{formattedPresenceCount} online",
|
||||
@@ -3829,6 +3849,7 @@
|
||||
"slash {commandName}",
|
||||
"spoiler",
|
||||
"sticker",
|
||||
"{bitrate} Mbps",
|
||||
"{context} · {accountName}",
|
||||
"{desktopChannel} Desktop {desktopVersion}",
|
||||
"{formattedPresenceCount} online",
|
||||
@@ -4180,6 +4201,7 @@
|
||||
"Win",
|
||||
"YubiKey",
|
||||
"spoiler",
|
||||
"{bitrate} Mbps",
|
||||
"{context} · {accountName}",
|
||||
"{fps} FPS",
|
||||
"{frameRate} FPS",
|
||||
@@ -4333,6 +4355,7 @@
|
||||
"Win",
|
||||
"Wordmark",
|
||||
"YubiKey",
|
||||
"{bitrate} Mbps",
|
||||
"{context} · {accountName}",
|
||||
"{fps} FPS",
|
||||
"{frameRate} FPS",
|
||||
@@ -4461,6 +4484,7 @@
|
||||
"Webhook {currentName}",
|
||||
"Win",
|
||||
"YubiKey",
|
||||
"{bitrate} Mbps",
|
||||
"{context} · {accountName}",
|
||||
"{fps} FPS",
|
||||
"{frameRate} FPS",
|
||||
|
||||
+20
-6
@@ -1005,6 +1005,11 @@ msgstr "{authorNickname} предпочита отговори с @спомен
|
||||
msgid "{backgroundCount} / {maxBackgroundImages} {backgroundCount, plural, one {custom background} other {custom backgrounds}}"
|
||||
msgstr "{backgroundCount} / {maxBackgroundImages} {backgroundCount, plural, one {персонализиран фон} other {персонализирани фона}}"
|
||||
|
||||
#. Option label of the screen share bitrate select in the video tab. bitrate is a formatted number of megabits per second. Mbps is a technical unit token.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
msgid "{bitrate} Mbps"
|
||||
msgstr "{bitrate} Mbps"
|
||||
|
||||
#. Accessible label for a category row in the Discovery search sidebar. {categoryLabel} is the category name and {count} is how many communities match the current search in it. Both are inserted by code.
|
||||
#: src/features/discovery/discovery/DiscoverySearchFilters.tsx
|
||||
msgid "{categoryLabel}, {count, plural, one {# community} other {# communities}}"
|
||||
@@ -5411,6 +5416,7 @@ msgid "Autocomplete suggestion: {label}, {selectedOptionPosition} of {resultCoun
|
||||
msgstr "Предложение за автоматично довършване: {label}, {selectedOptionPosition} от {resultCount}"
|
||||
|
||||
#. Channel overview settings tab label, control, or validation message (name, topic, slowmode, voice region, mature content gate).
|
||||
#. Default option of the screen share bitrate select in the video tab.
|
||||
#. Option label for a WebRTC content hint select.
|
||||
#. Option label for an SVC mode select.
|
||||
#. Option label for an encoder path select.
|
||||
@@ -5420,6 +5426,7 @@ msgstr "Предложение за автоматично довършване:
|
||||
#: src/features/app/components/setup/SetupWizardSteps.tsx
|
||||
#: src/features/channel/components/modals/channel_tabs/channel_overview_tab/RtcRegionSelect.tsx
|
||||
#: src/features/user/components/modals/tabs/advanced_settings_tab/AdvancedVideoControls.tsx
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
#: src/features/user/components/settings_utils/section_registry/NotificationsSections.ts
|
||||
#: src/features/voice/components/VoiceSettingsMenus.tsx
|
||||
msgid "Automatic"
|
||||
@@ -5983,7 +5990,9 @@ msgid "Biometrics"
|
||||
msgstr "Биометрични данни"
|
||||
|
||||
#. Settings search synonym. Used to match this term when the user types it in the settings search bar.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
#. Short label in the video tab for the screen share video bitrate select. Keep it concise.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
#: src/features/user/components/settings_utils/section_registry/VoiceVideoSections.ts
|
||||
msgid "Bitrate"
|
||||
msgstr "Битрейт"
|
||||
|
||||
@@ -14552,16 +14561,16 @@ msgstr "Включено"
|
||||
msgid "Encoder path"
|
||||
msgstr "Път на енкодера"
|
||||
|
||||
#. Settings search entry description. One-line summary of what the settings search entry controls.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
msgid "Encoder path, SVC mode, and content hint"
|
||||
msgstr "Път на кодера, SVC режим и подсказка за съдържание"
|
||||
|
||||
#. Description for the encoder path select.
|
||||
#: src/features/user/components/modals/tabs/advanced_settings_tab/AdvancedVideoControlsState.ts
|
||||
msgid "Encoder preference for new screen shares."
|
||||
msgstr "Предпочитан енкодер за нови споделяния на екрана."
|
||||
|
||||
#. Settings search entry description. One-line summary of what the settings search entry controls.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
msgid "Encoder, SVC, and bitrate presets"
|
||||
msgstr "Кодер, SVC и битрейт предварителни настройки"
|
||||
|
||||
#. Label for the choice of how the SMTP connection is encrypted.
|
||||
#: src/features/app/components/setup/SetupWizardSteps.tsx
|
||||
msgid "Encryption"
|
||||
@@ -40429,6 +40438,11 @@ msgstr "С {PREMIUM_PRODUCT_NAME} можеш да използваш аними
|
||||
msgid "With {premiumProductName}, your per-file upload limit increases to {fileSizeLimit}. You also get animated avatars, longer messages, and many other {premiumProductName} perks."
|
||||
msgstr "С {premiumProductName} лимитът ти за качване на файл се увеличава до {fileSizeLimit}. Получаваш и анимирани аватари, по-дълги съобщения и много други предимства на {premiumProductName}."
|
||||
|
||||
#. Description under the screen share bitrate select in the video tab. Automatic is the label of the default option.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
msgid "With Automatic, the bitrate follows your resolution and frame rate. Higher values keep fast motion sharper and use more upload bandwidth."
|
||||
msgstr "С „Автоматично“ битрейтът следва вашата резолюция и честота на кадрите. По-високите стойности поддържат по-рязко движението при бързи сцени и използват повече честотна лента за качване."
|
||||
|
||||
#. Label in the messages tab.
|
||||
#: src/features/user/components/modals/tabs/appearance_tab/MessagesTab.tsx
|
||||
msgid "With different display modes available"
|
||||
|
||||
+20
-6
@@ -1005,6 +1005,11 @@ msgstr "{authorNickname} preferuje odpovědi s @zmínkou. Přesto odeslat bez zm
|
||||
msgid "{backgroundCount} / {maxBackgroundImages} {backgroundCount, plural, one {custom background} other {custom backgrounds}}"
|
||||
msgstr "{backgroundCount} / {maxBackgroundImages} {backgroundCount, plural, one {vlastní pozadí} few {vlastní pozadí} many {vlastního pozadí} other {vlastních pozadí}}"
|
||||
|
||||
#. Option label of the screen share bitrate select in the video tab. bitrate is a formatted number of megabits per second. Mbps is a technical unit token.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
msgid "{bitrate} Mbps"
|
||||
msgstr "{bitrate} Mbps"
|
||||
|
||||
#. Accessible label for a category row in the Discovery search sidebar. {categoryLabel} is the category name and {count} is how many communities match the current search in it. Both are inserted by code.
|
||||
#: src/features/discovery/discovery/DiscoverySearchFilters.tsx
|
||||
msgid "{categoryLabel}, {count, plural, one {# community} other {# communities}}"
|
||||
@@ -5411,6 +5416,7 @@ msgid "Autocomplete suggestion: {label}, {selectedOptionPosition} of {resultCoun
|
||||
msgstr "Návrh automatického doplňování: {label}, {selectedOptionPosition} z {resultCount}"
|
||||
|
||||
#. Channel overview settings tab label, control, or validation message (name, topic, slowmode, voice region, mature content gate).
|
||||
#. Default option of the screen share bitrate select in the video tab.
|
||||
#. Option label for a WebRTC content hint select.
|
||||
#. Option label for an SVC mode select.
|
||||
#. Option label for an encoder path select.
|
||||
@@ -5420,6 +5426,7 @@ msgstr "Návrh automatického doplňování: {label}, {selectedOptionPosition} z
|
||||
#: src/features/app/components/setup/SetupWizardSteps.tsx
|
||||
#: src/features/channel/components/modals/channel_tabs/channel_overview_tab/RtcRegionSelect.tsx
|
||||
#: src/features/user/components/modals/tabs/advanced_settings_tab/AdvancedVideoControls.tsx
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
#: src/features/user/components/settings_utils/section_registry/NotificationsSections.ts
|
||||
#: src/features/voice/components/VoiceSettingsMenus.tsx
|
||||
msgid "Automatic"
|
||||
@@ -5983,7 +5990,9 @@ msgid "Biometrics"
|
||||
msgstr "Biometrické ověřování"
|
||||
|
||||
#. Settings search synonym. Used to match this term when the user types it in the settings search bar.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
#. Short label in the video tab for the screen share video bitrate select. Keep it concise.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
#: src/features/user/components/settings_utils/section_registry/VoiceVideoSections.ts
|
||||
msgid "Bitrate"
|
||||
msgstr "Přenosová rychlost"
|
||||
|
||||
@@ -14552,16 +14561,16 @@ msgstr "Zapnuto"
|
||||
msgid "Encoder path"
|
||||
msgstr "Způsob kódování"
|
||||
|
||||
#. Settings search entry description. One-line summary of what the settings search entry controls.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
msgid "Encoder path, SVC mode, and content hint"
|
||||
msgstr "Cesta kodéru, režim SVC a nápověda k obsahu"
|
||||
|
||||
#. Description for the encoder path select.
|
||||
#: src/features/user/components/modals/tabs/advanced_settings_tab/AdvancedVideoControlsState.ts
|
||||
msgid "Encoder preference for new screen shares."
|
||||
msgstr "Preferovaný enkodér pro nová sdílení obrazovky."
|
||||
|
||||
#. Settings search entry description. One-line summary of what the settings search entry controls.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
msgid "Encoder, SVC, and bitrate presets"
|
||||
msgstr "Kodér, SVC a předvolby přenosové rychlosti"
|
||||
|
||||
#. Label for the choice of how the SMTP connection is encrypted.
|
||||
#: src/features/app/components/setup/SetupWizardSteps.tsx
|
||||
msgid "Encryption"
|
||||
@@ -40429,6 +40438,11 @@ msgstr "S {PREMIUM_PRODUCT_NAME} můžete používat animované avatary ({ANIMAT
|
||||
msgid "With {premiumProductName}, your per-file upload limit increases to {fileSizeLimit}. You also get animated avatars, longer messages, and many other {premiumProductName} perks."
|
||||
msgstr "S {premiumProductName} se limit velikosti jednoho nahrávaného souboru zvýší na {fileSizeLimit}. Získáte také animované avatary, delší zprávy a mnoho dalších výhod {premiumProductName}."
|
||||
|
||||
#. Description under the screen share bitrate select in the video tab. Automatic is the label of the default option.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
msgid "With Automatic, the bitrate follows your resolution and frame rate. Higher values keep fast motion sharper and use more upload bandwidth."
|
||||
msgstr "S možností Automaticky se přenosová rychlost přizpůsobí vašemu rozlišení a snímkové frekvenci. Vyšší hodnoty udržují ostrý pohyb a využívají více šířky pásma pro nahrávání."
|
||||
|
||||
#. Label in the messages tab.
|
||||
#: src/features/user/components/modals/tabs/appearance_tab/MessagesTab.tsx
|
||||
msgid "With different display modes available"
|
||||
|
||||
+20
-6
@@ -1005,6 +1005,11 @@ msgstr "{authorNickname} foretrækker at blive @omtalt i svar. Send uden omtalen
|
||||
msgid "{backgroundCount} / {maxBackgroundImages} {backgroundCount, plural, one {custom background} other {custom backgrounds}}"
|
||||
msgstr "{backgroundCount} / {maxBackgroundImages} {backgroundCount, plural, one {brugerdefineret baggrund} other {brugerdefinerede baggrunde}}"
|
||||
|
||||
#. Option label of the screen share bitrate select in the video tab. bitrate is a formatted number of megabits per second. Mbps is a technical unit token.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
msgid "{bitrate} Mbps"
|
||||
msgstr "{bitrate} Mbps"
|
||||
|
||||
#. Accessible label for a category row in the Discovery search sidebar. {categoryLabel} is the category name and {count} is how many communities match the current search in it. Both are inserted by code.
|
||||
#: src/features/discovery/discovery/DiscoverySearchFilters.tsx
|
||||
msgid "{categoryLabel}, {count, plural, one {# community} other {# communities}}"
|
||||
@@ -5411,6 +5416,7 @@ msgid "Autocomplete suggestion: {label}, {selectedOptionPosition} of {resultCoun
|
||||
msgstr "Forslag til autoudfyldelse: {label}, {selectedOptionPosition} af {resultCount}"
|
||||
|
||||
#. Channel overview settings tab label, control, or validation message (name, topic, slowmode, voice region, mature content gate).
|
||||
#. Default option of the screen share bitrate select in the video tab.
|
||||
#. Option label for a WebRTC content hint select.
|
||||
#. Option label for an SVC mode select.
|
||||
#. Option label for an encoder path select.
|
||||
@@ -5420,6 +5426,7 @@ msgstr "Forslag til autoudfyldelse: {label}, {selectedOptionPosition} af {result
|
||||
#: src/features/app/components/setup/SetupWizardSteps.tsx
|
||||
#: src/features/channel/components/modals/channel_tabs/channel_overview_tab/RtcRegionSelect.tsx
|
||||
#: src/features/user/components/modals/tabs/advanced_settings_tab/AdvancedVideoControls.tsx
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
#: src/features/user/components/settings_utils/section_registry/NotificationsSections.ts
|
||||
#: src/features/voice/components/VoiceSettingsMenus.tsx
|
||||
msgid "Automatic"
|
||||
@@ -5983,7 +5990,9 @@ msgid "Biometrics"
|
||||
msgstr "Biometri"
|
||||
|
||||
#. Settings search synonym. Used to match this term when the user types it in the settings search bar.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
#. Short label in the video tab for the screen share video bitrate select. Keep it concise.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
#: src/features/user/components/settings_utils/section_registry/VoiceVideoSections.ts
|
||||
msgid "Bitrate"
|
||||
msgstr "Bitrate"
|
||||
|
||||
@@ -14552,16 +14561,16 @@ msgstr "Aktiveret"
|
||||
msgid "Encoder path"
|
||||
msgstr "Encodersti"
|
||||
|
||||
#. Settings search entry description. One-line summary of what the settings search entry controls.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
msgid "Encoder path, SVC mode, and content hint"
|
||||
msgstr "Encoder-sti, SVC-tilstand og indholdsindikator"
|
||||
|
||||
#. Description for the encoder path select.
|
||||
#: src/features/user/components/modals/tabs/advanced_settings_tab/AdvancedVideoControlsState.ts
|
||||
msgid "Encoder preference for new screen shares."
|
||||
msgstr "Encoderpræference for nye skærmdelinger."
|
||||
|
||||
#. Settings search entry description. One-line summary of what the settings search entry controls.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
msgid "Encoder, SVC, and bitrate presets"
|
||||
msgstr "Encoder, SVC og bitrate-forudindstillinger"
|
||||
|
||||
#. Label for the choice of how the SMTP connection is encrypted.
|
||||
#: src/features/app/components/setup/SetupWizardSteps.tsx
|
||||
msgid "Encryption"
|
||||
@@ -40429,6 +40438,11 @@ msgstr "Med {PREMIUM_PRODUCT_NAME} kan du bruge animerede avatarer ({ANIMATED_AV
|
||||
msgid "With {premiumProductName}, your per-file upload limit increases to {fileSizeLimit}. You also get animated avatars, longer messages, and many other {premiumProductName} perks."
|
||||
msgstr "Med {premiumProductName} stiger uploadgrænsen pr. fil til {fileSizeLimit}. Du får også animerede avatarer, længere beskeder og mange andre {premiumProductName}-fordele."
|
||||
|
||||
#. Description under the screen share bitrate select in the video tab. Automatic is the label of the default option.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
msgid "With Automatic, the bitrate follows your resolution and frame rate. Higher values keep fast motion sharper and use more upload bandwidth."
|
||||
msgstr "Med Automatisk følger bitraten din opløsning og billedhastighed. Højere værdier holder hurtige bevægelser skarpere og bruger mere upload-båndbredde."
|
||||
|
||||
#. Label in the messages tab.
|
||||
#: src/features/user/components/modals/tabs/appearance_tab/MessagesTab.tsx
|
||||
msgid "With different display modes available"
|
||||
|
||||
+20
-6
@@ -1005,6 +1005,11 @@ msgstr "{authorNickname} möchte bei Antworten eine @-Erwähnung erhalten. Trotz
|
||||
msgid "{backgroundCount} / {maxBackgroundImages} {backgroundCount, plural, one {custom background} other {custom backgrounds}}"
|
||||
msgstr "{backgroundCount} / {maxBackgroundImages} {backgroundCount, plural, one {eigener Hintergrund} other {eigene Hintergründe}}"
|
||||
|
||||
#. Option label of the screen share bitrate select in the video tab. bitrate is a formatted number of megabits per second. Mbps is a technical unit token.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
msgid "{bitrate} Mbps"
|
||||
msgstr "{bitrate} MBit/s"
|
||||
|
||||
#. Accessible label for a category row in the Discovery search sidebar. {categoryLabel} is the category name and {count} is how many communities match the current search in it. Both are inserted by code.
|
||||
#: src/features/discovery/discovery/DiscoverySearchFilters.tsx
|
||||
msgid "{categoryLabel}, {count, plural, one {# community} other {# communities}}"
|
||||
@@ -5411,6 +5416,7 @@ msgid "Autocomplete suggestion: {label}, {selectedOptionPosition} of {resultCoun
|
||||
msgstr "Vervollständigungsvorschlag: {label}, {selectedOptionPosition} von {resultCount}"
|
||||
|
||||
#. Channel overview settings tab label, control, or validation message (name, topic, slowmode, voice region, mature content gate).
|
||||
#. Default option of the screen share bitrate select in the video tab.
|
||||
#. Option label for a WebRTC content hint select.
|
||||
#. Option label for an SVC mode select.
|
||||
#. Option label for an encoder path select.
|
||||
@@ -5420,6 +5426,7 @@ msgstr "Vervollständigungsvorschlag: {label}, {selectedOptionPosition} von {res
|
||||
#: src/features/app/components/setup/SetupWizardSteps.tsx
|
||||
#: src/features/channel/components/modals/channel_tabs/channel_overview_tab/RtcRegionSelect.tsx
|
||||
#: src/features/user/components/modals/tabs/advanced_settings_tab/AdvancedVideoControls.tsx
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
#: src/features/user/components/settings_utils/section_registry/NotificationsSections.ts
|
||||
#: src/features/voice/components/VoiceSettingsMenus.tsx
|
||||
msgid "Automatic"
|
||||
@@ -5983,7 +5990,9 @@ msgid "Biometrics"
|
||||
msgstr "Biometrie"
|
||||
|
||||
#. Settings search synonym. Used to match this term when the user types it in the settings search bar.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
#. Short label in the video tab for the screen share video bitrate select. Keep it concise.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
#: src/features/user/components/settings_utils/section_registry/VoiceVideoSections.ts
|
||||
msgid "Bitrate"
|
||||
msgstr "Bitrate"
|
||||
|
||||
@@ -14552,16 +14561,16 @@ msgstr "Aktiviert"
|
||||
msgid "Encoder path"
|
||||
msgstr "Encoder-Pfad"
|
||||
|
||||
#. Settings search entry description. One-line summary of what the settings search entry controls.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
msgid "Encoder path, SVC mode, and content hint"
|
||||
msgstr "Encoderpfad, SVC-Modus und Inhalts-Hint"
|
||||
|
||||
#. Description for the encoder path select.
|
||||
#: src/features/user/components/modals/tabs/advanced_settings_tab/AdvancedVideoControlsState.ts
|
||||
msgid "Encoder preference for new screen shares."
|
||||
msgstr "Encoder-Einstellung für neue Bildschirmfreigaben."
|
||||
|
||||
#. Settings search entry description. One-line summary of what the settings search entry controls.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
msgid "Encoder, SVC, and bitrate presets"
|
||||
msgstr "Encoder, SVC und Bitraten-Voreinstellungen"
|
||||
|
||||
#. Label for the choice of how the SMTP connection is encrypted.
|
||||
#: src/features/app/components/setup/SetupWizardSteps.tsx
|
||||
msgid "Encryption"
|
||||
@@ -40429,6 +40438,11 @@ msgstr "Mit {PREMIUM_PRODUCT_NAME} kannst du animierte Avatare ({ANIMATED_AVATAR
|
||||
msgid "With {premiumProductName}, your per-file upload limit increases to {fileSizeLimit}. You also get animated avatars, longer messages, and many other {premiumProductName} perks."
|
||||
msgstr "Mit {premiumProductName} steigt dein Upload-Limit pro Datei auf {fileSizeLimit}. Außerdem erhältst du animierte Avatare, längere Nachrichten und viele weitere {premiumProductName}-Vorteile."
|
||||
|
||||
#. Description under the screen share bitrate select in the video tab. Automatic is the label of the default option.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
msgid "With Automatic, the bitrate follows your resolution and frame rate. Higher values keep fast motion sharper and use more upload bandwidth."
|
||||
msgstr "Mit Automatisch folgt die Bitrate deiner Auflösung und Bildrate. Höhere Werte halten schnelle Bewegungen schärfer und verbrauchen mehr Upload-Bandbreite."
|
||||
|
||||
#. Label in the messages tab.
|
||||
#: src/features/user/components/modals/tabs/appearance_tab/MessagesTab.tsx
|
||||
msgid "With different display modes available"
|
||||
|
||||
+20
-6
@@ -1005,6 +1005,11 @@ msgstr "Ο/Η {authorNickname} προτιμά να γίνεται αναφορά
|
||||
msgid "{backgroundCount} / {maxBackgroundImages} {backgroundCount, plural, one {custom background} other {custom backgrounds}}"
|
||||
msgstr "{backgroundCount} / {maxBackgroundImages} {backgroundCount, plural, one {προσαρμοσμένο φόντο} other {προσαρμοσμένα φόντα}}"
|
||||
|
||||
#. Option label of the screen share bitrate select in the video tab. bitrate is a formatted number of megabits per second. Mbps is a technical unit token.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
msgid "{bitrate} Mbps"
|
||||
msgstr "{bitrate} Mbps"
|
||||
|
||||
#. Accessible label for a category row in the Discovery search sidebar. {categoryLabel} is the category name and {count} is how many communities match the current search in it. Both are inserted by code.
|
||||
#: src/features/discovery/discovery/DiscoverySearchFilters.tsx
|
||||
msgid "{categoryLabel}, {count, plural, one {# community} other {# communities}}"
|
||||
@@ -5411,6 +5416,7 @@ msgid "Autocomplete suggestion: {label}, {selectedOptionPosition} of {resultCoun
|
||||
msgstr "Πρόταση αυτόματης συμπλήρωσης: {label}, {selectedOptionPosition} από {resultCount}"
|
||||
|
||||
#. Channel overview settings tab label, control, or validation message (name, topic, slowmode, voice region, mature content gate).
|
||||
#. Default option of the screen share bitrate select in the video tab.
|
||||
#. Option label for a WebRTC content hint select.
|
||||
#. Option label for an SVC mode select.
|
||||
#. Option label for an encoder path select.
|
||||
@@ -5420,6 +5426,7 @@ msgstr "Πρόταση αυτόματης συμπλήρωσης: {label}, {sele
|
||||
#: src/features/app/components/setup/SetupWizardSteps.tsx
|
||||
#: src/features/channel/components/modals/channel_tabs/channel_overview_tab/RtcRegionSelect.tsx
|
||||
#: src/features/user/components/modals/tabs/advanced_settings_tab/AdvancedVideoControls.tsx
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
#: src/features/user/components/settings_utils/section_registry/NotificationsSections.ts
|
||||
#: src/features/voice/components/VoiceSettingsMenus.tsx
|
||||
msgid "Automatic"
|
||||
@@ -5983,7 +5990,9 @@ msgid "Biometrics"
|
||||
msgstr "Βιομετρικά στοιχεία"
|
||||
|
||||
#. Settings search synonym. Used to match this term when the user types it in the settings search bar.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
#. Short label in the video tab for the screen share video bitrate select. Keep it concise.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
#: src/features/user/components/settings_utils/section_registry/VoiceVideoSections.ts
|
||||
msgid "Bitrate"
|
||||
msgstr "Ρυθμός μετάδοσης δεδομένων"
|
||||
|
||||
@@ -14552,16 +14561,16 @@ msgstr "Ενεργοποιημένο"
|
||||
msgid "Encoder path"
|
||||
msgstr "Τύπος κωδικοποιητή"
|
||||
|
||||
#. Settings search entry description. One-line summary of what the settings search entry controls.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
msgid "Encoder path, SVC mode, and content hint"
|
||||
msgstr "Διαδρομή κωδικοποιητή, λειτουργία SVC και υπόδειξη περιεχομένου"
|
||||
|
||||
#. Description for the encoder path select.
|
||||
#: src/features/user/components/modals/tabs/advanced_settings_tab/AdvancedVideoControlsState.ts
|
||||
msgid "Encoder preference for new screen shares."
|
||||
msgstr "Προτιμώμενος κωδικοποιητής για νέα κοινή χρήση οθόνης."
|
||||
|
||||
#. Settings search entry description. One-line summary of what the settings search entry controls.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
msgid "Encoder, SVC, and bitrate presets"
|
||||
msgstr "Κωδικοποιητής, SVC και προεπιλογές ρυθμού μετάδοσης"
|
||||
|
||||
#. Label for the choice of how the SMTP connection is encrypted.
|
||||
#: src/features/app/components/setup/SetupWizardSteps.tsx
|
||||
msgid "Encryption"
|
||||
@@ -40429,6 +40438,11 @@ msgstr "Με το {PREMIUM_PRODUCT_NAME}, μπορείτε να χρησιμοπ
|
||||
msgid "With {premiumProductName}, your per-file upload limit increases to {fileSizeLimit}. You also get animated avatars, longer messages, and many other {premiumProductName} perks."
|
||||
msgstr "Με το {premiumProductName}, το όριο μεταφόρτωσης ανά αρχείο αυξάνεται σε {fileSizeLimit}. Αποκτάτε επίσης κινούμενα avatar, μεγαλύτερα μηνύματα και πολλά άλλα προνόμια του {premiumProductName}."
|
||||
|
||||
#. Description under the screen share bitrate select in the video tab. Automatic is the label of the default option.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
msgid "With Automatic, the bitrate follows your resolution and frame rate. Higher values keep fast motion sharper and use more upload bandwidth."
|
||||
msgstr "Με την Αυτόματη ρύθμιση, το bitrate ακολουθεί την ανάλυση και τον ρυθμό καρέ σας. Μεγαλύτερες τιμές διατηρούν την ευκρίνεια της γρήγορης κίνησης και χρησιμοποιούν περισσότερο εύρος ζώνης αποστολής."
|
||||
|
||||
#. Label in the messages tab.
|
||||
#: src/features/user/components/modals/tabs/appearance_tab/MessagesTab.tsx
|
||||
msgid "With different display modes available"
|
||||
|
||||
+20
-6
@@ -1005,6 +1005,11 @@ msgstr "{authorNickname} prefers to be @mentioned on replies. Send without the m
|
||||
msgid "{backgroundCount} / {maxBackgroundImages} {backgroundCount, plural, one {custom background} other {custom backgrounds}}"
|
||||
msgstr "{backgroundCount} / {maxBackgroundImages} {backgroundCount, plural, one {custom background} other {custom backgrounds}}"
|
||||
|
||||
#. Option label of the screen share bitrate select in the video tab. bitrate is a formatted number of megabits per second. Mbps is a technical unit token.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
msgid "{bitrate} Mbps"
|
||||
msgstr "{bitrate} Mbps"
|
||||
|
||||
#. Accessible label for a category row in the Discovery search sidebar. {categoryLabel} is the category name and {count} is how many communities match the current search in it. Both are inserted by code.
|
||||
#: src/features/discovery/discovery/DiscoverySearchFilters.tsx
|
||||
msgid "{categoryLabel}, {count, plural, one {# community} other {# communities}}"
|
||||
@@ -5411,6 +5416,7 @@ msgid "Autocomplete suggestion: {label}, {selectedOptionPosition} of {resultCoun
|
||||
msgstr "Autocomplete suggestion: {label}, {selectedOptionPosition} of {resultCount}"
|
||||
|
||||
#. Channel overview settings tab label, control, or validation message (name, topic, slowmode, voice region, mature content gate).
|
||||
#. Default option of the screen share bitrate select in the video tab.
|
||||
#. Option label for a WebRTC content hint select.
|
||||
#. Option label for an SVC mode select.
|
||||
#. Option label for an encoder path select.
|
||||
@@ -5420,6 +5426,7 @@ msgstr "Autocomplete suggestion: {label}, {selectedOptionPosition} of {resultCou
|
||||
#: src/features/app/components/setup/SetupWizardSteps.tsx
|
||||
#: src/features/channel/components/modals/channel_tabs/channel_overview_tab/RtcRegionSelect.tsx
|
||||
#: src/features/user/components/modals/tabs/advanced_settings_tab/AdvancedVideoControls.tsx
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
#: src/features/user/components/settings_utils/section_registry/NotificationsSections.ts
|
||||
#: src/features/voice/components/VoiceSettingsMenus.tsx
|
||||
msgid "Automatic"
|
||||
@@ -5983,7 +5990,9 @@ msgid "Biometrics"
|
||||
msgstr "Biometrics"
|
||||
|
||||
#. Settings search synonym. Used to match this term when the user types it in the settings search bar.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
#. Short label in the video tab for the screen share video bitrate select. Keep it concise.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
#: src/features/user/components/settings_utils/section_registry/VoiceVideoSections.ts
|
||||
msgid "Bitrate"
|
||||
msgstr "Bitrate"
|
||||
|
||||
@@ -14552,16 +14561,16 @@ msgstr "Enabled"
|
||||
msgid "Encoder path"
|
||||
msgstr "Encoder path"
|
||||
|
||||
#. Settings search entry description. One-line summary of what the settings search entry controls.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
msgid "Encoder path, SVC mode, and content hint"
|
||||
msgstr "Encoder path, SVC mode, and content hint"
|
||||
|
||||
#. Description for the encoder path select.
|
||||
#: src/features/user/components/modals/tabs/advanced_settings_tab/AdvancedVideoControlsState.ts
|
||||
msgid "Encoder preference for new screen shares."
|
||||
msgstr "Encoder preference for new screen shares."
|
||||
|
||||
#. Settings search entry description. One-line summary of what the settings search entry controls.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
msgid "Encoder, SVC, and bitrate presets"
|
||||
msgstr "Encoder, SVC and bitrate presets"
|
||||
|
||||
#. Label for the choice of how the SMTP connection is encrypted.
|
||||
#: src/features/app/components/setup/SetupWizardSteps.tsx
|
||||
msgid "Encryption"
|
||||
@@ -40429,6 +40438,11 @@ msgstr "With {PREMIUM_PRODUCT_NAME}, you can use animated avatars ({ANIMATED_AVA
|
||||
msgid "With {premiumProductName}, your per-file upload limit increases to {fileSizeLimit}. You also get animated avatars, longer messages, and many other {premiumProductName} perks."
|
||||
msgstr "With {premiumProductName}, your per-file upload limit increases to {fileSizeLimit}. You also get animated avatars, longer messages, and many other {premiumProductName} perks."
|
||||
|
||||
#. Description under the screen share bitrate select in the video tab. Automatic is the label of the default option.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
msgid "With Automatic, the bitrate follows your resolution and frame rate. Higher values keep fast motion sharper and use more upload bandwidth."
|
||||
msgstr "With Automatic, the bitrate follows your resolution and frame rate. Higher values keep fast motion sharper and use more upload bandwidth."
|
||||
|
||||
#. Label in the messages tab.
|
||||
#: src/features/user/components/modals/tabs/appearance_tab/MessagesTab.tsx
|
||||
msgid "With different display modes available"
|
||||
|
||||
+20
-6
@@ -1005,6 +1005,11 @@ msgstr "{authorNickname} prefers to be @mentioned on replies. Send without the m
|
||||
msgid "{backgroundCount} / {maxBackgroundImages} {backgroundCount, plural, one {custom background} other {custom backgrounds}}"
|
||||
msgstr "{backgroundCount} / {maxBackgroundImages} {backgroundCount, plural, one {custom background} other {custom backgrounds}}"
|
||||
|
||||
#. Option label of the screen share bitrate select in the video tab. bitrate is a formatted number of megabits per second. Mbps is a technical unit token.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
msgid "{bitrate} Mbps"
|
||||
msgstr "{bitrate} Mbps"
|
||||
|
||||
#. Accessible label for a category row in the Discovery search sidebar. {categoryLabel} is the category name and {count} is how many communities match the current search in it. Both are inserted by code.
|
||||
#: src/features/discovery/discovery/DiscoverySearchFilters.tsx
|
||||
msgid "{categoryLabel}, {count, plural, one {# community} other {# communities}}"
|
||||
@@ -5411,6 +5416,7 @@ msgid "Autocomplete suggestion: {label}, {selectedOptionPosition} of {resultCoun
|
||||
msgstr "Autocomplete suggestion: {label}, {selectedOptionPosition} of {resultCount}"
|
||||
|
||||
#. Channel overview settings tab label, control, or validation message (name, topic, slowmode, voice region, mature content gate).
|
||||
#. Default option of the screen share bitrate select in the video tab.
|
||||
#. Option label for a WebRTC content hint select.
|
||||
#. Option label for an SVC mode select.
|
||||
#. Option label for an encoder path select.
|
||||
@@ -5420,6 +5426,7 @@ msgstr "Autocomplete suggestion: {label}, {selectedOptionPosition} of {resultCou
|
||||
#: src/features/app/components/setup/SetupWizardSteps.tsx
|
||||
#: src/features/channel/components/modals/channel_tabs/channel_overview_tab/RtcRegionSelect.tsx
|
||||
#: src/features/user/components/modals/tabs/advanced_settings_tab/AdvancedVideoControls.tsx
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
#: src/features/user/components/settings_utils/section_registry/NotificationsSections.ts
|
||||
#: src/features/voice/components/VoiceSettingsMenus.tsx
|
||||
msgid "Automatic"
|
||||
@@ -5983,7 +5990,9 @@ msgid "Biometrics"
|
||||
msgstr "Biometrics"
|
||||
|
||||
#. Settings search synonym. Used to match this term when the user types it in the settings search bar.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
#. Short label in the video tab for the screen share video bitrate select. Keep it concise.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
#: src/features/user/components/settings_utils/section_registry/VoiceVideoSections.ts
|
||||
msgid "Bitrate"
|
||||
msgstr "Bitrate"
|
||||
|
||||
@@ -14552,16 +14561,16 @@ msgstr "Enabled"
|
||||
msgid "Encoder path"
|
||||
msgstr "Encoder path"
|
||||
|
||||
#. Settings search entry description. One-line summary of what the settings search entry controls.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
msgid "Encoder path, SVC mode, and content hint"
|
||||
msgstr "Encoder path, SVC mode, and content hint"
|
||||
|
||||
#. Description for the encoder path select.
|
||||
#: src/features/user/components/modals/tabs/advanced_settings_tab/AdvancedVideoControlsState.ts
|
||||
msgid "Encoder preference for new screen shares."
|
||||
msgstr "Encoder preference for new screen shares."
|
||||
|
||||
#. Settings search entry description. One-line summary of what the settings search entry controls.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
msgid "Encoder, SVC, and bitrate presets"
|
||||
msgstr "Encoder, SVC, and bitrate presets"
|
||||
|
||||
#. Label for the choice of how the SMTP connection is encrypted.
|
||||
#: src/features/app/components/setup/SetupWizardSteps.tsx
|
||||
msgid "Encryption"
|
||||
@@ -40429,6 +40438,11 @@ msgstr "With {PREMIUM_PRODUCT_NAME}, you can use animated avatars ({ANIMATED_AVA
|
||||
msgid "With {premiumProductName}, your per-file upload limit increases to {fileSizeLimit}. You also get animated avatars, longer messages, and many other {premiumProductName} perks."
|
||||
msgstr "With {premiumProductName}, your per-file upload limit increases to {fileSizeLimit}. You also get animated avatars, longer messages, and many other {premiumProductName} perks."
|
||||
|
||||
#. Description under the screen share bitrate select in the video tab. Automatic is the label of the default option.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
msgid "With Automatic, the bitrate follows your resolution and frame rate. Higher values keep fast motion sharper and use more upload bandwidth."
|
||||
msgstr "With Automatic, the bitrate follows your resolution and frame rate. Higher values keep fast motion sharper and use more upload bandwidth."
|
||||
|
||||
#. Label in the messages tab.
|
||||
#: src/features/user/components/modals/tabs/appearance_tab/MessagesTab.tsx
|
||||
msgid "With different display modes available"
|
||||
|
||||
+20
-6
@@ -1005,6 +1005,11 @@ msgstr "{authorNickname} prefiere que lo mencionen en las respuestas. ¿Enviar s
|
||||
msgid "{backgroundCount} / {maxBackgroundImages} {backgroundCount, plural, one {custom background} other {custom backgrounds}}"
|
||||
msgstr "{backgroundCount} / {maxBackgroundImages} {backgroundCount, plural, one {fondo personalizado} many {fondos personalizados} other {fondos personalizados}}"
|
||||
|
||||
#. Option label of the screen share bitrate select in the video tab. bitrate is a formatted number of megabits per second. Mbps is a technical unit token.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
msgid "{bitrate} Mbps"
|
||||
msgstr "{bitrate} Mbps"
|
||||
|
||||
#. Accessible label for a category row in the Discovery search sidebar. {categoryLabel} is the category name and {count} is how many communities match the current search in it. Both are inserted by code.
|
||||
#: src/features/discovery/discovery/DiscoverySearchFilters.tsx
|
||||
msgid "{categoryLabel}, {count, plural, one {# community} other {# communities}}"
|
||||
@@ -5411,6 +5416,7 @@ msgid "Autocomplete suggestion: {label}, {selectedOptionPosition} of {resultCoun
|
||||
msgstr "Sugerencia de autocompletar: {label}, {selectedOptionPosition} de {resultCount}"
|
||||
|
||||
#. Channel overview settings tab label, control, or validation message (name, topic, slowmode, voice region, mature content gate).
|
||||
#. Default option of the screen share bitrate select in the video tab.
|
||||
#. Option label for a WebRTC content hint select.
|
||||
#. Option label for an SVC mode select.
|
||||
#. Option label for an encoder path select.
|
||||
@@ -5420,6 +5426,7 @@ msgstr "Sugerencia de autocompletar: {label}, {selectedOptionPosition} de {resul
|
||||
#: src/features/app/components/setup/SetupWizardSteps.tsx
|
||||
#: src/features/channel/components/modals/channel_tabs/channel_overview_tab/RtcRegionSelect.tsx
|
||||
#: src/features/user/components/modals/tabs/advanced_settings_tab/AdvancedVideoControls.tsx
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
#: src/features/user/components/settings_utils/section_registry/NotificationsSections.ts
|
||||
#: src/features/voice/components/VoiceSettingsMenus.tsx
|
||||
msgid "Automatic"
|
||||
@@ -5983,7 +5990,9 @@ msgid "Biometrics"
|
||||
msgstr "Datos biométricos"
|
||||
|
||||
#. Settings search synonym. Used to match this term when the user types it in the settings search bar.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
#. Short label in the video tab for the screen share video bitrate select. Keep it concise.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
#: src/features/user/components/settings_utils/section_registry/VoiceVideoSections.ts
|
||||
msgid "Bitrate"
|
||||
msgstr "Tasa de bits"
|
||||
|
||||
@@ -14552,16 +14561,16 @@ msgstr "Activado"
|
||||
msgid "Encoder path"
|
||||
msgstr "Ruta del codificador"
|
||||
|
||||
#. Settings search entry description. One-line summary of what the settings search entry controls.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
msgid "Encoder path, SVC mode, and content hint"
|
||||
msgstr "Ruta del codificador, modo SVC y sugerencia de contenido"
|
||||
|
||||
#. Description for the encoder path select.
|
||||
#: src/features/user/components/modals/tabs/advanced_settings_tab/AdvancedVideoControlsState.ts
|
||||
msgid "Encoder preference for new screen shares."
|
||||
msgstr "Preferencia de codificador para nuevas transmisiones de pantalla compartida."
|
||||
|
||||
#. Settings search entry description. One-line summary of what the settings search entry controls.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
msgid "Encoder, SVC, and bitrate presets"
|
||||
msgstr "Codificador, SVC y ajustes preestablecidos de tasa de bits"
|
||||
|
||||
#. Label for the choice of how the SMTP connection is encrypted.
|
||||
#: src/features/app/components/setup/SetupWizardSteps.tsx
|
||||
msgid "Encryption"
|
||||
@@ -40429,6 +40438,11 @@ msgstr "Con {PREMIUM_PRODUCT_NAME}, puedes usar avatares animados ({ANIMATED_AVA
|
||||
msgid "With {premiumProductName}, your per-file upload limit increases to {fileSizeLimit}. You also get animated avatars, longer messages, and many other {premiumProductName} perks."
|
||||
msgstr "Con {premiumProductName}, tu límite de subida por archivo aumenta a {fileSizeLimit}. También obtienes avatares animados, mensajes más largos y muchos otros beneficios de {premiumProductName}."
|
||||
|
||||
#. Description under the screen share bitrate select in the video tab. Automatic is the label of the default option.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
msgid "With Automatic, the bitrate follows your resolution and frame rate. Higher values keep fast motion sharper and use more upload bandwidth."
|
||||
msgstr "Con Automático, la tasa de bits sigue tu resolución y tasa de fotogramas. Los valores más altos mantienen el movimiento rápido más nítido y usan más ancho de banda de subida."
|
||||
|
||||
#. Label in the messages tab.
|
||||
#: src/features/user/components/modals/tabs/appearance_tab/MessagesTab.tsx
|
||||
msgid "With different display modes available"
|
||||
|
||||
+20
-6
@@ -1005,6 +1005,11 @@ msgstr "{authorNickname} prefiere que se le mencione en las respuestas. ¿Enviar
|
||||
msgid "{backgroundCount} / {maxBackgroundImages} {backgroundCount, plural, one {custom background} other {custom backgrounds}}"
|
||||
msgstr "{backgroundCount} / {maxBackgroundImages} {backgroundCount, plural, one {fondo personalizado} many {fondos personalizados} other {fondos personalizados}}"
|
||||
|
||||
#. Option label of the screen share bitrate select in the video tab. bitrate is a formatted number of megabits per second. Mbps is a technical unit token.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
msgid "{bitrate} Mbps"
|
||||
msgstr "{bitrate} Mbps"
|
||||
|
||||
#. Accessible label for a category row in the Discovery search sidebar. {categoryLabel} is the category name and {count} is how many communities match the current search in it. Both are inserted by code.
|
||||
#: src/features/discovery/discovery/DiscoverySearchFilters.tsx
|
||||
msgid "{categoryLabel}, {count, plural, one {# community} other {# communities}}"
|
||||
@@ -5411,6 +5416,7 @@ msgid "Autocomplete suggestion: {label}, {selectedOptionPosition} of {resultCoun
|
||||
msgstr "Sugerencia de autocompletar: {label}, {selectedOptionPosition} de {resultCount}"
|
||||
|
||||
#. Channel overview settings tab label, control, or validation message (name, topic, slowmode, voice region, mature content gate).
|
||||
#. Default option of the screen share bitrate select in the video tab.
|
||||
#. Option label for a WebRTC content hint select.
|
||||
#. Option label for an SVC mode select.
|
||||
#. Option label for an encoder path select.
|
||||
@@ -5420,6 +5426,7 @@ msgstr "Sugerencia de autocompletar: {label}, {selectedOptionPosition} de {resul
|
||||
#: src/features/app/components/setup/SetupWizardSteps.tsx
|
||||
#: src/features/channel/components/modals/channel_tabs/channel_overview_tab/RtcRegionSelect.tsx
|
||||
#: src/features/user/components/modals/tabs/advanced_settings_tab/AdvancedVideoControls.tsx
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
#: src/features/user/components/settings_utils/section_registry/NotificationsSections.ts
|
||||
#: src/features/voice/components/VoiceSettingsMenus.tsx
|
||||
msgid "Automatic"
|
||||
@@ -5983,7 +5990,9 @@ msgid "Biometrics"
|
||||
msgstr "Datos biométricos"
|
||||
|
||||
#. Settings search synonym. Used to match this term when the user types it in the settings search bar.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
#. Short label in the video tab for the screen share video bitrate select. Keep it concise.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
#: src/features/user/components/settings_utils/section_registry/VoiceVideoSections.ts
|
||||
msgid "Bitrate"
|
||||
msgstr "Tasa de bits"
|
||||
|
||||
@@ -14552,16 +14561,16 @@ msgstr "Activado"
|
||||
msgid "Encoder path"
|
||||
msgstr "Ruta del codificador"
|
||||
|
||||
#. Settings search entry description. One-line summary of what the settings search entry controls.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
msgid "Encoder path, SVC mode, and content hint"
|
||||
msgstr "Ruta del codificador, modo SVC y sugerencia de contenido"
|
||||
|
||||
#. Description for the encoder path select.
|
||||
#: src/features/user/components/modals/tabs/advanced_settings_tab/AdvancedVideoControlsState.ts
|
||||
msgid "Encoder preference for new screen shares."
|
||||
msgstr "Preferencia del codificador para nuevos flujos de pantalla compartida."
|
||||
|
||||
#. Settings search entry description. One-line summary of what the settings search entry controls.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
msgid "Encoder, SVC, and bitrate presets"
|
||||
msgstr "Ajustes predeterminados de codificador, SVC y tasa de bits"
|
||||
|
||||
#. Label for the choice of how the SMTP connection is encrypted.
|
||||
#: src/features/app/components/setup/SetupWizardSteps.tsx
|
||||
msgid "Encryption"
|
||||
@@ -40429,6 +40438,11 @@ msgstr "Con {PREMIUM_PRODUCT_NAME}, puedes usar avatares animados ({ANIMATED_AVA
|
||||
msgid "With {premiumProductName}, your per-file upload limit increases to {fileSizeLimit}. You also get animated avatars, longer messages, and many other {premiumProductName} perks."
|
||||
msgstr "Con {premiumProductName}, tu límite de subida por archivo aumenta a {fileSizeLimit}. También obtienes avatares animados, mensajes más largos y muchas otras ventajas de {premiumProductName}."
|
||||
|
||||
#. Description under the screen share bitrate select in the video tab. Automatic is the label of the default option.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
msgid "With Automatic, the bitrate follows your resolution and frame rate. Higher values keep fast motion sharper and use more upload bandwidth."
|
||||
msgstr "Con Automático, la tasa de bits sigue tu resolución y tasa de fotogramas. Los valores más altos mantienen el movimiento rápido más nítido y usan más ancho de banda de subida."
|
||||
|
||||
#. Label in the messages tab.
|
||||
#: src/features/user/components/modals/tabs/appearance_tab/MessagesTab.tsx
|
||||
msgid "With different display modes available"
|
||||
|
||||
+20
-6
@@ -1005,6 +1005,11 @@ msgstr "{authorNickname} haluaa, että hänet mainitaan vastauksissa. Lähetetä
|
||||
msgid "{backgroundCount} / {maxBackgroundImages} {backgroundCount, plural, one {custom background} other {custom backgrounds}}"
|
||||
msgstr "{backgroundCount} / {maxBackgroundImages} {backgroundCount, plural, one {mukautettu tausta} other {mukautettua taustaa}}"
|
||||
|
||||
#. Option label of the screen share bitrate select in the video tab. bitrate is a formatted number of megabits per second. Mbps is a technical unit token.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
msgid "{bitrate} Mbps"
|
||||
msgstr "{bitrate} Mbit/s"
|
||||
|
||||
#. Accessible label for a category row in the Discovery search sidebar. {categoryLabel} is the category name and {count} is how many communities match the current search in it. Both are inserted by code.
|
||||
#: src/features/discovery/discovery/DiscoverySearchFilters.tsx
|
||||
msgid "{categoryLabel}, {count, plural, one {# community} other {# communities}}"
|
||||
@@ -5411,6 +5416,7 @@ msgid "Autocomplete suggestion: {label}, {selectedOptionPosition} of {resultCoun
|
||||
msgstr "Automaattinen täydennysehdotus: {label}, {selectedOptionPosition}/{resultCount}"
|
||||
|
||||
#. Channel overview settings tab label, control, or validation message (name, topic, slowmode, voice region, mature content gate).
|
||||
#. Default option of the screen share bitrate select in the video tab.
|
||||
#. Option label for a WebRTC content hint select.
|
||||
#. Option label for an SVC mode select.
|
||||
#. Option label for an encoder path select.
|
||||
@@ -5420,6 +5426,7 @@ msgstr "Automaattinen täydennysehdotus: {label}, {selectedOptionPosition}/{resu
|
||||
#: src/features/app/components/setup/SetupWizardSteps.tsx
|
||||
#: src/features/channel/components/modals/channel_tabs/channel_overview_tab/RtcRegionSelect.tsx
|
||||
#: src/features/user/components/modals/tabs/advanced_settings_tab/AdvancedVideoControls.tsx
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
#: src/features/user/components/settings_utils/section_registry/NotificationsSections.ts
|
||||
#: src/features/voice/components/VoiceSettingsMenus.tsx
|
||||
msgid "Automatic"
|
||||
@@ -5983,7 +5990,9 @@ msgid "Biometrics"
|
||||
msgstr "Biometriikka"
|
||||
|
||||
#. Settings search synonym. Used to match this term when the user types it in the settings search bar.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
#. Short label in the video tab for the screen share video bitrate select. Keep it concise.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
#: src/features/user/components/settings_utils/section_registry/VoiceVideoSections.ts
|
||||
msgid "Bitrate"
|
||||
msgstr "Bittinopeus"
|
||||
|
||||
@@ -14552,16 +14561,16 @@ msgstr "Käytössä"
|
||||
msgid "Encoder path"
|
||||
msgstr "Enkooderin polku"
|
||||
|
||||
#. Settings search entry description. One-line summary of what the settings search entry controls.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
msgid "Encoder path, SVC mode, and content hint"
|
||||
msgstr "Kooderin polku, SVC-tila ja sisältövihje"
|
||||
|
||||
#. Description for the encoder path select.
|
||||
#: src/features/user/components/modals/tabs/advanced_settings_tab/AdvancedVideoControlsState.ts
|
||||
msgid "Encoder preference for new screen shares."
|
||||
msgstr "Ensisijainen enkooderi uusissa näytönjaoissa."
|
||||
|
||||
#. Settings search entry description. One-line summary of what the settings search entry controls.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
msgid "Encoder, SVC, and bitrate presets"
|
||||
msgstr "Kooderi, SVC ja bittinopeusasetukset"
|
||||
|
||||
#. Label for the choice of how the SMTP connection is encrypted.
|
||||
#: src/features/app/components/setup/SetupWizardSteps.tsx
|
||||
msgid "Encryption"
|
||||
@@ -40429,6 +40438,11 @@ msgstr "{PREMIUM_PRODUCT_NAME}-tilauksella voit käyttää animoituja avatareita
|
||||
msgid "With {premiumProductName}, your per-file upload limit increases to {fileSizeLimit}. You also get animated avatars, longer messages, and many other {premiumProductName} perks."
|
||||
msgstr "{premiumProductName}-tilauksella tiedostokohtainen lähetysraja nousee arvoon {fileSizeLimit}. Saat myös animoituja avatareita, pidempiä viestejä ja monia muita {premiumProductName}-etuja."
|
||||
|
||||
#. Description under the screen share bitrate select in the video tab. Automatic is the label of the default option.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
msgid "With Automatic, the bitrate follows your resolution and frame rate. Higher values keep fast motion sharper and use more upload bandwidth."
|
||||
msgstr "Automaattinen: bittinopeus seuraa resoluutiotasi ja kuvataajuuttasi. Suuremmat arvot pitävät nopean liikkeen terävämpänä ja käyttävät enemmän lähetyskaistaa."
|
||||
|
||||
#. Label in the messages tab.
|
||||
#: src/features/user/components/modals/tabs/appearance_tab/MessagesTab.tsx
|
||||
msgid "With different display modes available"
|
||||
|
||||
+20
-6
@@ -1005,6 +1005,11 @@ msgstr "{authorNickname} préfère être mentionné dans les réponses. Envoyer
|
||||
msgid "{backgroundCount} / {maxBackgroundImages} {backgroundCount, plural, one {custom background} other {custom backgrounds}}"
|
||||
msgstr "{backgroundCount} / {maxBackgroundImages} {backgroundCount, plural, one {arrière-plan personnalisé} many {arrière-plans personnalisés} other {arrière-plans personnalisés}}"
|
||||
|
||||
#. Option label of the screen share bitrate select in the video tab. bitrate is a formatted number of megabits per second. Mbps is a technical unit token.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
msgid "{bitrate} Mbps"
|
||||
msgstr "{bitrate} Mbps"
|
||||
|
||||
#. Accessible label for a category row in the Discovery search sidebar. {categoryLabel} is the category name and {count} is how many communities match the current search in it. Both are inserted by code.
|
||||
#: src/features/discovery/discovery/DiscoverySearchFilters.tsx
|
||||
msgid "{categoryLabel}, {count, plural, one {# community} other {# communities}}"
|
||||
@@ -5411,6 +5416,7 @@ msgid "Autocomplete suggestion: {label}, {selectedOptionPosition} of {resultCoun
|
||||
msgstr "Suggestion de saisie semi-automatique : {label}, {selectedOptionPosition} sur {resultCount}"
|
||||
|
||||
#. Channel overview settings tab label, control, or validation message (name, topic, slowmode, voice region, mature content gate).
|
||||
#. Default option of the screen share bitrate select in the video tab.
|
||||
#. Option label for a WebRTC content hint select.
|
||||
#. Option label for an SVC mode select.
|
||||
#. Option label for an encoder path select.
|
||||
@@ -5420,6 +5426,7 @@ msgstr "Suggestion de saisie semi-automatique : {label}, {selectedOptionPosition
|
||||
#: src/features/app/components/setup/SetupWizardSteps.tsx
|
||||
#: src/features/channel/components/modals/channel_tabs/channel_overview_tab/RtcRegionSelect.tsx
|
||||
#: src/features/user/components/modals/tabs/advanced_settings_tab/AdvancedVideoControls.tsx
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
#: src/features/user/components/settings_utils/section_registry/NotificationsSections.ts
|
||||
#: src/features/voice/components/VoiceSettingsMenus.tsx
|
||||
msgid "Automatic"
|
||||
@@ -5983,7 +5990,9 @@ msgid "Biometrics"
|
||||
msgstr "Données biométriques"
|
||||
|
||||
#. Settings search synonym. Used to match this term when the user types it in the settings search bar.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
#. Short label in the video tab for the screen share video bitrate select. Keep it concise.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
#: src/features/user/components/settings_utils/section_registry/VoiceVideoSections.ts
|
||||
msgid "Bitrate"
|
||||
msgstr "Débit binaire"
|
||||
|
||||
@@ -14552,16 +14561,16 @@ msgstr "Activé"
|
||||
msgid "Encoder path"
|
||||
msgstr "Chemin de l’encodeur"
|
||||
|
||||
#. Settings search entry description. One-line summary of what the settings search entry controls.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
msgid "Encoder path, SVC mode, and content hint"
|
||||
msgstr "Chemin de l'encodeur, mode SVC et indication de contenu"
|
||||
|
||||
#. Description for the encoder path select.
|
||||
#: src/features/user/components/modals/tabs/advanced_settings_tab/AdvancedVideoControlsState.ts
|
||||
msgid "Encoder preference for new screen shares."
|
||||
msgstr "Préférence d’encodeur pour les nouveaux partages d’écran."
|
||||
|
||||
#. Settings search entry description. One-line summary of what the settings search entry controls.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
msgid "Encoder, SVC, and bitrate presets"
|
||||
msgstr "Encodeur, SVC et préréglages de débit"
|
||||
|
||||
#. Label for the choice of how the SMTP connection is encrypted.
|
||||
#: src/features/app/components/setup/SetupWizardSteps.tsx
|
||||
msgid "Encryption"
|
||||
@@ -40429,6 +40438,11 @@ msgstr "Avec {PREMIUM_PRODUCT_NAME}, vous pouvez utiliser des avatars animés ({
|
||||
msgid "With {premiumProductName}, your per-file upload limit increases to {fileSizeLimit}. You also get animated avatars, longer messages, and many other {premiumProductName} perks."
|
||||
msgstr "Avec {premiumProductName}, la limite d’envoi par fichier passe à {fileSizeLimit}. Vous bénéficiez aussi d’avatars animés, de messages plus longs et de nombreux autres avantages {premiumProductName}."
|
||||
|
||||
#. Description under the screen share bitrate select in the video tab. Automatic is the label of the default option.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
msgid "With Automatic, the bitrate follows your resolution and frame rate. Higher values keep fast motion sharper and use more upload bandwidth."
|
||||
msgstr "Avec Automatique, le débit binaire suit votre résolution et votre fréquence d'images. Des valeurs plus élevées gardent le mouvement rapide plus net et utilisent plus de bande passante d'envoi."
|
||||
|
||||
#. Label in the messages tab.
|
||||
#: src/features/user/components/modals/tabs/appearance_tab/MessagesTab.tsx
|
||||
msgid "With different display modes available"
|
||||
|
||||
+20
-6
@@ -1005,6 +1005,11 @@ msgstr "{authorNickname} מעדיף/ה לקבל אזכור בתגובות. לש
|
||||
msgid "{backgroundCount} / {maxBackgroundImages} {backgroundCount, plural, one {custom background} other {custom backgrounds}}"
|
||||
msgstr "{backgroundCount} / {maxBackgroundImages} {backgroundCount, plural, one {רקע מותאם אישית} two {רקעים מותאמים אישית} other {רקעים מותאמים אישית}}"
|
||||
|
||||
#. Option label of the screen share bitrate select in the video tab. bitrate is a formatted number of megabits per second. Mbps is a technical unit token.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
msgid "{bitrate} Mbps"
|
||||
msgstr "{bitrate} מגה-ביט לשנייה"
|
||||
|
||||
#. Accessible label for a category row in the Discovery search sidebar. {categoryLabel} is the category name and {count} is how many communities match the current search in it. Both are inserted by code.
|
||||
#: src/features/discovery/discovery/DiscoverySearchFilters.tsx
|
||||
msgid "{categoryLabel}, {count, plural, one {# community} other {# communities}}"
|
||||
@@ -5411,6 +5416,7 @@ msgid "Autocomplete suggestion: {label}, {selectedOptionPosition} of {resultCoun
|
||||
msgstr "הצעת השלמה אוטומטית: {label}, {selectedOptionPosition} מתוך {resultCount}"
|
||||
|
||||
#. Channel overview settings tab label, control, or validation message (name, topic, slowmode, voice region, mature content gate).
|
||||
#. Default option of the screen share bitrate select in the video tab.
|
||||
#. Option label for a WebRTC content hint select.
|
||||
#. Option label for an SVC mode select.
|
||||
#. Option label for an encoder path select.
|
||||
@@ -5420,6 +5426,7 @@ msgstr "הצעת השלמה אוטומטית: {label}, {selectedOptionPosition}
|
||||
#: src/features/app/components/setup/SetupWizardSteps.tsx
|
||||
#: src/features/channel/components/modals/channel_tabs/channel_overview_tab/RtcRegionSelect.tsx
|
||||
#: src/features/user/components/modals/tabs/advanced_settings_tab/AdvancedVideoControls.tsx
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
#: src/features/user/components/settings_utils/section_registry/NotificationsSections.ts
|
||||
#: src/features/voice/components/VoiceSettingsMenus.tsx
|
||||
msgid "Automatic"
|
||||
@@ -5983,7 +5990,9 @@ msgid "Biometrics"
|
||||
msgstr "ביומטריה"
|
||||
|
||||
#. Settings search synonym. Used to match this term when the user types it in the settings search bar.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
#. Short label in the video tab for the screen share video bitrate select. Keep it concise.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
#: src/features/user/components/settings_utils/section_registry/VoiceVideoSections.ts
|
||||
msgid "Bitrate"
|
||||
msgstr "קצב סיביות"
|
||||
|
||||
@@ -14552,16 +14561,16 @@ msgstr "מופעל"
|
||||
msgid "Encoder path"
|
||||
msgstr "נתיב המקודד"
|
||||
|
||||
#. Settings search entry description. One-line summary of what the settings search entry controls.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
msgid "Encoder path, SVC mode, and content hint"
|
||||
msgstr "נתיב מקודד, מצב SVC ורמז לתוכן"
|
||||
|
||||
#. Description for the encoder path select.
|
||||
#: src/features/user/components/modals/tabs/advanced_settings_tab/AdvancedVideoControlsState.ts
|
||||
msgid "Encoder preference for new screen shares."
|
||||
msgstr "העדפת מקודד עבור שיתופי מסך חדשים."
|
||||
|
||||
#. Settings search entry description. One-line summary of what the settings search entry controls.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
msgid "Encoder, SVC, and bitrate presets"
|
||||
msgstr "קידוד, SVC והגדרות קבועות מראש של קצב סיביות"
|
||||
|
||||
#. Label for the choice of how the SMTP connection is encrypted.
|
||||
#: src/features/app/components/setup/SetupWizardSteps.tsx
|
||||
msgid "Encryption"
|
||||
@@ -40429,6 +40438,11 @@ msgstr "עם {PREMIUM_PRODUCT_NAME}, תוכל להשתמש בתמונות פרו
|
||||
msgid "With {premiumProductName}, your per-file upload limit increases to {fileSizeLimit}. You also get animated avatars, longer messages, and many other {premiumProductName} perks."
|
||||
msgstr "עם {premiumProductName}, מגבלת ההעלאה לקובץ תגדל ל-{fileSizeLimit}. בנוסף תקבל תמונות פרופיל מונפשות, הודעות ארוכות יותר והרבה הטבות נוספות של {premiumProductName}."
|
||||
|
||||
#. Description under the screen share bitrate select in the video tab. Automatic is the label of the default option.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
msgid "With Automatic, the bitrate follows your resolution and frame rate. Higher values keep fast motion sharper and use more upload bandwidth."
|
||||
msgstr "עם אוטומטי, קצב הנתונים עוקב אחר הרזולוציה וקצב הפריימים שלך. ערכים גבוהים יותר שומרים על תנועה מהירה חדה יותר ומשתמשים ביותר רוחב פס להעלאה."
|
||||
|
||||
#. Label in the messages tab.
|
||||
#: src/features/user/components/modals/tabs/appearance_tab/MessagesTab.tsx
|
||||
msgid "With different display modes available"
|
||||
|
||||
+20
-6
@@ -1005,6 +1005,11 @@ msgstr "{authorNickname} चाहते हैं कि जवाब में
|
||||
msgid "{backgroundCount} / {maxBackgroundImages} {backgroundCount, plural, one {custom background} other {custom backgrounds}}"
|
||||
msgstr "{backgroundCount} / {maxBackgroundImages} {backgroundCount, plural, one {कस्टम बैकग्राउंड} other {कस्टम बैकग्राउंड}}"
|
||||
|
||||
#. Option label of the screen share bitrate select in the video tab. bitrate is a formatted number of megabits per second. Mbps is a technical unit token.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
msgid "{bitrate} Mbps"
|
||||
msgstr "{bitrate} एमबीपीएस"
|
||||
|
||||
#. Accessible label for a category row in the Discovery search sidebar. {categoryLabel} is the category name and {count} is how many communities match the current search in it. Both are inserted by code.
|
||||
#: src/features/discovery/discovery/DiscoverySearchFilters.tsx
|
||||
msgid "{categoryLabel}, {count, plural, one {# community} other {# communities}}"
|
||||
@@ -5411,6 +5416,7 @@ msgid "Autocomplete suggestion: {label}, {selectedOptionPosition} of {resultCoun
|
||||
msgstr "ऑटो-कम्प्लीट सुझाव: {label}, {resultCount} में से {selectedOptionPosition}"
|
||||
|
||||
#. Channel overview settings tab label, control, or validation message (name, topic, slowmode, voice region, mature content gate).
|
||||
#. Default option of the screen share bitrate select in the video tab.
|
||||
#. Option label for a WebRTC content hint select.
|
||||
#. Option label for an SVC mode select.
|
||||
#. Option label for an encoder path select.
|
||||
@@ -5420,6 +5426,7 @@ msgstr "ऑटो-कम्प्लीट सुझाव: {label}, {resultCoun
|
||||
#: src/features/app/components/setup/SetupWizardSteps.tsx
|
||||
#: src/features/channel/components/modals/channel_tabs/channel_overview_tab/RtcRegionSelect.tsx
|
||||
#: src/features/user/components/modals/tabs/advanced_settings_tab/AdvancedVideoControls.tsx
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
#: src/features/user/components/settings_utils/section_registry/NotificationsSections.ts
|
||||
#: src/features/voice/components/VoiceSettingsMenus.tsx
|
||||
msgid "Automatic"
|
||||
@@ -5983,7 +5990,9 @@ msgid "Biometrics"
|
||||
msgstr "बायोमेट्रिक्स"
|
||||
|
||||
#. Settings search synonym. Used to match this term when the user types it in the settings search bar.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
#. Short label in the video tab for the screen share video bitrate select. Keep it concise.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
#: src/features/user/components/settings_utils/section_registry/VoiceVideoSections.ts
|
||||
msgid "Bitrate"
|
||||
msgstr "बिटरेट"
|
||||
|
||||
@@ -14552,16 +14561,16 @@ msgstr "चालू है"
|
||||
msgid "Encoder path"
|
||||
msgstr "एन्कोडर पाथ"
|
||||
|
||||
#. Settings search entry description. One-line summary of what the settings search entry controls.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
msgid "Encoder path, SVC mode, and content hint"
|
||||
msgstr "एनकोडर पाथ, एसवीसी मोड और कंटेंट हिंट"
|
||||
|
||||
#. Description for the encoder path select.
|
||||
#: src/features/user/components/modals/tabs/advanced_settings_tab/AdvancedVideoControlsState.ts
|
||||
msgid "Encoder preference for new screen shares."
|
||||
msgstr "नए स्क्रीन शेयर के लिए एन्कोडर प्राथमिकता।"
|
||||
|
||||
#. Settings search entry description. One-line summary of what the settings search entry controls.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
msgid "Encoder, SVC, and bitrate presets"
|
||||
msgstr "एनकोडर, एसवीसी और बिटरेट प्रीसेट"
|
||||
|
||||
#. Label for the choice of how the SMTP connection is encrypted.
|
||||
#: src/features/app/components/setup/SetupWizardSteps.tsx
|
||||
msgid "Encryption"
|
||||
@@ -40429,6 +40438,11 @@ msgstr "{PREMIUM_PRODUCT_NAME} के साथ आप एनिमेटेड
|
||||
msgid "With {premiumProductName}, your per-file upload limit increases to {fileSizeLimit}. You also get animated avatars, longer messages, and many other {premiumProductName} perks."
|
||||
msgstr "{premiumProductName} के साथ आपकी प्रति-फ़ाइल अपलोड सीमा बढ़कर {fileSizeLimit} हो जाती है। साथ ही आपको एनिमेटेड अवतार, लंबे मैसेज और {premiumProductName} के कई दूसरे पर्क मिलते हैं।"
|
||||
|
||||
#. Description under the screen share bitrate select in the video tab. Automatic is the label of the default option.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
msgid "With Automatic, the bitrate follows your resolution and frame rate. Higher values keep fast motion sharper and use more upload bandwidth."
|
||||
msgstr "Automatic के साथ, बिटरेट आपके रिज़ॉल्यूशन और फ़्रेम रेट का अनुसरण करता है। उच्च मान तेज़ गति को अधिक शार्प रखते हैं और अधिक अपलोड बैंडविड्थ का उपयोग करते हैं।"
|
||||
|
||||
#. Label in the messages tab.
|
||||
#: src/features/user/components/modals/tabs/appearance_tab/MessagesTab.tsx
|
||||
msgid "With different display modes available"
|
||||
|
||||
+20
-6
@@ -1005,6 +1005,11 @@ msgstr "{authorNickname} želi @spominjanje u odgovorima. Želite li svejedno po
|
||||
msgid "{backgroundCount} / {maxBackgroundImages} {backgroundCount, plural, one {custom background} other {custom backgrounds}}"
|
||||
msgstr "{backgroundCount} / {maxBackgroundImages} {backgroundCount, plural, one {prilagođena pozadina} few {prilagođene pozadine} other {prilagođenih pozadina}}"
|
||||
|
||||
#. Option label of the screen share bitrate select in the video tab. bitrate is a formatted number of megabits per second. Mbps is a technical unit token.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
msgid "{bitrate} Mbps"
|
||||
msgstr "{bitrate} Mbps"
|
||||
|
||||
#. Accessible label for a category row in the Discovery search sidebar. {categoryLabel} is the category name and {count} is how many communities match the current search in it. Both are inserted by code.
|
||||
#: src/features/discovery/discovery/DiscoverySearchFilters.tsx
|
||||
msgid "{categoryLabel}, {count, plural, one {# community} other {# communities}}"
|
||||
@@ -5411,6 +5416,7 @@ msgid "Autocomplete suggestion: {label}, {selectedOptionPosition} of {resultCoun
|
||||
msgstr "Prijedlog automatskog dovršavanja: {label}, {selectedOptionPosition} od {resultCount}"
|
||||
|
||||
#. Channel overview settings tab label, control, or validation message (name, topic, slowmode, voice region, mature content gate).
|
||||
#. Default option of the screen share bitrate select in the video tab.
|
||||
#. Option label for a WebRTC content hint select.
|
||||
#. Option label for an SVC mode select.
|
||||
#. Option label for an encoder path select.
|
||||
@@ -5420,6 +5426,7 @@ msgstr "Prijedlog automatskog dovršavanja: {label}, {selectedOptionPosition} od
|
||||
#: src/features/app/components/setup/SetupWizardSteps.tsx
|
||||
#: src/features/channel/components/modals/channel_tabs/channel_overview_tab/RtcRegionSelect.tsx
|
||||
#: src/features/user/components/modals/tabs/advanced_settings_tab/AdvancedVideoControls.tsx
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
#: src/features/user/components/settings_utils/section_registry/NotificationsSections.ts
|
||||
#: src/features/voice/components/VoiceSettingsMenus.tsx
|
||||
msgid "Automatic"
|
||||
@@ -5983,7 +5990,9 @@ msgid "Biometrics"
|
||||
msgstr "Biometrija"
|
||||
|
||||
#. Settings search synonym. Used to match this term when the user types it in the settings search bar.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
#. Short label in the video tab for the screen share video bitrate select. Keep it concise.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
#: src/features/user/components/settings_utils/section_registry/VoiceVideoSections.ts
|
||||
msgid "Bitrate"
|
||||
msgstr "Brzina prijenosa podataka"
|
||||
|
||||
@@ -14552,16 +14561,16 @@ msgstr "Omogućeno"
|
||||
msgid "Encoder path"
|
||||
msgstr "Način kodiranja"
|
||||
|
||||
#. Settings search entry description. One-line summary of what the settings search entry controls.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
msgid "Encoder path, SVC mode, and content hint"
|
||||
msgstr "Putanja kodera, SVC način rada i savjet za sadržaj"
|
||||
|
||||
#. Description for the encoder path select.
|
||||
#: src/features/user/components/modals/tabs/advanced_settings_tab/AdvancedVideoControlsState.ts
|
||||
msgid "Encoder preference for new screen shares."
|
||||
msgstr "Željeni način kodiranja za nova dijeljenja zaslona."
|
||||
|
||||
#. Settings search entry description. One-line summary of what the settings search entry controls.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
msgid "Encoder, SVC, and bitrate presets"
|
||||
msgstr "Kodeci, SVC i unaprijed postavljene vrijednosti protoka"
|
||||
|
||||
#. Label for the choice of how the SMTP connection is encrypted.
|
||||
#: src/features/app/components/setup/SetupWizardSteps.tsx
|
||||
msgid "Encryption"
|
||||
@@ -40429,6 +40438,11 @@ msgstr "Uz {PREMIUM_PRODUCT_NAME} možete koristiti animirane avatare ({ANIMATED
|
||||
msgid "With {premiumProductName}, your per-file upload limit increases to {fileSizeLimit}. You also get animated avatars, longer messages, and many other {premiumProductName} perks."
|
||||
msgstr "Uz {premiumProductName} ograničenje veličine pojedine datoteke povećava se na {fileSizeLimit}. Dobivate i animirane avatare, duže poruke i mnoge druge pogodnosti {premiumProductName}."
|
||||
|
||||
#. Description under the screen share bitrate select in the video tab. Automatic is the label of the default option.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
msgid "With Automatic, the bitrate follows your resolution and frame rate. Higher values keep fast motion sharper and use more upload bandwidth."
|
||||
msgstr "Uz Automatski, protok podataka prati vašu razlučivost i broj sličica u sekundi. Veće vrijednosti zadržavaju oštrinu brze akcije i koriste više propusnosti za prijenos."
|
||||
|
||||
#. Label in the messages tab.
|
||||
#: src/features/user/components/modals/tabs/appearance_tab/MessagesTab.tsx
|
||||
msgid "With different display modes available"
|
||||
|
||||
+20
-6
@@ -1005,6 +1005,11 @@ msgstr "{authorNickname} szeretné, ha @említést kapna a válaszokban. Mégis
|
||||
msgid "{backgroundCount} / {maxBackgroundImages} {backgroundCount, plural, one {custom background} other {custom backgrounds}}"
|
||||
msgstr "{backgroundCount} / {maxBackgroundImages} {backgroundCount, plural, one {egyéni háttér} other {egyéni háttér}}"
|
||||
|
||||
#. Option label of the screen share bitrate select in the video tab. bitrate is a formatted number of megabits per second. Mbps is a technical unit token.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
msgid "{bitrate} Mbps"
|
||||
msgstr "{bitrate} Mbps"
|
||||
|
||||
#. Accessible label for a category row in the Discovery search sidebar. {categoryLabel} is the category name and {count} is how many communities match the current search in it. Both are inserted by code.
|
||||
#: src/features/discovery/discovery/DiscoverySearchFilters.tsx
|
||||
msgid "{categoryLabel}, {count, plural, one {# community} other {# communities}}"
|
||||
@@ -5411,6 +5416,7 @@ msgid "Autocomplete suggestion: {label}, {selectedOptionPosition} of {resultCoun
|
||||
msgstr "Automatikus kiegészítési javaslat: {label}, {selectedOptionPosition}/{resultCount}"
|
||||
|
||||
#. Channel overview settings tab label, control, or validation message (name, topic, slowmode, voice region, mature content gate).
|
||||
#. Default option of the screen share bitrate select in the video tab.
|
||||
#. Option label for a WebRTC content hint select.
|
||||
#. Option label for an SVC mode select.
|
||||
#. Option label for an encoder path select.
|
||||
@@ -5420,6 +5426,7 @@ msgstr "Automatikus kiegészítési javaslat: {label}, {selectedOptionPosition}/
|
||||
#: src/features/app/components/setup/SetupWizardSteps.tsx
|
||||
#: src/features/channel/components/modals/channel_tabs/channel_overview_tab/RtcRegionSelect.tsx
|
||||
#: src/features/user/components/modals/tabs/advanced_settings_tab/AdvancedVideoControls.tsx
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
#: src/features/user/components/settings_utils/section_registry/NotificationsSections.ts
|
||||
#: src/features/voice/components/VoiceSettingsMenus.tsx
|
||||
msgid "Automatic"
|
||||
@@ -5983,7 +5990,9 @@ msgid "Biometrics"
|
||||
msgstr "Biometria"
|
||||
|
||||
#. Settings search synonym. Used to match this term when the user types it in the settings search bar.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
#. Short label in the video tab for the screen share video bitrate select. Keep it concise.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
#: src/features/user/components/settings_utils/section_registry/VoiceVideoSections.ts
|
||||
msgid "Bitrate"
|
||||
msgstr "Bitráta"
|
||||
|
||||
@@ -14552,16 +14561,16 @@ msgstr "Engedélyezve"
|
||||
msgid "Encoder path"
|
||||
msgstr "Kódolási útvonal"
|
||||
|
||||
#. Settings search entry description. One-line summary of what the settings search entry controls.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
msgid "Encoder path, SVC mode, and content hint"
|
||||
msgstr "Kódolóútvonal, SVC mód és tartalomhint"
|
||||
|
||||
#. Description for the encoder path select.
|
||||
#: src/features/user/components/modals/tabs/advanced_settings_tab/AdvancedVideoControlsState.ts
|
||||
msgid "Encoder preference for new screen shares."
|
||||
msgstr "Az új képernyőmegosztásokhoz használt kódoló beállításai."
|
||||
|
||||
#. Settings search entry description. One-line summary of what the settings search entry controls.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
msgid "Encoder, SVC, and bitrate presets"
|
||||
msgstr "Kódoló, SVC és bitráta előbeállítások"
|
||||
|
||||
#. Label for the choice of how the SMTP connection is encrypted.
|
||||
#: src/features/app/components/setup/SetupWizardSteps.tsx
|
||||
msgid "Encryption"
|
||||
@@ -40429,6 +40438,11 @@ msgstr "A(z) {PREMIUM_PRODUCT_NAME} csomaggal animált profilképeket ({ANIMATED
|
||||
msgid "With {premiumProductName}, your per-file upload limit increases to {fileSizeLimit}. You also get animated avatars, longer messages, and many other {premiumProductName} perks."
|
||||
msgstr "A(z) {premiumProductName} csomaggal a fájlonkénti feltöltési korlátod {fileSizeLimit} lesz. Animált profilképeket, hosszabb üzeneteket és a(z) {premiumProductName} számos további előnyét is megkapod."
|
||||
|
||||
#. Description under the screen share bitrate select in the video tab. Automatic is the label of the default option.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
msgid "With Automatic, the bitrate follows your resolution and frame rate. Higher values keep fast motion sharper and use more upload bandwidth."
|
||||
msgstr "Az Automatikus beállítással a bitráta a felbontásodhoz és képkockasebességedhez igazodik. A magasabb értékek élesebben tartják a gyors mozgást, és több feltöltési sávszélességet használnak."
|
||||
|
||||
#. Label in the messages tab.
|
||||
#: src/features/user/components/modals/tabs/appearance_tab/MessagesTab.tsx
|
||||
msgid "With different display modes available"
|
||||
|
||||
+20
-6
@@ -1005,6 +1005,11 @@ msgstr "{authorNickname} lebih suka disebut dengan @sebutan saat dibalas. Tetap
|
||||
msgid "{backgroundCount} / {maxBackgroundImages} {backgroundCount, plural, one {custom background} other {custom backgrounds}}"
|
||||
msgstr "{backgroundCount} / {maxBackgroundImages} {backgroundCount, plural, other {latar belakang kustom}}"
|
||||
|
||||
#. Option label of the screen share bitrate select in the video tab. bitrate is a formatted number of megabits per second. Mbps is a technical unit token.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
msgid "{bitrate} Mbps"
|
||||
msgstr "{bitrate} Mbps"
|
||||
|
||||
#. Accessible label for a category row in the Discovery search sidebar. {categoryLabel} is the category name and {count} is how many communities match the current search in it. Both are inserted by code.
|
||||
#: src/features/discovery/discovery/DiscoverySearchFilters.tsx
|
||||
msgid "{categoryLabel}, {count, plural, one {# community} other {# communities}}"
|
||||
@@ -5411,6 +5416,7 @@ msgid "Autocomplete suggestion: {label}, {selectedOptionPosition} of {resultCoun
|
||||
msgstr "Saran pelengkapan otomatis: {label}, {selectedOptionPosition} dari {resultCount}"
|
||||
|
||||
#. Channel overview settings tab label, control, or validation message (name, topic, slowmode, voice region, mature content gate).
|
||||
#. Default option of the screen share bitrate select in the video tab.
|
||||
#. Option label for a WebRTC content hint select.
|
||||
#. Option label for an SVC mode select.
|
||||
#. Option label for an encoder path select.
|
||||
@@ -5420,6 +5426,7 @@ msgstr "Saran pelengkapan otomatis: {label}, {selectedOptionPosition} dari {resu
|
||||
#: src/features/app/components/setup/SetupWizardSteps.tsx
|
||||
#: src/features/channel/components/modals/channel_tabs/channel_overview_tab/RtcRegionSelect.tsx
|
||||
#: src/features/user/components/modals/tabs/advanced_settings_tab/AdvancedVideoControls.tsx
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
#: src/features/user/components/settings_utils/section_registry/NotificationsSections.ts
|
||||
#: src/features/voice/components/VoiceSettingsMenus.tsx
|
||||
msgid "Automatic"
|
||||
@@ -5983,7 +5990,9 @@ msgid "Biometrics"
|
||||
msgstr "Biometrik"
|
||||
|
||||
#. Settings search synonym. Used to match this term when the user types it in the settings search bar.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
#. Short label in the video tab for the screen share video bitrate select. Keep it concise.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
#: src/features/user/components/settings_utils/section_registry/VoiceVideoSections.ts
|
||||
msgid "Bitrate"
|
||||
msgstr "Bitrate"
|
||||
|
||||
@@ -14552,16 +14561,16 @@ msgstr "Diaktifkan"
|
||||
msgid "Encoder path"
|
||||
msgstr "Jalur encoder"
|
||||
|
||||
#. Settings search entry description. One-line summary of what the settings search entry controls.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
msgid "Encoder path, SVC mode, and content hint"
|
||||
msgstr "Jalur encoder, mode SVC, dan petunjuk konten"
|
||||
|
||||
#. Description for the encoder path select.
|
||||
#: src/features/user/components/modals/tabs/advanced_settings_tab/AdvancedVideoControlsState.ts
|
||||
msgid "Encoder preference for new screen shares."
|
||||
msgstr "Preferensi encoder untuk berbagi layar baru."
|
||||
|
||||
#. Settings search entry description. One-line summary of what the settings search entry controls.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
msgid "Encoder, SVC, and bitrate presets"
|
||||
msgstr "Encoder, preset SVC, dan bitrate"
|
||||
|
||||
#. Label for the choice of how the SMTP connection is encrypted.
|
||||
#: src/features/app/components/setup/SetupWizardSteps.tsx
|
||||
msgid "Encryption"
|
||||
@@ -40429,6 +40438,11 @@ msgstr "Dengan {PREMIUM_PRODUCT_NAME}, kamu bisa memakai avatar animasi ({ANIMAT
|
||||
msgid "With {premiumProductName}, your per-file upload limit increases to {fileSizeLimit}. You also get animated avatars, longer messages, and many other {premiumProductName} perks."
|
||||
msgstr "Dengan {premiumProductName}, batas unggah per file naik menjadi {fileSizeLimit}. Kamu juga mendapat avatar animasi, pesan yang lebih panjang, dan banyak keuntungan {premiumProductName} lainnya."
|
||||
|
||||
#. Description under the screen share bitrate select in the video tab. Automatic is the label of the default option.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
msgid "With Automatic, the bitrate follows your resolution and frame rate. Higher values keep fast motion sharper and use more upload bandwidth."
|
||||
msgstr "Dengan Otomatis, bitrate mengikuti resolusi dan frame rate Anda. Nilai yang lebih tinggi menjaga gerakan cepat tetap tajam dan menggunakan lebih banyak bandwidth unggah."
|
||||
|
||||
#. Label in the messages tab.
|
||||
#: src/features/user/components/modals/tabs/appearance_tab/MessagesTab.tsx
|
||||
msgid "With different display modes available"
|
||||
|
||||
+20
-6
@@ -1005,6 +1005,11 @@ msgstr "{authorNickname} preferisce essere menzionato nelle risposte. Vuoi invia
|
||||
msgid "{backgroundCount} / {maxBackgroundImages} {backgroundCount, plural, one {custom background} other {custom backgrounds}}"
|
||||
msgstr "{backgroundCount} / {maxBackgroundImages} {backgroundCount, plural, one {sfondo personalizzato} many {sfondi personalizzati} other {sfondi personalizzati}}"
|
||||
|
||||
#. Option label of the screen share bitrate select in the video tab. bitrate is a formatted number of megabits per second. Mbps is a technical unit token.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
msgid "{bitrate} Mbps"
|
||||
msgstr "{bitrate} Mbps"
|
||||
|
||||
#. Accessible label for a category row in the Discovery search sidebar. {categoryLabel} is the category name and {count} is how many communities match the current search in it. Both are inserted by code.
|
||||
#: src/features/discovery/discovery/DiscoverySearchFilters.tsx
|
||||
msgid "{categoryLabel}, {count, plural, one {# community} other {# communities}}"
|
||||
@@ -5411,6 +5416,7 @@ msgid "Autocomplete suggestion: {label}, {selectedOptionPosition} of {resultCoun
|
||||
msgstr "Suggerimento di completamento automatico: {label}, {selectedOptionPosition} di {resultCount}"
|
||||
|
||||
#. Channel overview settings tab label, control, or validation message (name, topic, slowmode, voice region, mature content gate).
|
||||
#. Default option of the screen share bitrate select in the video tab.
|
||||
#. Option label for a WebRTC content hint select.
|
||||
#. Option label for an SVC mode select.
|
||||
#. Option label for an encoder path select.
|
||||
@@ -5420,6 +5426,7 @@ msgstr "Suggerimento di completamento automatico: {label}, {selectedOptionPositi
|
||||
#: src/features/app/components/setup/SetupWizardSteps.tsx
|
||||
#: src/features/channel/components/modals/channel_tabs/channel_overview_tab/RtcRegionSelect.tsx
|
||||
#: src/features/user/components/modals/tabs/advanced_settings_tab/AdvancedVideoControls.tsx
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
#: src/features/user/components/settings_utils/section_registry/NotificationsSections.ts
|
||||
#: src/features/voice/components/VoiceSettingsMenus.tsx
|
||||
msgid "Automatic"
|
||||
@@ -5983,7 +5990,9 @@ msgid "Biometrics"
|
||||
msgstr "Biometria"
|
||||
|
||||
#. Settings search synonym. Used to match this term when the user types it in the settings search bar.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
#. Short label in the video tab for the screen share video bitrate select. Keep it concise.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
#: src/features/user/components/settings_utils/section_registry/VoiceVideoSections.ts
|
||||
msgid "Bitrate"
|
||||
msgstr "Bitrate"
|
||||
|
||||
@@ -14552,16 +14561,16 @@ msgstr "Abilitato"
|
||||
msgid "Encoder path"
|
||||
msgstr "Percorso encoder"
|
||||
|
||||
#. Settings search entry description. One-line summary of what the settings search entry controls.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
msgid "Encoder path, SVC mode, and content hint"
|
||||
msgstr "Percorso codificatore, modalità SVC e suggerimento contenuto"
|
||||
|
||||
#. Description for the encoder path select.
|
||||
#: src/features/user/components/modals/tabs/advanced_settings_tab/AdvancedVideoControlsState.ts
|
||||
msgid "Encoder preference for new screen shares."
|
||||
msgstr "Preferenza dell'encoder per le nuove condivisioni schermo."
|
||||
|
||||
#. Settings search entry description. One-line summary of what the settings search entry controls.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
msgid "Encoder, SVC, and bitrate presets"
|
||||
msgstr "Codifica, SVC e preimpostazioni bitrate"
|
||||
|
||||
#. Label for the choice of how the SMTP connection is encrypted.
|
||||
#: src/features/app/components/setup/SetupWizardSteps.tsx
|
||||
msgid "Encryption"
|
||||
@@ -40429,6 +40438,11 @@ msgstr "Con {PREMIUM_PRODUCT_NAME}, puoi utilizzare avatar animati ({ANIMATED_AV
|
||||
msgid "With {premiumProductName}, your per-file upload limit increases to {fileSizeLimit}. You also get animated avatars, longer messages, and many other {premiumProductName} perks."
|
||||
msgstr "Con {premiumProductName}, il limite di caricamento per file aumenta a {fileSizeLimit}. Ottieni anche avatar animati, messaggi più lunghi e molti altri vantaggi di {premiumProductName}."
|
||||
|
||||
#. Description under the screen share bitrate select in the video tab. Automatic is the label of the default option.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
msgid "With Automatic, the bitrate follows your resolution and frame rate. Higher values keep fast motion sharper and use more upload bandwidth."
|
||||
msgstr "Con Automatico, la velocità in bit segue la tua risoluzione e frequenza dei fotogrammi. Valori più alti mantengono più nitidi i movimenti veloci e utilizzano più larghezza di banda in upload."
|
||||
|
||||
#. Label in the messages tab.
|
||||
#: src/features/user/components/modals/tabs/appearance_tab/MessagesTab.tsx
|
||||
msgid "With different display modes available"
|
||||
|
||||
+20
-6
@@ -1005,6 +1005,11 @@ msgstr "{authorNickname}さんは返信時にメンションされることを
|
||||
msgid "{backgroundCount} / {maxBackgroundImages} {backgroundCount, plural, one {custom background} other {custom backgrounds}}"
|
||||
msgstr "{backgroundCount, plural, other {カスタム背景}} {backgroundCount} / {maxBackgroundImages}"
|
||||
|
||||
#. Option label of the screen share bitrate select in the video tab. bitrate is a formatted number of megabits per second. Mbps is a technical unit token.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
msgid "{bitrate} Mbps"
|
||||
msgstr "{bitrate} Mbps"
|
||||
|
||||
#. Accessible label for a category row in the Discovery search sidebar. {categoryLabel} is the category name and {count} is how many communities match the current search in it. Both are inserted by code.
|
||||
#: src/features/discovery/discovery/DiscoverySearchFilters.tsx
|
||||
msgid "{categoryLabel}, {count, plural, one {# community} other {# communities}}"
|
||||
@@ -5411,6 +5416,7 @@ msgid "Autocomplete suggestion: {label}, {selectedOptionPosition} of {resultCoun
|
||||
msgstr "入力候補: {label}、{resultCount}件中{selectedOptionPosition}番目"
|
||||
|
||||
#. Channel overview settings tab label, control, or validation message (name, topic, slowmode, voice region, mature content gate).
|
||||
#. Default option of the screen share bitrate select in the video tab.
|
||||
#. Option label for a WebRTC content hint select.
|
||||
#. Option label for an SVC mode select.
|
||||
#. Option label for an encoder path select.
|
||||
@@ -5420,6 +5426,7 @@ msgstr "入力候補: {label}、{resultCount}件中{selectedOptionPosition}番
|
||||
#: src/features/app/components/setup/SetupWizardSteps.tsx
|
||||
#: src/features/channel/components/modals/channel_tabs/channel_overview_tab/RtcRegionSelect.tsx
|
||||
#: src/features/user/components/modals/tabs/advanced_settings_tab/AdvancedVideoControls.tsx
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
#: src/features/user/components/settings_utils/section_registry/NotificationsSections.ts
|
||||
#: src/features/voice/components/VoiceSettingsMenus.tsx
|
||||
msgid "Automatic"
|
||||
@@ -5983,7 +5990,9 @@ msgid "Biometrics"
|
||||
msgstr "生体認証"
|
||||
|
||||
#. Settings search synonym. Used to match this term when the user types it in the settings search bar.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
#. Short label in the video tab for the screen share video bitrate select. Keep it concise.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
#: src/features/user/components/settings_utils/section_registry/VoiceVideoSections.ts
|
||||
msgid "Bitrate"
|
||||
msgstr "ビットレート"
|
||||
|
||||
@@ -14552,16 +14561,16 @@ msgstr "有効"
|
||||
msgid "Encoder path"
|
||||
msgstr "エンコーダーパス"
|
||||
|
||||
#. Settings search entry description. One-line summary of what the settings search entry controls.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
msgid "Encoder path, SVC mode, and content hint"
|
||||
msgstr "エンコーダーパス、SVCモード、コンテンツヒント"
|
||||
|
||||
#. Description for the encoder path select.
|
||||
#: src/features/user/components/modals/tabs/advanced_settings_tab/AdvancedVideoControlsState.ts
|
||||
msgid "Encoder preference for new screen shares."
|
||||
msgstr "新しい画面共有のエンコーダー設定"
|
||||
|
||||
#. Settings search entry description. One-line summary of what the settings search entry controls.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
msgid "Encoder, SVC, and bitrate presets"
|
||||
msgstr "エンコーダー、SVC、ビットレートプリセット"
|
||||
|
||||
#. Label for the choice of how the SMTP connection is encrypted.
|
||||
#: src/features/app/components/setup/SetupWizardSteps.tsx
|
||||
msgid "Encryption"
|
||||
@@ -40429,6 +40438,11 @@ msgstr "{PREMIUM_PRODUCT_NAME}では、アニメーションアバター({ANIM
|
||||
msgid "With {premiumProductName}, your per-file upload limit increases to {fileSizeLimit}. You also get animated avatars, longer messages, and many other {premiumProductName} perks."
|
||||
msgstr "{premiumProductName}を使用すると、ファイルあたりのアップロード制限が{fileSizeLimit}に増加し、アニメーションアバター、より長いメッセージ、その他多くの{premiumProductName}の特典を利用できます。"
|
||||
|
||||
#. Description under the screen share bitrate select in the video tab. Automatic is the label of the default option.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
msgid "With Automatic, the bitrate follows your resolution and frame rate. Higher values keep fast motion sharper and use more upload bandwidth."
|
||||
msgstr "自動を選択すると、ビットレートは解像度とフレームレートに合わせて調整されます。値が高いほど、動きの速い映像が鮮明になり、アップロード帯域幅をより多く使用します。"
|
||||
|
||||
#. Label in the messages tab.
|
||||
#: src/features/user/components/modals/tabs/appearance_tab/MessagesTab.tsx
|
||||
msgid "With different display modes available"
|
||||
|
||||
+20
-6
@@ -1005,6 +1005,11 @@ msgstr "{authorNickname}님은 답장 시 멘션되는 것을 선호합니다.
|
||||
msgid "{backgroundCount} / {maxBackgroundImages} {backgroundCount, plural, one {custom background} other {custom backgrounds}}"
|
||||
msgstr "{backgroundCount, plural, other {맞춤 배경}} {backgroundCount} / {maxBackgroundImages}개"
|
||||
|
||||
#. Option label of the screen share bitrate select in the video tab. bitrate is a formatted number of megabits per second. Mbps is a technical unit token.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
msgid "{bitrate} Mbps"
|
||||
msgstr "{bitrate}Mbps"
|
||||
|
||||
#. Accessible label for a category row in the Discovery search sidebar. {categoryLabel} is the category name and {count} is how many communities match the current search in it. Both are inserted by code.
|
||||
#: src/features/discovery/discovery/DiscoverySearchFilters.tsx
|
||||
msgid "{categoryLabel}, {count, plural, one {# community} other {# communities}}"
|
||||
@@ -5411,6 +5416,7 @@ msgid "Autocomplete suggestion: {label}, {selectedOptionPosition} of {resultCoun
|
||||
msgstr "자동 완성 제안: {label}, {resultCount}개 중 {selectedOptionPosition}번째"
|
||||
|
||||
#. Channel overview settings tab label, control, or validation message (name, topic, slowmode, voice region, mature content gate).
|
||||
#. Default option of the screen share bitrate select in the video tab.
|
||||
#. Option label for a WebRTC content hint select.
|
||||
#. Option label for an SVC mode select.
|
||||
#. Option label for an encoder path select.
|
||||
@@ -5420,6 +5426,7 @@ msgstr "자동 완성 제안: {label}, {resultCount}개 중 {selectedOptionPosit
|
||||
#: src/features/app/components/setup/SetupWizardSteps.tsx
|
||||
#: src/features/channel/components/modals/channel_tabs/channel_overview_tab/RtcRegionSelect.tsx
|
||||
#: src/features/user/components/modals/tabs/advanced_settings_tab/AdvancedVideoControls.tsx
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
#: src/features/user/components/settings_utils/section_registry/NotificationsSections.ts
|
||||
#: src/features/voice/components/VoiceSettingsMenus.tsx
|
||||
msgid "Automatic"
|
||||
@@ -5983,7 +5990,9 @@ msgid "Biometrics"
|
||||
msgstr "생체 인식"
|
||||
|
||||
#. Settings search synonym. Used to match this term when the user types it in the settings search bar.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
#. Short label in the video tab for the screen share video bitrate select. Keep it concise.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
#: src/features/user/components/settings_utils/section_registry/VoiceVideoSections.ts
|
||||
msgid "Bitrate"
|
||||
msgstr "비트 전송률"
|
||||
|
||||
@@ -14552,16 +14561,16 @@ msgstr "사용"
|
||||
msgid "Encoder path"
|
||||
msgstr "인코더 방식"
|
||||
|
||||
#. Settings search entry description. One-line summary of what the settings search entry controls.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
msgid "Encoder path, SVC mode, and content hint"
|
||||
msgstr "인코더 경로, SVC 모드 및 콘텐츠 힌트"
|
||||
|
||||
#. Description for the encoder path select.
|
||||
#: src/features/user/components/modals/tabs/advanced_settings_tab/AdvancedVideoControlsState.ts
|
||||
msgid "Encoder preference for new screen shares."
|
||||
msgstr "새 화면 공유에 사용할 인코더 설정입니다."
|
||||
|
||||
#. Settings search entry description. One-line summary of what the settings search entry controls.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
msgid "Encoder, SVC, and bitrate presets"
|
||||
msgstr "인코더, SVC 및 비트 전송률 사전 설정"
|
||||
|
||||
#. Label for the choice of how the SMTP connection is encrypted.
|
||||
#: src/features/app/components/setup/SetupWizardSteps.tsx
|
||||
msgid "Encryption"
|
||||
@@ -40429,6 +40438,11 @@ msgstr "{PREMIUM_PRODUCT_NAME}을 사용하면 애니메이션 아바타({ANIMAT
|
||||
msgid "With {premiumProductName}, your per-file upload limit increases to {fileSizeLimit}. You also get animated avatars, longer messages, and many other {premiumProductName} perks."
|
||||
msgstr "{premiumProductName}을 사용하면 파일당 업로드 제한이 {fileSizeLimit}로 증가하며, 애니메이션 아바타, 더 긴 메시지 및 기타 {premiumProductName} 혜택도 이용할 수 있습니다."
|
||||
|
||||
#. Description under the screen share bitrate select in the video tab. Automatic is the label of the default option.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
msgid "With Automatic, the bitrate follows your resolution and frame rate. Higher values keep fast motion sharper and use more upload bandwidth."
|
||||
msgstr "자동을 선택하면 비트 전송률이 해상도 및 프레임 속도를 따라갑니다. 값이 높을수록 빠른 움직임이 더 선명하게 유지되고 더 많은 업로드 대역폭을 사용합니다."
|
||||
|
||||
#. Label in the messages tab.
|
||||
#: src/features/user/components/modals/tabs/appearance_tab/MessagesTab.tsx
|
||||
msgid "With different display modes available"
|
||||
|
||||
+20
-6
@@ -1005,6 +1005,11 @@ msgstr "{authorNickname} pageidauja, kad atsakymai būtų siunčiami su @paminė
|
||||
msgid "{backgroundCount} / {maxBackgroundImages} {backgroundCount, plural, one {custom background} other {custom backgrounds}}"
|
||||
msgstr "{backgroundCount} / {maxBackgroundImages} {backgroundCount, plural, one {pasirinktinis fonas} few {pasirinktiniai fonai} many {pasirinktinio fono} other {pasirinktinių fonų}}"
|
||||
|
||||
#. Option label of the screen share bitrate select in the video tab. bitrate is a formatted number of megabits per second. Mbps is a technical unit token.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
msgid "{bitrate} Mbps"
|
||||
msgstr "{bitrate} Mbps"
|
||||
|
||||
#. Accessible label for a category row in the Discovery search sidebar. {categoryLabel} is the category name and {count} is how many communities match the current search in it. Both are inserted by code.
|
||||
#: src/features/discovery/discovery/DiscoverySearchFilters.tsx
|
||||
msgid "{categoryLabel}, {count, plural, one {# community} other {# communities}}"
|
||||
@@ -5411,6 +5416,7 @@ msgid "Autocomplete suggestion: {label}, {selectedOptionPosition} of {resultCoun
|
||||
msgstr "Automatinio užbaigimo pasiūlymas: {label}, {selectedOptionPosition} iš {resultCount}"
|
||||
|
||||
#. Channel overview settings tab label, control, or validation message (name, topic, slowmode, voice region, mature content gate).
|
||||
#. Default option of the screen share bitrate select in the video tab.
|
||||
#. Option label for a WebRTC content hint select.
|
||||
#. Option label for an SVC mode select.
|
||||
#. Option label for an encoder path select.
|
||||
@@ -5420,6 +5426,7 @@ msgstr "Automatinio užbaigimo pasiūlymas: {label}, {selectedOptionPosition} i
|
||||
#: src/features/app/components/setup/SetupWizardSteps.tsx
|
||||
#: src/features/channel/components/modals/channel_tabs/channel_overview_tab/RtcRegionSelect.tsx
|
||||
#: src/features/user/components/modals/tabs/advanced_settings_tab/AdvancedVideoControls.tsx
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
#: src/features/user/components/settings_utils/section_registry/NotificationsSections.ts
|
||||
#: src/features/voice/components/VoiceSettingsMenus.tsx
|
||||
msgid "Automatic"
|
||||
@@ -5983,7 +5990,9 @@ msgid "Biometrics"
|
||||
msgstr "Biometriniai duomenys"
|
||||
|
||||
#. Settings search synonym. Used to match this term when the user types it in the settings search bar.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
#. Short label in the video tab for the screen share video bitrate select. Keep it concise.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
#: src/features/user/components/settings_utils/section_registry/VoiceVideoSections.ts
|
||||
msgid "Bitrate"
|
||||
msgstr "Bitų srautas"
|
||||
|
||||
@@ -14552,16 +14561,16 @@ msgstr "Įjungta"
|
||||
msgid "Encoder path"
|
||||
msgstr "Kodavimo būdas"
|
||||
|
||||
#. Settings search entry description. One-line summary of what the settings search entry controls.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
msgid "Encoder path, SVC mode, and content hint"
|
||||
msgstr "Kodavimo kelias, SVC režimas ir turinio užuomina"
|
||||
|
||||
#. Description for the encoder path select.
|
||||
#: src/features/user/components/modals/tabs/advanced_settings_tab/AdvancedVideoControlsState.ts
|
||||
msgid "Encoder preference for new screen shares."
|
||||
msgstr "Pageidaujamas naujų ekrano bendrinimų kodavimo būdas."
|
||||
|
||||
#. Settings search entry description. One-line summary of what the settings search entry controls.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
msgid "Encoder, SVC, and bitrate presets"
|
||||
msgstr "Encoderio, SVC ir bitų perdavimo spartos išankstiniai nustatymai"
|
||||
|
||||
#. Label for the choice of how the SMTP connection is encrypted.
|
||||
#: src/features/app/components/setup/SetupWizardSteps.tsx
|
||||
msgid "Encryption"
|
||||
@@ -40430,6 +40439,11 @@ msgstr "Naudodami {PREMIUM_PRODUCT_NAME}, galite naudoti animuotus avatarus ({AN
|
||||
msgid "With {premiumProductName}, your per-file upload limit increases to {fileSizeLimit}. You also get animated avatars, longer messages, and many other {premiumProductName} perks."
|
||||
msgstr "Su {premiumProductName} vieno failo įkėlimo limitas padidėja iki {fileSizeLimit}. Taip pat gausite animuotus avatarus, ilgesnes žinutes ir daugybę kitų {premiumProductName} privilegijų."
|
||||
|
||||
#. Description under the screen share bitrate select in the video tab. Automatic is the label of the default option.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
msgid "With Automatic, the bitrate follows your resolution and frame rate. Higher values keep fast motion sharper and use more upload bandwidth."
|
||||
msgstr "Su „Automatinis“ bitų perdavimas atitinka jūsų skiriamąją gebą ir kadrų dažnį. Didesnės reikšmės išlaiko judesį ryškesnį ir naudoja daugiau įkėlimo pralaidumo."
|
||||
|
||||
#. Label in the messages tab.
|
||||
#: src/features/user/components/modals/tabs/appearance_tab/MessagesTab.tsx
|
||||
msgid "With different display modes available"
|
||||
|
||||
+20
-6
@@ -1005,6 +1005,11 @@ msgstr "{authorNickname} wil graag een @vermelding ontvangen bij antwoorden. Toc
|
||||
msgid "{backgroundCount} / {maxBackgroundImages} {backgroundCount, plural, one {custom background} other {custom backgrounds}}"
|
||||
msgstr "{backgroundCount} / {maxBackgroundImages} {backgroundCount, plural, one {aangepaste achtergrond} other {aangepaste achtergronden}}"
|
||||
|
||||
#. Option label of the screen share bitrate select in the video tab. bitrate is a formatted number of megabits per second. Mbps is a technical unit token.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
msgid "{bitrate} Mbps"
|
||||
msgstr "{bitrate} Mbps"
|
||||
|
||||
#. Accessible label for a category row in the Discovery search sidebar. {categoryLabel} is the category name and {count} is how many communities match the current search in it. Both are inserted by code.
|
||||
#: src/features/discovery/discovery/DiscoverySearchFilters.tsx
|
||||
msgid "{categoryLabel}, {count, plural, one {# community} other {# communities}}"
|
||||
@@ -5411,6 +5416,7 @@ msgid "Autocomplete suggestion: {label}, {selectedOptionPosition} of {resultCoun
|
||||
msgstr "Automatische aanvulling: {label}, {selectedOptionPosition} van {resultCount}"
|
||||
|
||||
#. Channel overview settings tab label, control, or validation message (name, topic, slowmode, voice region, mature content gate).
|
||||
#. Default option of the screen share bitrate select in the video tab.
|
||||
#. Option label for a WebRTC content hint select.
|
||||
#. Option label for an SVC mode select.
|
||||
#. Option label for an encoder path select.
|
||||
@@ -5420,6 +5426,7 @@ msgstr "Automatische aanvulling: {label}, {selectedOptionPosition} van {resultCo
|
||||
#: src/features/app/components/setup/SetupWizardSteps.tsx
|
||||
#: src/features/channel/components/modals/channel_tabs/channel_overview_tab/RtcRegionSelect.tsx
|
||||
#: src/features/user/components/modals/tabs/advanced_settings_tab/AdvancedVideoControls.tsx
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
#: src/features/user/components/settings_utils/section_registry/NotificationsSections.ts
|
||||
#: src/features/voice/components/VoiceSettingsMenus.tsx
|
||||
msgid "Automatic"
|
||||
@@ -5983,7 +5990,9 @@ msgid "Biometrics"
|
||||
msgstr "Biometrie"
|
||||
|
||||
#. Settings search synonym. Used to match this term when the user types it in the settings search bar.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
#. Short label in the video tab for the screen share video bitrate select. Keep it concise.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
#: src/features/user/components/settings_utils/section_registry/VoiceVideoSections.ts
|
||||
msgid "Bitrate"
|
||||
msgstr "Bitrate"
|
||||
|
||||
@@ -14552,16 +14561,16 @@ msgstr "Ingeschakeld"
|
||||
msgid "Encoder path"
|
||||
msgstr "Encoderpad"
|
||||
|
||||
#. Settings search entry description. One-line summary of what the settings search entry controls.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
msgid "Encoder path, SVC mode, and content hint"
|
||||
msgstr "Encoderpad, SVC-modus en contenthint"
|
||||
|
||||
#. Description for the encoder path select.
|
||||
#: src/features/user/components/modals/tabs/advanced_settings_tab/AdvancedVideoControlsState.ts
|
||||
msgid "Encoder preference for new screen shares."
|
||||
msgstr "Encodervoorkeur voor nieuwe schermdeelsessies."
|
||||
|
||||
#. Settings search entry description. One-line summary of what the settings search entry controls.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
msgid "Encoder, SVC, and bitrate presets"
|
||||
msgstr "Encoder-, SVC- en bitrate-presets"
|
||||
|
||||
#. Label for the choice of how the SMTP connection is encrypted.
|
||||
#: src/features/app/components/setup/SetupWizardSteps.tsx
|
||||
msgid "Encryption"
|
||||
@@ -40429,6 +40438,11 @@ msgstr "Met {PREMIUM_PRODUCT_NAME} kun je geanimeerde avatars ({ANIMATED_AVATAR_
|
||||
msgid "With {premiumProductName}, your per-file upload limit increases to {fileSizeLimit}. You also get animated avatars, longer messages, and many other {premiumProductName} perks."
|
||||
msgstr "Met {premiumProductName} stijgt je uploadlimiet per bestand naar {fileSizeLimit}. Je krijgt ook geanimeerde avatars, langere berichten en vele andere {premiumProductName}-voordelen."
|
||||
|
||||
#. Description under the screen share bitrate select in the video tab. Automatic is the label of the default option.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
msgid "With Automatic, the bitrate follows your resolution and frame rate. Higher values keep fast motion sharper and use more upload bandwidth."
|
||||
msgstr "Met Automatisch volgt de bitrate je resolutie en framesnelheid. Hogere waarden houden snelle bewegingen scherper en gebruiken meer uploadbandbreedte."
|
||||
|
||||
#. Label in the messages tab.
|
||||
#: src/features/user/components/modals/tabs/appearance_tab/MessagesTab.tsx
|
||||
msgid "With different display modes available"
|
||||
|
||||
+20
-6
@@ -1005,6 +1005,11 @@ msgstr "{authorNickname} foretrekker å bli @omtalt i svar. Vil du sende uten om
|
||||
msgid "{backgroundCount} / {maxBackgroundImages} {backgroundCount, plural, one {custom background} other {custom backgrounds}}"
|
||||
msgstr "{backgroundCount} / {maxBackgroundImages} {backgroundCount, plural, one {egendefinert bakgrunn} other {egendefinerte bakgrunner}}"
|
||||
|
||||
#. Option label of the screen share bitrate select in the video tab. bitrate is a formatted number of megabits per second. Mbps is a technical unit token.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
msgid "{bitrate} Mbps"
|
||||
msgstr "{bitrate} Mbps"
|
||||
|
||||
#. Accessible label for a category row in the Discovery search sidebar. {categoryLabel} is the category name and {count} is how many communities match the current search in it. Both are inserted by code.
|
||||
#: src/features/discovery/discovery/DiscoverySearchFilters.tsx
|
||||
msgid "{categoryLabel}, {count, plural, one {# community} other {# communities}}"
|
||||
@@ -5411,6 +5416,7 @@ msgid "Autocomplete suggestion: {label}, {selectedOptionPosition} of {resultCoun
|
||||
msgstr "Autofullføringsforslag: {label}, {selectedOptionPosition} av {resultCount}"
|
||||
|
||||
#. Channel overview settings tab label, control, or validation message (name, topic, slowmode, voice region, mature content gate).
|
||||
#. Default option of the screen share bitrate select in the video tab.
|
||||
#. Option label for a WebRTC content hint select.
|
||||
#. Option label for an SVC mode select.
|
||||
#. Option label for an encoder path select.
|
||||
@@ -5420,6 +5426,7 @@ msgstr "Autofullføringsforslag: {label}, {selectedOptionPosition} av {resultCou
|
||||
#: src/features/app/components/setup/SetupWizardSteps.tsx
|
||||
#: src/features/channel/components/modals/channel_tabs/channel_overview_tab/RtcRegionSelect.tsx
|
||||
#: src/features/user/components/modals/tabs/advanced_settings_tab/AdvancedVideoControls.tsx
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
#: src/features/user/components/settings_utils/section_registry/NotificationsSections.ts
|
||||
#: src/features/voice/components/VoiceSettingsMenus.tsx
|
||||
msgid "Automatic"
|
||||
@@ -5983,7 +5990,9 @@ msgid "Biometrics"
|
||||
msgstr "Biometri"
|
||||
|
||||
#. Settings search synonym. Used to match this term when the user types it in the settings search bar.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
#. Short label in the video tab for the screen share video bitrate select. Keep it concise.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
#: src/features/user/components/settings_utils/section_registry/VoiceVideoSections.ts
|
||||
msgid "Bitrate"
|
||||
msgstr "Bithastighet"
|
||||
|
||||
@@ -14552,16 +14561,16 @@ msgstr "Aktivert"
|
||||
msgid "Encoder path"
|
||||
msgstr "Kodingsmetode"
|
||||
|
||||
#. Settings search entry description. One-line summary of what the settings search entry controls.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
msgid "Encoder path, SVC mode, and content hint"
|
||||
msgstr "Kodingsbane, SVC-modus og innholdsindikator"
|
||||
|
||||
#. Description for the encoder path select.
|
||||
#: src/features/user/components/modals/tabs/advanced_settings_tab/AdvancedVideoControlsState.ts
|
||||
msgid "Encoder preference for new screen shares."
|
||||
msgstr "Foretrukket kodingsmetode for nye skjermdelinger."
|
||||
|
||||
#. Settings search entry description. One-line summary of what the settings search entry controls.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
msgid "Encoder, SVC, and bitrate presets"
|
||||
msgstr "Koder, SVC og bitratemaler"
|
||||
|
||||
#. Label for the choice of how the SMTP connection is encrypted.
|
||||
#: src/features/app/components/setup/SetupWizardSteps.tsx
|
||||
msgid "Encryption"
|
||||
@@ -40429,6 +40438,11 @@ msgstr "Med {PREMIUM_PRODUCT_NAME} kan du bruke animerte avatarer ({ANIMATED_AVA
|
||||
msgid "With {premiumProductName}, your per-file upload limit increases to {fileSizeLimit}. You also get animated avatars, longer messages, and many other {premiumProductName} perks."
|
||||
msgstr "Med {premiumProductName} øker opplastingsgrensen per fil til {fileSizeLimit}. Du får også animerte avatarer, lengre meldinger og mange andre {premiumProductName}-fordeler."
|
||||
|
||||
#. Description under the screen share bitrate select in the video tab. Automatic is the label of the default option.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
msgid "With Automatic, the bitrate follows your resolution and frame rate. Higher values keep fast motion sharper and use more upload bandwidth."
|
||||
msgstr "Med Automatisk følger bithastigheten oppløsningen og bildefrekvensen din. Høyere verdier holder raske bevegelser skarpere og bruker mer opplastingsbåndbredde."
|
||||
|
||||
#. Label in the messages tab.
|
||||
#: src/features/user/components/modals/tabs/appearance_tab/MessagesTab.tsx
|
||||
msgid "With different display modes available"
|
||||
|
||||
+20
-6
@@ -1005,6 +1005,11 @@ msgstr "{authorNickname} woli odpowiedzi ze wzmianką. Wysłać mimo to bez wzmi
|
||||
msgid "{backgroundCount} / {maxBackgroundImages} {backgroundCount, plural, one {custom background} other {custom backgrounds}}"
|
||||
msgstr "{backgroundCount} / {maxBackgroundImages} {backgroundCount, plural, one {niestandardowe tło} few {niestandardowe tła} many {niestandardowych teł} other {niestandardowego tła}}"
|
||||
|
||||
#. Option label of the screen share bitrate select in the video tab. bitrate is a formatted number of megabits per second. Mbps is a technical unit token.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
msgid "{bitrate} Mbps"
|
||||
msgstr "{bitrate} Mbps"
|
||||
|
||||
#. Accessible label for a category row in the Discovery search sidebar. {categoryLabel} is the category name and {count} is how many communities match the current search in it. Both are inserted by code.
|
||||
#: src/features/discovery/discovery/DiscoverySearchFilters.tsx
|
||||
msgid "{categoryLabel}, {count, plural, one {# community} other {# communities}}"
|
||||
@@ -5411,6 +5416,7 @@ msgid "Autocomplete suggestion: {label}, {selectedOptionPosition} of {resultCoun
|
||||
msgstr "Sugestia autouzupełniania: {label}, {selectedOptionPosition} z {resultCount}"
|
||||
|
||||
#. Channel overview settings tab label, control, or validation message (name, topic, slowmode, voice region, mature content gate).
|
||||
#. Default option of the screen share bitrate select in the video tab.
|
||||
#. Option label for a WebRTC content hint select.
|
||||
#. Option label for an SVC mode select.
|
||||
#. Option label for an encoder path select.
|
||||
@@ -5420,6 +5426,7 @@ msgstr "Sugestia autouzupełniania: {label}, {selectedOptionPosition} z {resultC
|
||||
#: src/features/app/components/setup/SetupWizardSteps.tsx
|
||||
#: src/features/channel/components/modals/channel_tabs/channel_overview_tab/RtcRegionSelect.tsx
|
||||
#: src/features/user/components/modals/tabs/advanced_settings_tab/AdvancedVideoControls.tsx
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
#: src/features/user/components/settings_utils/section_registry/NotificationsSections.ts
|
||||
#: src/features/voice/components/VoiceSettingsMenus.tsx
|
||||
msgid "Automatic"
|
||||
@@ -5983,7 +5990,9 @@ msgid "Biometrics"
|
||||
msgstr "Biometria"
|
||||
|
||||
#. Settings search synonym. Used to match this term when the user types it in the settings search bar.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
#. Short label in the video tab for the screen share video bitrate select. Keep it concise.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
#: src/features/user/components/settings_utils/section_registry/VoiceVideoSections.ts
|
||||
msgid "Bitrate"
|
||||
msgstr "Przepływność"
|
||||
|
||||
@@ -14552,16 +14561,16 @@ msgstr "Włączone"
|
||||
msgid "Encoder path"
|
||||
msgstr "Ścieżka kodera"
|
||||
|
||||
#. Settings search entry description. One-line summary of what the settings search entry controls.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
msgid "Encoder path, SVC mode, and content hint"
|
||||
msgstr "Ścieżka kodera, tryb SVC i wskazówka dotycząca zawartości"
|
||||
|
||||
#. Description for the encoder path select.
|
||||
#: src/features/user/components/modals/tabs/advanced_settings_tab/AdvancedVideoControlsState.ts
|
||||
msgid "Encoder preference for new screen shares."
|
||||
msgstr "Preferowana metoda kodowania dla nowych udostępnień ekranu."
|
||||
|
||||
#. Settings search entry description. One-line summary of what the settings search entry controls.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
msgid "Encoder, SVC, and bitrate presets"
|
||||
msgstr "Koder, SVC i presety przepustowości"
|
||||
|
||||
#. Label for the choice of how the SMTP connection is encrypted.
|
||||
#: src/features/app/components/setup/SetupWizardSteps.tsx
|
||||
msgid "Encryption"
|
||||
@@ -40429,6 +40438,11 @@ msgstr "Dzięki {PREMIUM_PRODUCT_NAME} możesz używać animowanych awatarów ({
|
||||
msgid "With {premiumProductName}, your per-file upload limit increases to {fileSizeLimit}. You also get animated avatars, longer messages, and many other {premiumProductName} perks."
|
||||
msgstr "Dzięki {premiumProductName} Twój limit rozmiaru pojedynczego przesyłanego pliku zwiększa się do {fileSizeLimit}. Zyskujesz też animowane awatary, dłuższe wiadomości i wiele innych korzyści z {premiumProductName}."
|
||||
|
||||
#. Description under the screen share bitrate select in the video tab. Automatic is the label of the default option.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
msgid "With Automatic, the bitrate follows your resolution and frame rate. Higher values keep fast motion sharper and use more upload bandwidth."
|
||||
msgstr "Z opcją Automatycznie jakość przesyłu dostosowuje się do Twojej rozdzielczości i liczby klatek na sekundę. Wyższe wartości sprawiają, że szybki ruch jest ostrzejszy i zużywają więcej przepustowości wysyłania."
|
||||
|
||||
#. Label in the messages tab.
|
||||
#: src/features/user/components/modals/tabs/appearance_tab/MessagesTab.tsx
|
||||
msgid "With different display modes available"
|
||||
|
||||
+20
-6
@@ -1005,6 +1005,11 @@ msgstr "{authorNickname} prefere ser @mencionado nas respostas. Enviar sem a men
|
||||
msgid "{backgroundCount} / {maxBackgroundImages} {backgroundCount, plural, one {custom background} other {custom backgrounds}}"
|
||||
msgstr "{backgroundCount} / {maxBackgroundImages} {backgroundCount, plural, =0 {planos de fundo personalizados} one {plano de fundo personalizado} many {planos de fundo personalizados} other {planos de fundo personalizados}}"
|
||||
|
||||
#. Option label of the screen share bitrate select in the video tab. bitrate is a formatted number of megabits per second. Mbps is a technical unit token.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
msgid "{bitrate} Mbps"
|
||||
msgstr "{bitrate} Mbps"
|
||||
|
||||
#. Accessible label for a category row in the Discovery search sidebar. {categoryLabel} is the category name and {count} is how many communities match the current search in it. Both are inserted by code.
|
||||
#: src/features/discovery/discovery/DiscoverySearchFilters.tsx
|
||||
msgid "{categoryLabel}, {count, plural, one {# community} other {# communities}}"
|
||||
@@ -5411,6 +5416,7 @@ msgid "Autocomplete suggestion: {label}, {selectedOptionPosition} of {resultCoun
|
||||
msgstr "Sugestão de preenchimento automático: {label}, {selectedOptionPosition} de {resultCount}"
|
||||
|
||||
#. Channel overview settings tab label, control, or validation message (name, topic, slowmode, voice region, mature content gate).
|
||||
#. Default option of the screen share bitrate select in the video tab.
|
||||
#. Option label for a WebRTC content hint select.
|
||||
#. Option label for an SVC mode select.
|
||||
#. Option label for an encoder path select.
|
||||
@@ -5420,6 +5426,7 @@ msgstr "Sugestão de preenchimento automático: {label}, {selectedOptionPosition
|
||||
#: src/features/app/components/setup/SetupWizardSteps.tsx
|
||||
#: src/features/channel/components/modals/channel_tabs/channel_overview_tab/RtcRegionSelect.tsx
|
||||
#: src/features/user/components/modals/tabs/advanced_settings_tab/AdvancedVideoControls.tsx
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
#: src/features/user/components/settings_utils/section_registry/NotificationsSections.ts
|
||||
#: src/features/voice/components/VoiceSettingsMenus.tsx
|
||||
msgid "Automatic"
|
||||
@@ -5983,7 +5990,9 @@ msgid "Biometrics"
|
||||
msgstr "Biometria"
|
||||
|
||||
#. Settings search synonym. Used to match this term when the user types it in the settings search bar.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
#. Short label in the video tab for the screen share video bitrate select. Keep it concise.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
#: src/features/user/components/settings_utils/section_registry/VoiceVideoSections.ts
|
||||
msgid "Bitrate"
|
||||
msgstr "Taxa de bits"
|
||||
|
||||
@@ -14552,16 +14561,16 @@ msgstr "Ativado"
|
||||
msgid "Encoder path"
|
||||
msgstr "Caminho do codificador"
|
||||
|
||||
#. Settings search entry description. One-line summary of what the settings search entry controls.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
msgid "Encoder path, SVC mode, and content hint"
|
||||
msgstr "Caminho do codificador, modo SVC e dica de conteúdo"
|
||||
|
||||
#. Description for the encoder path select.
|
||||
#: src/features/user/components/modals/tabs/advanced_settings_tab/AdvancedVideoControlsState.ts
|
||||
msgid "Encoder preference for new screen shares."
|
||||
msgstr "Preferência do codificador para novos compartilhamentos de tela."
|
||||
|
||||
#. Settings search entry description. One-line summary of what the settings search entry controls.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
msgid "Encoder, SVC, and bitrate presets"
|
||||
msgstr "Codificador, SVC e predefinições de taxa de bits"
|
||||
|
||||
#. Label for the choice of how the SMTP connection is encrypted.
|
||||
#: src/features/app/components/setup/SetupWizardSteps.tsx
|
||||
msgid "Encryption"
|
||||
@@ -40429,6 +40438,11 @@ msgstr "Com o {PREMIUM_PRODUCT_NAME}, você pode usar avatares animados ({ANIMAT
|
||||
msgid "With {premiumProductName}, your per-file upload limit increases to {fileSizeLimit}. You also get animated avatars, longer messages, and many other {premiumProductName} perks."
|
||||
msgstr "Com o {premiumProductName}, seu limite de upload por arquivo aumenta para {fileSizeLimit}, além de avatares animados, mensagens mais longas e muitos outros benefícios do {premiumProductName}."
|
||||
|
||||
#. Description under the screen share bitrate select in the video tab. Automatic is the label of the default option.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
msgid "With Automatic, the bitrate follows your resolution and frame rate. Higher values keep fast motion sharper and use more upload bandwidth."
|
||||
msgstr "Com Automático, a taxa de bits segue sua resolução e taxa de quadros. Valores mais altos mantêm o movimento rápido mais nítido e usam mais largura de banda de upload."
|
||||
|
||||
#. Label in the messages tab.
|
||||
#: src/features/user/components/modals/tabs/appearance_tab/MessagesTab.tsx
|
||||
msgid "With different display modes available"
|
||||
|
||||
+20
-6
@@ -1005,6 +1005,11 @@ msgstr "{authorNickname} preferă să fie menționat(ă) în răspunsuri. Trimi
|
||||
msgid "{backgroundCount} / {maxBackgroundImages} {backgroundCount, plural, one {custom background} other {custom backgrounds}}"
|
||||
msgstr "{backgroundCount} / {maxBackgroundImages} {backgroundCount, plural, one {fundal personalizat} few {fundaluri personalizate} other {de fundaluri personalizate}}"
|
||||
|
||||
#. Option label of the screen share bitrate select in the video tab. bitrate is a formatted number of megabits per second. Mbps is a technical unit token.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
msgid "{bitrate} Mbps"
|
||||
msgstr "{bitrate} Mbps"
|
||||
|
||||
#. Accessible label for a category row in the Discovery search sidebar. {categoryLabel} is the category name and {count} is how many communities match the current search in it. Both are inserted by code.
|
||||
#: src/features/discovery/discovery/DiscoverySearchFilters.tsx
|
||||
msgid "{categoryLabel}, {count, plural, one {# community} other {# communities}}"
|
||||
@@ -5411,6 +5416,7 @@ msgid "Autocomplete suggestion: {label}, {selectedOptionPosition} of {resultCoun
|
||||
msgstr "Sugestie de completare automată: {label}, {selectedOptionPosition} din {resultCount}"
|
||||
|
||||
#. Channel overview settings tab label, control, or validation message (name, topic, slowmode, voice region, mature content gate).
|
||||
#. Default option of the screen share bitrate select in the video tab.
|
||||
#. Option label for a WebRTC content hint select.
|
||||
#. Option label for an SVC mode select.
|
||||
#. Option label for an encoder path select.
|
||||
@@ -5420,6 +5426,7 @@ msgstr "Sugestie de completare automată: {label}, {selectedOptionPosition} din
|
||||
#: src/features/app/components/setup/SetupWizardSteps.tsx
|
||||
#: src/features/channel/components/modals/channel_tabs/channel_overview_tab/RtcRegionSelect.tsx
|
||||
#: src/features/user/components/modals/tabs/advanced_settings_tab/AdvancedVideoControls.tsx
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
#: src/features/user/components/settings_utils/section_registry/NotificationsSections.ts
|
||||
#: src/features/voice/components/VoiceSettingsMenus.tsx
|
||||
msgid "Automatic"
|
||||
@@ -5983,7 +5990,9 @@ msgid "Biometrics"
|
||||
msgstr "Biometrie"
|
||||
|
||||
#. Settings search synonym. Used to match this term when the user types it in the settings search bar.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
#. Short label in the video tab for the screen share video bitrate select. Keep it concise.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
#: src/features/user/components/settings_utils/section_registry/VoiceVideoSections.ts
|
||||
msgid "Bitrate"
|
||||
msgstr "Bitrate"
|
||||
|
||||
@@ -14552,16 +14561,16 @@ msgstr "Activat"
|
||||
msgid "Encoder path"
|
||||
msgstr "Cale de codificare"
|
||||
|
||||
#. Settings search entry description. One-line summary of what the settings search entry controls.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
msgid "Encoder path, SVC mode, and content hint"
|
||||
msgstr "Cale codor, mod SVC și sugestie de conținut"
|
||||
|
||||
#. Description for the encoder path select.
|
||||
#: src/features/user/components/modals/tabs/advanced_settings_tab/AdvancedVideoControlsState.ts
|
||||
msgid "Encoder preference for new screen shares."
|
||||
msgstr "Preferința codificatorului pentru noile partajări de ecran."
|
||||
|
||||
#. Settings search entry description. One-line summary of what the settings search entry controls.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
msgid "Encoder, SVC, and bitrate presets"
|
||||
msgstr "Codificator, SVC și presetări de bitrate"
|
||||
|
||||
#. Label for the choice of how the SMTP connection is encrypted.
|
||||
#: src/features/app/components/setup/SetupWizardSteps.tsx
|
||||
msgid "Encryption"
|
||||
@@ -40429,6 +40438,11 @@ msgstr "Cu {PREMIUM_PRODUCT_NAME}, poți folosi avatare animate ({ANIMATED_AVATA
|
||||
msgid "With {premiumProductName}, your per-file upload limit increases to {fileSizeLimit}. You also get animated avatars, longer messages, and many other {premiumProductName} perks."
|
||||
msgstr "Cu {premiumProductName}, limita ta de încărcare per fișier crește la {fileSizeLimit}, plus avatare animate, mesaje mai lungi și multe alte avantaje {premiumProductName}."
|
||||
|
||||
#. Description under the screen share bitrate select in the video tab. Automatic is the label of the default option.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
msgid "With Automatic, the bitrate follows your resolution and frame rate. Higher values keep fast motion sharper and use more upload bandwidth."
|
||||
msgstr "Cu Automat, rata de biți urmează rezoluția și rata de cadre. Valorile mai mari păstrează mișcarea rapidă mai clară și folosesc mai multă lățime de bandă de încărcare."
|
||||
|
||||
#. Label in the messages tab.
|
||||
#: src/features/user/components/modals/tabs/appearance_tab/MessagesTab.tsx
|
||||
msgid "With different display modes available"
|
||||
|
||||
+20
-6
@@ -1005,6 +1005,11 @@ msgstr "{authorNickname} предпочитает получать упомин
|
||||
msgid "{backgroundCount} / {maxBackgroundImages} {backgroundCount, plural, one {custom background} other {custom backgrounds}}"
|
||||
msgstr "{backgroundCount} / {maxBackgroundImages} {backgroundCount, plural, one {пользовательский фон} few {пользовательских фона} many {пользовательских фонов} other {пользовательского фона}}"
|
||||
|
||||
#. Option label of the screen share bitrate select in the video tab. bitrate is a formatted number of megabits per second. Mbps is a technical unit token.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
msgid "{bitrate} Mbps"
|
||||
msgstr "{bitrate} Мбит/с"
|
||||
|
||||
#. Accessible label for a category row in the Discovery search sidebar. {categoryLabel} is the category name and {count} is how many communities match the current search in it. Both are inserted by code.
|
||||
#: src/features/discovery/discovery/DiscoverySearchFilters.tsx
|
||||
msgid "{categoryLabel}, {count, plural, one {# community} other {# communities}}"
|
||||
@@ -5411,6 +5416,7 @@ msgid "Autocomplete suggestion: {label}, {selectedOptionPosition} of {resultCoun
|
||||
msgstr "Подсказка: {label}, {selectedOptionPosition} из {resultCount}"
|
||||
|
||||
#. Channel overview settings tab label, control, or validation message (name, topic, slowmode, voice region, mature content gate).
|
||||
#. Default option of the screen share bitrate select in the video tab.
|
||||
#. Option label for a WebRTC content hint select.
|
||||
#. Option label for an SVC mode select.
|
||||
#. Option label for an encoder path select.
|
||||
@@ -5420,6 +5426,7 @@ msgstr "Подсказка: {label}, {selectedOptionPosition} из {resultCount}
|
||||
#: src/features/app/components/setup/SetupWizardSteps.tsx
|
||||
#: src/features/channel/components/modals/channel_tabs/channel_overview_tab/RtcRegionSelect.tsx
|
||||
#: src/features/user/components/modals/tabs/advanced_settings_tab/AdvancedVideoControls.tsx
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
#: src/features/user/components/settings_utils/section_registry/NotificationsSections.ts
|
||||
#: src/features/voice/components/VoiceSettingsMenus.tsx
|
||||
msgid "Automatic"
|
||||
@@ -5983,7 +5990,9 @@ msgid "Biometrics"
|
||||
msgstr "Биометрия"
|
||||
|
||||
#. Settings search synonym. Used to match this term when the user types it in the settings search bar.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
#. Short label in the video tab for the screen share video bitrate select. Keep it concise.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
#: src/features/user/components/settings_utils/section_registry/VoiceVideoSections.ts
|
||||
msgid "Bitrate"
|
||||
msgstr "Битрейт"
|
||||
|
||||
@@ -14552,16 +14561,16 @@ msgstr "Включено"
|
||||
msgid "Encoder path"
|
||||
msgstr "Тип кодировщика"
|
||||
|
||||
#. Settings search entry description. One-line summary of what the settings search entry controls.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
msgid "Encoder path, SVC mode, and content hint"
|
||||
msgstr "Путь кодировщика, режим SVC и подсказка контента"
|
||||
|
||||
#. Description for the encoder path select.
|
||||
#: src/features/user/components/modals/tabs/advanced_settings_tab/AdvancedVideoControlsState.ts
|
||||
msgid "Encoder preference for new screen shares."
|
||||
msgstr "Предпочтительный кодировщик для новых демонстраций экрана."
|
||||
|
||||
#. Settings search entry description. One-line summary of what the settings search entry controls.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
msgid "Encoder, SVC, and bitrate presets"
|
||||
msgstr "Кодировщик, SVC и предустановки битрейта"
|
||||
|
||||
#. Label for the choice of how the SMTP connection is encrypted.
|
||||
#: src/features/app/components/setup/SetupWizardSteps.tsx
|
||||
msgid "Encryption"
|
||||
@@ -40429,6 +40438,11 @@ msgstr "Благодаря {PREMIUM_PRODUCT_NAME} вы можете исполь
|
||||
msgid "With {premiumProductName}, your per-file upload limit increases to {fileSizeLimit}. You also get animated avatars, longer messages, and many other {premiumProductName} perks."
|
||||
msgstr "С помощью {premiumProductName} лимит загрузки файлов увеличивается до {fileSizeLimit}, а также вы получаете доступ к анимированным аватарам, более длинным сообщениям и множеству других преимуществ {premiumProductName}."
|
||||
|
||||
#. Description under the screen share bitrate select in the video tab. Automatic is the label of the default option.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
msgid "With Automatic, the bitrate follows your resolution and frame rate. Higher values keep fast motion sharper and use more upload bandwidth."
|
||||
msgstr "С параметром «Авто» битрейт соответствует вашему разрешению и частоте кадров. Более высокие значения делают быстрое движение чётче и используют больше пропускной способности для загрузки."
|
||||
|
||||
#. Label in the messages tab.
|
||||
#: src/features/user/components/modals/tabs/appearance_tab/MessagesTab.tsx
|
||||
msgid "With different display modes available"
|
||||
|
||||
+20
-6
@@ -1005,6 +1005,11 @@ msgstr "{authorNickname} föredrar att bli @-omnämnd i svar. Skicka utan omnäm
|
||||
msgid "{backgroundCount} / {maxBackgroundImages} {backgroundCount, plural, one {custom background} other {custom backgrounds}}"
|
||||
msgstr "{backgroundCount} / {maxBackgroundImages} {backgroundCount, plural, one {anpassad bakgrund} other {anpassade bakgrunder}}"
|
||||
|
||||
#. Option label of the screen share bitrate select in the video tab. bitrate is a formatted number of megabits per second. Mbps is a technical unit token.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
msgid "{bitrate} Mbps"
|
||||
msgstr "{bitrate} Mbit/s"
|
||||
|
||||
#. Accessible label for a category row in the Discovery search sidebar. {categoryLabel} is the category name and {count} is how many communities match the current search in it. Both are inserted by code.
|
||||
#: src/features/discovery/discovery/DiscoverySearchFilters.tsx
|
||||
msgid "{categoryLabel}, {count, plural, one {# community} other {# communities}}"
|
||||
@@ -5411,6 +5416,7 @@ msgid "Autocomplete suggestion: {label}, {selectedOptionPosition} of {resultCoun
|
||||
msgstr "Föreslagen komplettering: {label}, {selectedOptionPosition} av {resultCount}"
|
||||
|
||||
#. Channel overview settings tab label, control, or validation message (name, topic, slowmode, voice region, mature content gate).
|
||||
#. Default option of the screen share bitrate select in the video tab.
|
||||
#. Option label for a WebRTC content hint select.
|
||||
#. Option label for an SVC mode select.
|
||||
#. Option label for an encoder path select.
|
||||
@@ -5420,6 +5426,7 @@ msgstr "Föreslagen komplettering: {label}, {selectedOptionPosition} av {resultC
|
||||
#: src/features/app/components/setup/SetupWizardSteps.tsx
|
||||
#: src/features/channel/components/modals/channel_tabs/channel_overview_tab/RtcRegionSelect.tsx
|
||||
#: src/features/user/components/modals/tabs/advanced_settings_tab/AdvancedVideoControls.tsx
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
#: src/features/user/components/settings_utils/section_registry/NotificationsSections.ts
|
||||
#: src/features/voice/components/VoiceSettingsMenus.tsx
|
||||
msgid "Automatic"
|
||||
@@ -5983,7 +5990,9 @@ msgid "Biometrics"
|
||||
msgstr "Biometri"
|
||||
|
||||
#. Settings search synonym. Used to match this term when the user types it in the settings search bar.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
#. Short label in the video tab for the screen share video bitrate select. Keep it concise.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
#: src/features/user/components/settings_utils/section_registry/VoiceVideoSections.ts
|
||||
msgid "Bitrate"
|
||||
msgstr "Bithastighet"
|
||||
|
||||
@@ -14552,16 +14561,16 @@ msgstr "Aktiverad"
|
||||
msgid "Encoder path"
|
||||
msgstr "Kodningsmetod"
|
||||
|
||||
#. Settings search entry description. One-line summary of what the settings search entry controls.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
msgid "Encoder path, SVC mode, and content hint"
|
||||
msgstr "Kodningssökväg, SVC-läge och innehållstips"
|
||||
|
||||
#. Description for the encoder path select.
|
||||
#: src/features/user/components/modals/tabs/advanced_settings_tab/AdvancedVideoControlsState.ts
|
||||
msgid "Encoder preference for new screen shares."
|
||||
msgstr "Önskad kodare för nya skärmdelningar."
|
||||
|
||||
#. Settings search entry description. One-line summary of what the settings search entry controls.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
msgid "Encoder, SVC, and bitrate presets"
|
||||
msgstr "Kodare, SVC och bithastighetsförinställningar"
|
||||
|
||||
#. Label for the choice of how the SMTP connection is encrypted.
|
||||
#: src/features/app/components/setup/SetupWizardSteps.tsx
|
||||
msgid "Encryption"
|
||||
@@ -40429,6 +40438,11 @@ msgstr "Med {PREMIUM_PRODUCT_NAME} kan du använda animerade avatarer ({ANIMATED
|
||||
msgid "With {premiumProductName}, your per-file upload limit increases to {fileSizeLimit}. You also get animated avatars, longer messages, and many other {premiumProductName} perks."
|
||||
msgstr "Med {premiumProductName} ökar uppladdningsgränsen per fil till {fileSizeLimit}. Du får också animerade avatarer, längre meddelanden och många andra {premiumProductName}-förmåner."
|
||||
|
||||
#. Description under the screen share bitrate select in the video tab. Automatic is the label of the default option.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
msgid "With Automatic, the bitrate follows your resolution and frame rate. Higher values keep fast motion sharper and use more upload bandwidth."
|
||||
msgstr "Med Automatisk följer bithastigheten din upplösning och bildfrekvens. Högre värden håller snabba rörelser skarpare och använder mer uppladdningsbandbredd."
|
||||
|
||||
#. Label in the messages tab.
|
||||
#: src/features/user/components/modals/tabs/appearance_tab/MessagesTab.tsx
|
||||
msgid "With different display modes available"
|
||||
|
||||
+20
-6
@@ -1005,6 +1005,11 @@ msgstr "{authorNickname} ต้องการให้กล่าวถึง
|
||||
msgid "{backgroundCount} / {maxBackgroundImages} {backgroundCount, plural, one {custom background} other {custom backgrounds}}"
|
||||
msgstr "{backgroundCount} / {maxBackgroundImages} {backgroundCount, plural, other {ภาพพื้นหลังที่กำหนดเอง}}"
|
||||
|
||||
#. Option label of the screen share bitrate select in the video tab. bitrate is a formatted number of megabits per second. Mbps is a technical unit token.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
msgid "{bitrate} Mbps"
|
||||
msgstr "{bitrate} เมกะบิตต่อวินาที"
|
||||
|
||||
#. Accessible label for a category row in the Discovery search sidebar. {categoryLabel} is the category name and {count} is how many communities match the current search in it. Both are inserted by code.
|
||||
#: src/features/discovery/discovery/DiscoverySearchFilters.tsx
|
||||
msgid "{categoryLabel}, {count, plural, one {# community} other {# communities}}"
|
||||
@@ -5411,6 +5416,7 @@ msgid "Autocomplete suggestion: {label}, {selectedOptionPosition} of {resultCoun
|
||||
msgstr "คำแนะนำการเติมข้อความอัตโนมัติ: {label}, {selectedOptionPosition} จาก {resultCount} รายการ"
|
||||
|
||||
#. Channel overview settings tab label, control, or validation message (name, topic, slowmode, voice region, mature content gate).
|
||||
#. Default option of the screen share bitrate select in the video tab.
|
||||
#. Option label for a WebRTC content hint select.
|
||||
#. Option label for an SVC mode select.
|
||||
#. Option label for an encoder path select.
|
||||
@@ -5420,6 +5426,7 @@ msgstr "คำแนะนำการเติมข้อความอัต
|
||||
#: src/features/app/components/setup/SetupWizardSteps.tsx
|
||||
#: src/features/channel/components/modals/channel_tabs/channel_overview_tab/RtcRegionSelect.tsx
|
||||
#: src/features/user/components/modals/tabs/advanced_settings_tab/AdvancedVideoControls.tsx
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
#: src/features/user/components/settings_utils/section_registry/NotificationsSections.ts
|
||||
#: src/features/voice/components/VoiceSettingsMenus.tsx
|
||||
msgid "Automatic"
|
||||
@@ -5983,7 +5990,9 @@ msgid "Biometrics"
|
||||
msgstr "ไบโอเมตริกซ์"
|
||||
|
||||
#. Settings search synonym. Used to match this term when the user types it in the settings search bar.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
#. Short label in the video tab for the screen share video bitrate select. Keep it concise.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
#: src/features/user/components/settings_utils/section_registry/VoiceVideoSections.ts
|
||||
msgid "Bitrate"
|
||||
msgstr "บิตเรต"
|
||||
|
||||
@@ -14552,16 +14561,16 @@ msgstr "เปิดใช้งาน"
|
||||
msgid "Encoder path"
|
||||
msgstr "เส้นทางตัวเข้ารหัส"
|
||||
|
||||
#. Settings search entry description. One-line summary of what the settings search entry controls.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
msgid "Encoder path, SVC mode, and content hint"
|
||||
msgstr "เส้นทางการเข้ารหัส, โหมด SVC และคำแนะนำเนื้อหา"
|
||||
|
||||
#. Description for the encoder path select.
|
||||
#: src/features/user/components/modals/tabs/advanced_settings_tab/AdvancedVideoControlsState.ts
|
||||
msgid "Encoder preference for new screen shares."
|
||||
msgstr "การตั้งค่าตัวเข้ารหัสสำหรับแชร์หน้าจอใหม่"
|
||||
|
||||
#. Settings search entry description. One-line summary of what the settings search entry controls.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
msgid "Encoder, SVC, and bitrate presets"
|
||||
msgstr "การตั้งค่าล่วงหน้าสำหรับตัวเข้ารหัส, SVC และบิตเรต"
|
||||
|
||||
#. Label for the choice of how the SMTP connection is encrypted.
|
||||
#: src/features/app/components/setup/SetupWizardSteps.tsx
|
||||
msgid "Encryption"
|
||||
@@ -40429,6 +40438,11 @@ msgstr "เมื่อคุณมี {PREMIUM_PRODUCT_NAME} คุณสาม
|
||||
msgid "With {premiumProductName}, your per-file upload limit increases to {fileSizeLimit}. You also get animated avatars, longer messages, and many other {premiumProductName} perks."
|
||||
msgstr "เมื่อสมัครใช้ {premiumProductName} ขีดจำกัดการอัปโหลดต่อไฟล์ของคุณจะเพิ่มเป็น {fileSizeLimit} และคุณยังได้รูปโปรไฟล์แบบเคลื่อนไหว ข้อความที่ยาวขึ้น และสิทธิประโยชน์ {premiumProductName} อื่นๆ อีกมากมาย"
|
||||
|
||||
#. Description under the screen share bitrate select in the video tab. Automatic is the label of the default option.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
msgid "With Automatic, the bitrate follows your resolution and frame rate. Higher values keep fast motion sharper and use more upload bandwidth."
|
||||
msgstr "ด้วยการตั้งค่าอัตโนมัติ บิตเรตจะปรับตามความละเอียดและอัตราเฟรมของคุณ ค่าที่สูงขึ้นจะทำให้ภาพเคลื่อนไหวเร็วคมชัดขึ้นและใช้แบนด์วิดท์อัปโหลดมากขึ้น"
|
||||
|
||||
#. Label in the messages tab.
|
||||
#: src/features/user/components/modals/tabs/appearance_tab/MessagesTab.tsx
|
||||
msgid "With different display modes available"
|
||||
|
||||
+20
-6
@@ -1005,6 +1005,11 @@ msgstr "{authorNickname}, yanıtlarda @bahsedilmeyi tercih ediyor. Yine de bahse
|
||||
msgid "{backgroundCount} / {maxBackgroundImages} {backgroundCount, plural, one {custom background} other {custom backgrounds}}"
|
||||
msgstr "{backgroundCount} / {maxBackgroundImages} {backgroundCount, plural, one {özel arka plan} other {özel arka plan}}"
|
||||
|
||||
#. Option label of the screen share bitrate select in the video tab. bitrate is a formatted number of megabits per second. Mbps is a technical unit token.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
msgid "{bitrate} Mbps"
|
||||
msgstr "{bitrate} Mbps"
|
||||
|
||||
#. Accessible label for a category row in the Discovery search sidebar. {categoryLabel} is the category name and {count} is how many communities match the current search in it. Both are inserted by code.
|
||||
#: src/features/discovery/discovery/DiscoverySearchFilters.tsx
|
||||
msgid "{categoryLabel}, {count, plural, one {# community} other {# communities}}"
|
||||
@@ -5411,6 +5416,7 @@ msgid "Autocomplete suggestion: {label}, {selectedOptionPosition} of {resultCoun
|
||||
msgstr "Otomatik tamamlama önerisi: {label}, {resultCount} sonuçtan {selectedOptionPosition}."
|
||||
|
||||
#. Channel overview settings tab label, control, or validation message (name, topic, slowmode, voice region, mature content gate).
|
||||
#. Default option of the screen share bitrate select in the video tab.
|
||||
#. Option label for a WebRTC content hint select.
|
||||
#. Option label for an SVC mode select.
|
||||
#. Option label for an encoder path select.
|
||||
@@ -5420,6 +5426,7 @@ msgstr "Otomatik tamamlama önerisi: {label}, {resultCount} sonuçtan {selectedO
|
||||
#: src/features/app/components/setup/SetupWizardSteps.tsx
|
||||
#: src/features/channel/components/modals/channel_tabs/channel_overview_tab/RtcRegionSelect.tsx
|
||||
#: src/features/user/components/modals/tabs/advanced_settings_tab/AdvancedVideoControls.tsx
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
#: src/features/user/components/settings_utils/section_registry/NotificationsSections.ts
|
||||
#: src/features/voice/components/VoiceSettingsMenus.tsx
|
||||
msgid "Automatic"
|
||||
@@ -5983,7 +5990,9 @@ msgid "Biometrics"
|
||||
msgstr "Biyometrik veriler"
|
||||
|
||||
#. Settings search synonym. Used to match this term when the user types it in the settings search bar.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
#. Short label in the video tab for the screen share video bitrate select. Keep it concise.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
#: src/features/user/components/settings_utils/section_registry/VoiceVideoSections.ts
|
||||
msgid "Bitrate"
|
||||
msgstr "Bit hızı"
|
||||
|
||||
@@ -14552,16 +14561,16 @@ msgstr "Etkin"
|
||||
msgid "Encoder path"
|
||||
msgstr "Kodlayıcı yolu"
|
||||
|
||||
#. Settings search entry description. One-line summary of what the settings search entry controls.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
msgid "Encoder path, SVC mode, and content hint"
|
||||
msgstr "Kodlayıcı yolu, SVC modu ve içerik ipucu"
|
||||
|
||||
#. Description for the encoder path select.
|
||||
#: src/features/user/components/modals/tabs/advanced_settings_tab/AdvancedVideoControlsState.ts
|
||||
msgid "Encoder preference for new screen shares."
|
||||
msgstr "Yeni ekran paylaşımları için kodlayıcı tercihi."
|
||||
|
||||
#. Settings search entry description. One-line summary of what the settings search entry controls.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
msgid "Encoder, SVC, and bitrate presets"
|
||||
msgstr "Kodlayıcı, SVC ve bit hızı ön ayarları"
|
||||
|
||||
#. Label for the choice of how the SMTP connection is encrypted.
|
||||
#: src/features/app/components/setup/SetupWizardSteps.tsx
|
||||
msgid "Encryption"
|
||||
@@ -40429,6 +40438,11 @@ msgstr "{PREMIUM_PRODUCT_NAME} ile hareketli avatarlar ({ANIMATED_AVATAR_FORMATS
|
||||
msgid "With {premiumProductName}, your per-file upload limit increases to {fileSizeLimit}. You also get animated avatars, longer messages, and many other {premiumProductName} perks."
|
||||
msgstr "{premiumProductName} ile dosya başına yükleme sınırınız {fileSizeLimit} boyutuna yükselir. Ayrıca hareketli avatarlar, daha uzun mesajlar ve diğer birçok {premiumProductName} avantajı elde edersiniz."
|
||||
|
||||
#. Description under the screen share bitrate select in the video tab. Automatic is the label of the default option.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
msgid "With Automatic, the bitrate follows your resolution and frame rate. Higher values keep fast motion sharper and use more upload bandwidth."
|
||||
msgstr "Otomatik ile bit hızınız çözünürlüğünüze ve kare hızınıza göre ayarlanır. Daha yüksek değerler hızlı hareketleri daha keskin tutar ve daha fazla yükleme bant genişliği kullanır."
|
||||
|
||||
#. Label in the messages tab.
|
||||
#: src/features/user/components/modals/tabs/appearance_tab/MessagesTab.tsx
|
||||
msgid "With different display modes available"
|
||||
|
||||
+20
-6
@@ -1005,6 +1005,11 @@ msgstr "{authorNickname} надає перевагу відповідям із @
|
||||
msgid "{backgroundCount} / {maxBackgroundImages} {backgroundCount, plural, one {custom background} other {custom backgrounds}}"
|
||||
msgstr "{backgroundCount} / {maxBackgroundImages} {backgroundCount, plural, one {власний фон} few {власні фони} many {власних фонів} other {власного фону}}"
|
||||
|
||||
#. Option label of the screen share bitrate select in the video tab. bitrate is a formatted number of megabits per second. Mbps is a technical unit token.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
msgid "{bitrate} Mbps"
|
||||
msgstr "{bitrate} Мбіт/с"
|
||||
|
||||
#. Accessible label for a category row in the Discovery search sidebar. {categoryLabel} is the category name and {count} is how many communities match the current search in it. Both are inserted by code.
|
||||
#: src/features/discovery/discovery/DiscoverySearchFilters.tsx
|
||||
msgid "{categoryLabel}, {count, plural, one {# community} other {# communities}}"
|
||||
@@ -5411,6 +5416,7 @@ msgid "Autocomplete suggestion: {label}, {selectedOptionPosition} of {resultCoun
|
||||
msgstr "Пропозиція автозаповнення: {label}, {selectedOptionPosition} з {resultCount}"
|
||||
|
||||
#. Channel overview settings tab label, control, or validation message (name, topic, slowmode, voice region, mature content gate).
|
||||
#. Default option of the screen share bitrate select in the video tab.
|
||||
#. Option label for a WebRTC content hint select.
|
||||
#. Option label for an SVC mode select.
|
||||
#. Option label for an encoder path select.
|
||||
@@ -5420,6 +5426,7 @@ msgstr "Пропозиція автозаповнення: {label}, {selectedOpt
|
||||
#: src/features/app/components/setup/SetupWizardSteps.tsx
|
||||
#: src/features/channel/components/modals/channel_tabs/channel_overview_tab/RtcRegionSelect.tsx
|
||||
#: src/features/user/components/modals/tabs/advanced_settings_tab/AdvancedVideoControls.tsx
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
#: src/features/user/components/settings_utils/section_registry/NotificationsSections.ts
|
||||
#: src/features/voice/components/VoiceSettingsMenus.tsx
|
||||
msgid "Automatic"
|
||||
@@ -5983,7 +5990,9 @@ msgid "Biometrics"
|
||||
msgstr "Біометрія"
|
||||
|
||||
#. Settings search synonym. Used to match this term when the user types it in the settings search bar.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
#. Short label in the video tab for the screen share video bitrate select. Keep it concise.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
#: src/features/user/components/settings_utils/section_registry/VoiceVideoSections.ts
|
||||
msgid "Bitrate"
|
||||
msgstr "Бітрейт"
|
||||
|
||||
@@ -14552,16 +14561,16 @@ msgstr "Увімкнено"
|
||||
msgid "Encoder path"
|
||||
msgstr "Спосіб кодування"
|
||||
|
||||
#. Settings search entry description. One-line summary of what the settings search entry controls.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
msgid "Encoder path, SVC mode, and content hint"
|
||||
msgstr "Шлях кодувальника, режим SVC та підказка вмісту"
|
||||
|
||||
#. Description for the encoder path select.
|
||||
#: src/features/user/components/modals/tabs/advanced_settings_tab/AdvancedVideoControlsState.ts
|
||||
msgid "Encoder preference for new screen shares."
|
||||
msgstr "Вибір кодувальника для нових демонстрацій екрана."
|
||||
|
||||
#. Settings search entry description. One-line summary of what the settings search entry controls.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
msgid "Encoder, SVC, and bitrate presets"
|
||||
msgstr "Кодувальник, SVC та попередні налаштування бітрейту"
|
||||
|
||||
#. Label for the choice of how the SMTP connection is encrypted.
|
||||
#: src/features/app/components/setup/SetupWizardSteps.tsx
|
||||
msgid "Encryption"
|
||||
@@ -40429,6 +40438,11 @@ msgstr "Завдяки {PREMIUM_PRODUCT_NAME} ви можете використ
|
||||
msgid "With {premiumProductName}, your per-file upload limit increases to {fileSizeLimit}. You also get animated avatars, longer messages, and many other {premiumProductName} perks."
|
||||
msgstr "Завдяки {premiumProductName} ліміт на завантаження одного файлу зростає до {fileSizeLimit}. Ви також отримуєте анімовані аватари, довші повідомлення та багато інших переваг {premiumProductName}."
|
||||
|
||||
#. Description under the screen share bitrate select in the video tab. Automatic is the label of the default option.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
msgid "With Automatic, the bitrate follows your resolution and frame rate. Higher values keep fast motion sharper and use more upload bandwidth."
|
||||
msgstr "З автоматичним бітрейтом він відповідає вашій роздільній здатності та частоті кадрів. Вищі значення роблять швидкий рух чіткішим і використовують більше пропускної здатності завантаження."
|
||||
|
||||
#. Label in the messages tab.
|
||||
#: src/features/user/components/modals/tabs/appearance_tab/MessagesTab.tsx
|
||||
msgid "With different display modes available"
|
||||
|
||||
+20
-6
@@ -1005,6 +1005,11 @@ msgstr "{authorNickname} thích được nhắc đến trong các tin nhắn tr
|
||||
msgid "{backgroundCount} / {maxBackgroundImages} {backgroundCount, plural, one {custom background} other {custom backgrounds}}"
|
||||
msgstr "{backgroundCount} / {maxBackgroundImages} {backgroundCount, plural, other {ảnh nền tùy chỉnh}}"
|
||||
|
||||
#. Option label of the screen share bitrate select in the video tab. bitrate is a formatted number of megabits per second. Mbps is a technical unit token.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
msgid "{bitrate} Mbps"
|
||||
msgstr "{bitrate} Mbps"
|
||||
|
||||
#. Accessible label for a category row in the Discovery search sidebar. {categoryLabel} is the category name and {count} is how many communities match the current search in it. Both are inserted by code.
|
||||
#: src/features/discovery/discovery/DiscoverySearchFilters.tsx
|
||||
msgid "{categoryLabel}, {count, plural, one {# community} other {# communities}}"
|
||||
@@ -5411,6 +5416,7 @@ msgid "Autocomplete suggestion: {label}, {selectedOptionPosition} of {resultCoun
|
||||
msgstr "Gợi ý tự động hoàn tất: {label}, {selectedOptionPosition} trên {resultCount}"
|
||||
|
||||
#. Channel overview settings tab label, control, or validation message (name, topic, slowmode, voice region, mature content gate).
|
||||
#. Default option of the screen share bitrate select in the video tab.
|
||||
#. Option label for a WebRTC content hint select.
|
||||
#. Option label for an SVC mode select.
|
||||
#. Option label for an encoder path select.
|
||||
@@ -5420,6 +5426,7 @@ msgstr "Gợi ý tự động hoàn tất: {label}, {selectedOptionPosition} tr
|
||||
#: src/features/app/components/setup/SetupWizardSteps.tsx
|
||||
#: src/features/channel/components/modals/channel_tabs/channel_overview_tab/RtcRegionSelect.tsx
|
||||
#: src/features/user/components/modals/tabs/advanced_settings_tab/AdvancedVideoControls.tsx
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
#: src/features/user/components/settings_utils/section_registry/NotificationsSections.ts
|
||||
#: src/features/voice/components/VoiceSettingsMenus.tsx
|
||||
msgid "Automatic"
|
||||
@@ -5983,7 +5990,9 @@ msgid "Biometrics"
|
||||
msgstr "Sinh trắc học"
|
||||
|
||||
#. Settings search synonym. Used to match this term when the user types it in the settings search bar.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
#. Short label in the video tab for the screen share video bitrate select. Keep it concise.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
#: src/features/user/components/settings_utils/section_registry/VoiceVideoSections.ts
|
||||
msgid "Bitrate"
|
||||
msgstr "Tốc độ bit"
|
||||
|
||||
@@ -14552,16 +14561,16 @@ msgstr "Đã bật"
|
||||
msgid "Encoder path"
|
||||
msgstr "Đường dẫn bộ mã hóa"
|
||||
|
||||
#. Settings search entry description. One-line summary of what the settings search entry controls.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
msgid "Encoder path, SVC mode, and content hint"
|
||||
msgstr "Đường dẫn bộ mã hóa, chế độ SVC và gợi ý nội dung"
|
||||
|
||||
#. Description for the encoder path select.
|
||||
#: src/features/user/components/modals/tabs/advanced_settings_tab/AdvancedVideoControlsState.ts
|
||||
msgid "Encoder preference for new screen shares."
|
||||
msgstr "Ưu tiên bộ mã hóa cho các lần chia sẻ màn hình mới."
|
||||
|
||||
#. Settings search entry description. One-line summary of what the settings search entry controls.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
msgid "Encoder, SVC, and bitrate presets"
|
||||
msgstr "Bộ mã hóa, SVC và cài đặt trước tốc độ bit"
|
||||
|
||||
#. Label for the choice of how the SMTP connection is encrypted.
|
||||
#: src/features/app/components/setup/SetupWizardSteps.tsx
|
||||
msgid "Encryption"
|
||||
@@ -40429,6 +40438,11 @@ msgstr "Với {PREMIUM_PRODUCT_NAME}, bạn có thể sử dụng ảnh đại d
|
||||
msgid "With {premiumProductName}, your per-file upload limit increases to {fileSizeLimit}. You also get animated avatars, longer messages, and many other {premiumProductName} perks."
|
||||
msgstr "Với {premiumProductName}, giới hạn tải lên mỗi tệp của bạn sẽ tăng lên {fileSizeLimit}. Bạn cũng nhận được ảnh đại diện động, tin nhắn dài hơn và nhiều đặc quyền {premiumProductName} khác."
|
||||
|
||||
#. Description under the screen share bitrate select in the video tab. Automatic is the label of the default option.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
msgid "With Automatic, the bitrate follows your resolution and frame rate. Higher values keep fast motion sharper and use more upload bandwidth."
|
||||
msgstr "Với Tự động, tốc độ bit sẽ theo độ phân giải và tốc độ khung hình của bạn. Giá trị cao hơn giữ cho chuyển động nhanh rõ nét hơn và sử dụng nhiều băng thông tải lên hơn."
|
||||
|
||||
#. Label in the messages tab.
|
||||
#: src/features/user/components/modals/tabs/appearance_tab/MessagesTab.tsx
|
||||
msgid "With different display modes available"
|
||||
|
||||
+20
-6
@@ -1005,6 +1005,11 @@ msgstr "{authorNickname} 希望在回复中被 @ 提及。仍要发送不带提
|
||||
msgid "{backgroundCount} / {maxBackgroundImages} {backgroundCount, plural, one {custom background} other {custom backgrounds}}"
|
||||
msgstr "{backgroundCount, plural, other {自定义背景}} {backgroundCount} / {maxBackgroundImages}"
|
||||
|
||||
#. Option label of the screen share bitrate select in the video tab. bitrate is a formatted number of megabits per second. Mbps is a technical unit token.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
msgid "{bitrate} Mbps"
|
||||
msgstr "{bitrate} 兆比特每秒"
|
||||
|
||||
#. Accessible label for a category row in the Discovery search sidebar. {categoryLabel} is the category name and {count} is how many communities match the current search in it. Both are inserted by code.
|
||||
#: src/features/discovery/discovery/DiscoverySearchFilters.tsx
|
||||
msgid "{categoryLabel}, {count, plural, one {# community} other {# communities}}"
|
||||
@@ -5411,6 +5416,7 @@ msgid "Autocomplete suggestion: {label}, {selectedOptionPosition} of {resultCoun
|
||||
msgstr "自动补全建议:{label},第 {selectedOptionPosition} 项,共 {resultCount} 项"
|
||||
|
||||
#. Channel overview settings tab label, control, or validation message (name, topic, slowmode, voice region, mature content gate).
|
||||
#. Default option of the screen share bitrate select in the video tab.
|
||||
#. Option label for a WebRTC content hint select.
|
||||
#. Option label for an SVC mode select.
|
||||
#. Option label for an encoder path select.
|
||||
@@ -5420,6 +5426,7 @@ msgstr "自动补全建议:{label},第 {selectedOptionPosition} 项,共 {r
|
||||
#: src/features/app/components/setup/SetupWizardSteps.tsx
|
||||
#: src/features/channel/components/modals/channel_tabs/channel_overview_tab/RtcRegionSelect.tsx
|
||||
#: src/features/user/components/modals/tabs/advanced_settings_tab/AdvancedVideoControls.tsx
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
#: src/features/user/components/settings_utils/section_registry/NotificationsSections.ts
|
||||
#: src/features/voice/components/VoiceSettingsMenus.tsx
|
||||
msgid "Automatic"
|
||||
@@ -5983,7 +5990,9 @@ msgid "Biometrics"
|
||||
msgstr "生物识别"
|
||||
|
||||
#. Settings search synonym. Used to match this term when the user types it in the settings search bar.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
#. Short label in the video tab for the screen share video bitrate select. Keep it concise.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
#: src/features/user/components/settings_utils/section_registry/VoiceVideoSections.ts
|
||||
msgid "Bitrate"
|
||||
msgstr "比特率"
|
||||
|
||||
@@ -14552,16 +14561,16 @@ msgstr "已启用"
|
||||
msgid "Encoder path"
|
||||
msgstr "编码器路径"
|
||||
|
||||
#. Settings search entry description. One-line summary of what the settings search entry controls.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
msgid "Encoder path, SVC mode, and content hint"
|
||||
msgstr "编码器路径、SVC 模式和内容提示"
|
||||
|
||||
#. Description for the encoder path select.
|
||||
#: src/features/user/components/modals/tabs/advanced_settings_tab/AdvancedVideoControlsState.ts
|
||||
msgid "Encoder preference for new screen shares."
|
||||
msgstr "新屏幕共享的首选编码器。"
|
||||
|
||||
#. Settings search entry description. One-line summary of what the settings search entry controls.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
msgid "Encoder, SVC, and bitrate presets"
|
||||
msgstr "编码器、SVC 和比特率预设"
|
||||
|
||||
#. Label for the choice of how the SMTP connection is encrypted.
|
||||
#: src/features/app/components/setup/SetupWizardSteps.tsx
|
||||
msgid "Encryption"
|
||||
@@ -40429,6 +40438,11 @@ msgstr "有了 {PREMIUM_PRODUCT_NAME},你可以使用动态头像({ANIMATED_
|
||||
msgid "With {premiumProductName}, your per-file upload limit increases to {fileSizeLimit}. You also get animated avatars, longer messages, and many other {premiumProductName} perks."
|
||||
msgstr "有了 {premiumProductName},你的单次文件上传限制将提高到 {fileSizeLimit},此外还有动态头像、更长的消息以及许多其他 {premiumProductName} 福利。"
|
||||
|
||||
#. Description under the screen share bitrate select in the video tab. Automatic is the label of the default option.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
msgid "With Automatic, the bitrate follows your resolution and frame rate. Higher values keep fast motion sharper and use more upload bandwidth."
|
||||
msgstr "使用“自动”时,比特率会根据您的分辨率和帧率进行调整。更高的值可以使快速移动的画面更清晰,但会占用更多上传带宽。"
|
||||
|
||||
#. Label in the messages tab.
|
||||
#: src/features/user/components/modals/tabs/appearance_tab/MessagesTab.tsx
|
||||
msgid "With different display modes available"
|
||||
|
||||
+20
-6
@@ -1005,6 +1005,11 @@ msgstr "{authorNickname} 偏好在回覆時被 @提及。仍要不提及就傳
|
||||
msgid "{backgroundCount} / {maxBackgroundImages} {backgroundCount, plural, one {custom background} other {custom backgrounds}}"
|
||||
msgstr "{backgroundCount} / {maxBackgroundImages} 個{backgroundCount, plural, one {自訂背景} other {自訂背景}}"
|
||||
|
||||
#. Option label of the screen share bitrate select in the video tab. bitrate is a formatted number of megabits per second. Mbps is a technical unit token.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
msgid "{bitrate} Mbps"
|
||||
msgstr "{bitrate} Mbps"
|
||||
|
||||
#. Accessible label for a category row in the Discovery search sidebar. {categoryLabel} is the category name and {count} is how many communities match the current search in it. Both are inserted by code.
|
||||
#: src/features/discovery/discovery/DiscoverySearchFilters.tsx
|
||||
msgid "{categoryLabel}, {count, plural, one {# community} other {# communities}}"
|
||||
@@ -5411,6 +5416,7 @@ msgid "Autocomplete suggestion: {label}, {selectedOptionPosition} of {resultCoun
|
||||
msgstr "自動完成建議:{label},第 {selectedOptionPosition} 項,共 {resultCount} 項"
|
||||
|
||||
#. Channel overview settings tab label, control, or validation message (name, topic, slowmode, voice region, mature content gate).
|
||||
#. Default option of the screen share bitrate select in the video tab.
|
||||
#. Option label for a WebRTC content hint select.
|
||||
#. Option label for an SVC mode select.
|
||||
#. Option label for an encoder path select.
|
||||
@@ -5420,6 +5426,7 @@ msgstr "自動完成建議:{label},第 {selectedOptionPosition} 項,共 {r
|
||||
#: src/features/app/components/setup/SetupWizardSteps.tsx
|
||||
#: src/features/channel/components/modals/channel_tabs/channel_overview_tab/RtcRegionSelect.tsx
|
||||
#: src/features/user/components/modals/tabs/advanced_settings_tab/AdvancedVideoControls.tsx
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
#: src/features/user/components/settings_utils/section_registry/NotificationsSections.ts
|
||||
#: src/features/voice/components/VoiceSettingsMenus.tsx
|
||||
msgid "Automatic"
|
||||
@@ -5983,7 +5990,9 @@ msgid "Biometrics"
|
||||
msgstr "生物辨識"
|
||||
|
||||
#. Settings search synonym. Used to match this term when the user types it in the settings search bar.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
#. Short label in the video tab for the screen share video bitrate select. Keep it concise.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
#: src/features/user/components/settings_utils/section_registry/VoiceVideoSections.ts
|
||||
msgid "Bitrate"
|
||||
msgstr "位元率"
|
||||
|
||||
@@ -14552,16 +14561,16 @@ msgstr "已啟用"
|
||||
msgid "Encoder path"
|
||||
msgstr "編碼方式"
|
||||
|
||||
#. Settings search entry description. One-line summary of what the settings search entry controls.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
msgid "Encoder path, SVC mode, and content hint"
|
||||
msgstr "編碼器路徑、SVC 模式和內容提示"
|
||||
|
||||
#. Description for the encoder path select.
|
||||
#: src/features/user/components/modals/tabs/advanced_settings_tab/AdvancedVideoControlsState.ts
|
||||
msgid "Encoder preference for new screen shares."
|
||||
msgstr "新螢幕分享的編碼器偏好設定。"
|
||||
|
||||
#. Settings search entry description. One-line summary of what the settings search entry controls.
|
||||
#: src/features/user/components/settings_utils/search_index/VoiceVideoIndex.ts
|
||||
msgid "Encoder, SVC, and bitrate presets"
|
||||
msgstr "編碼器、SVC 和位元率預設"
|
||||
|
||||
#. Label for the choice of how the SMTP connection is encrypted.
|
||||
#: src/features/app/components/setup/SetupWizardSteps.tsx
|
||||
msgid "Encryption"
|
||||
@@ -40429,6 +40438,11 @@ msgstr "有了 {PREMIUM_PRODUCT_NAME},您可以使用動態頭像({ANIMATED_
|
||||
msgid "With {premiumProductName}, your per-file upload limit increases to {fileSizeLimit}. You also get animated avatars, longer messages, and many other {premiumProductName} perks."
|
||||
msgstr "有了 {premiumProductName},您的單檔上傳上限會提高到 {fileSizeLimit},還能使用動態頭像、更長的訊息,以及許多其他 {premiumProductName} 福利。"
|
||||
|
||||
#. Description under the screen share bitrate select in the video tab. Automatic is the label of the default option.
|
||||
#: src/features/user/components/modals/tabs/UserVideoTab.tsx
|
||||
msgid "With Automatic, the bitrate follows your resolution and frame rate. Higher values keep fast motion sharper and use more upload bandwidth."
|
||||
msgstr "使用「自動」,位元率會隨著您的解析度和畫面播放速率調整。較高的數值可讓動態畫面更清晰,並使用更多上傳頻寬。"
|
||||
|
||||
#. Label in the messages tab.
|
||||
#: src/features/user/components/modals/tabs/appearance_tab/MessagesTab.tsx
|
||||
msgid "With different display modes available"
|
||||
|
||||
@@ -102,6 +102,25 @@ const MIRROR_CAMERA_DESCRIPTOR = msg({
|
||||
message: 'Mirror camera',
|
||||
comment: 'Switch label in the video tab for flipping the local camera preview horizontally.',
|
||||
});
|
||||
const SCREEN_SHARE_BITRATE_DESCRIPTOR = msg({
|
||||
message: 'Bitrate',
|
||||
comment: 'Short label in the video tab for the screen share video bitrate select. Keep it concise.',
|
||||
});
|
||||
const SCREEN_SHARE_BITRATE_DESCRIPTION_DESCRIPTOR = msg({
|
||||
message:
|
||||
'With Automatic, the bitrate follows your resolution and frame rate. Higher values keep fast motion sharper and use more upload bandwidth.',
|
||||
comment:
|
||||
'Description under the screen share bitrate select in the video tab. Automatic is the label of the default option.',
|
||||
});
|
||||
const SCREEN_SHARE_BITRATE_AUTOMATIC_DESCRIPTOR = msg({
|
||||
message: 'Automatic',
|
||||
comment: 'Default option of the screen share bitrate select in the video tab.',
|
||||
});
|
||||
const SCREEN_SHARE_BITRATE_MBPS_DESCRIPTOR = msg({
|
||||
message: '{bitrate} Mbps',
|
||||
comment:
|
||||
'Option label of the screen share bitrate select in the video tab. bitrate is a formatted number of megabits per second. Mbps is a technical unit token.',
|
||||
});
|
||||
const SCREEN_SHARE_QUALITY_DESCRIPTOR = msg({
|
||||
message: 'Screen share quality',
|
||||
comment: 'Short label in the video tab. Keep it concise.',
|
||||
@@ -176,6 +195,7 @@ export const VideoTab: React.FC<VideoTabProps> = observer(
|
||||
const screenShareState = resolveUserVideoTabScreenShareState({
|
||||
quality: screenShareQuality,
|
||||
hintSetting: screenShareContentHint,
|
||||
bitrate: voiceSettings.getScreenShareBitrateBudget(),
|
||||
selfHosted: !showPremium,
|
||||
});
|
||||
const screenshareResolutionOptions: ReadonlyArray<ComboboxOption<OfferedScreenShareResolution>> =
|
||||
@@ -189,6 +209,15 @@ export const VideoTab: React.FC<VideoTabProps> = observer(
|
||||
value,
|
||||
label: i18n._(FPS_DESCRIPTOR, {frameRate: value}),
|
||||
}));
|
||||
const bitrateOptions: ReadonlyArray<ComboboxOption<number | null>> = [
|
||||
{value: null, label: i18n._(SCREEN_SHARE_BITRATE_AUTOMATIC_DESCRIPTOR)},
|
||||
...screenShareState.bitrateOptions.map((value) => ({
|
||||
value,
|
||||
label: i18n._(SCREEN_SHARE_BITRATE_MBPS_DESCRIPTOR, {
|
||||
bitrate: i18n.number(value / 1_000_000, {maximumFractionDigits: 1}),
|
||||
}),
|
||||
})),
|
||||
];
|
||||
const handleCameraPreview = async () => {
|
||||
const granted = await requestPermission();
|
||||
if (granted) {
|
||||
@@ -387,6 +416,19 @@ export const VideoTab: React.FC<VideoTabProps> = observer(
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
{hasHigherQuality && (
|
||||
<CompactComboboxRow<number | null>
|
||||
label={i18n._(SCREEN_SHARE_BITRATE_DESCRIPTOR)}
|
||||
description={i18n._(SCREEN_SHARE_BITRATE_DESCRIPTION_DESCRIPTOR)}
|
||||
options={bitrateOptions}
|
||||
value={screenShareState.bitrate}
|
||||
onChange={(value) => VoiceSettingsCommands.update({screenShareBitrate: value})}
|
||||
isSearchable={false}
|
||||
controlWidth="small"
|
||||
dataFlx="user.video-tab.select.screen-share-bitrate-change"
|
||||
data-flx="user.user-video-tab.video-tab.compact-combobox-row.screen-share-bitrate-change"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<div className={styles.actionRow} data-flx="user.video-tab.advanced-video-settings-section">
|
||||
<span className={styles.actionLabel} data-flx="user.video-tab.advanced-video-settings-label">
|
||||
|
||||
@@ -12,6 +12,7 @@ import type {ScreenShareContentHint} from '@app/features/voice/utils/CodecCapabi
|
||||
import {
|
||||
resolveScreenShareFrameRate,
|
||||
resolveScreenShareTarget,
|
||||
type ScreenShareBitrateBudget,
|
||||
type ScreenShareContext,
|
||||
type ScreenShareQualityInput,
|
||||
SUPPORTED_SCREEN_SHARE_FRAME_RATES,
|
||||
@@ -35,10 +36,15 @@ const FREE_SCREEN_SHARE_RESOLUTIONS: ReadonlyArray<OfferedScreenShareResolution>
|
||||
const PREMIUM_SCREEN_SHARE_RESOLUTIONS: ReadonlyArray<OfferedScreenShareResolution> = ['high', 'ultra', 'source'];
|
||||
const FREE_SCREEN_SHARE_FRAME_RATES: ReadonlyArray<SupportedScreenShareFrameRate> = [15, 30];
|
||||
const PREMIUM_SCREEN_SHARE_FRAME_RATES: ReadonlyArray<SupportedScreenShareFrameRate> = [15, 30, 60];
|
||||
const SCREEN_SHARE_BITRATE_STEPS_BPS: ReadonlyArray<number> = [
|
||||
2_000_000, 4_000_000, 6_000_000, 8_000_000, 10_000_000, 15_000_000, 20_000_000, 25_000_000, 30_000_000, 40_000_000,
|
||||
50_000_000,
|
||||
];
|
||||
|
||||
export interface UserVideoTabScreenShareInput {
|
||||
quality: ScreenShareQualityInput;
|
||||
hintSetting: ScreenShareContentHint;
|
||||
bitrate: ScreenShareBitrateBudget;
|
||||
selfHosted: boolean;
|
||||
}
|
||||
|
||||
@@ -52,6 +58,8 @@ export interface UserVideoTabScreenShareState {
|
||||
frameRate: SupportedScreenShareFrameRate;
|
||||
resolutionOptions: ReadonlyArray<UserVideoTabResolutionOption>;
|
||||
frameRateOptions: ReadonlyArray<SupportedScreenShareFrameRate>;
|
||||
bitrate: number | null;
|
||||
bitrateOptions: ReadonlyArray<number>;
|
||||
preset: Exclude<StreamingMode, 'custom'> | null;
|
||||
presetOverriddenByContext: boolean;
|
||||
saved: {resolution: OfferedScreenShareResolution; frameRate: SupportedScreenShareFrameRate} | null;
|
||||
@@ -82,8 +90,20 @@ function buildFrameRateOptions(
|
||||
return SUPPORTED_SCREEN_SHARE_FRAME_RATES.filter((value) => value === effective || offered.includes(value));
|
||||
}
|
||||
|
||||
function buildBitrateOptions(budget: ScreenShareBitrateBudget): ReadonlyArray<number> {
|
||||
const offered = new Set(SCREEN_SHARE_BITRATE_STEPS_BPS.filter((value) => value < budget.ceilingBps));
|
||||
offered.add(budget.ceilingBps);
|
||||
if (budget.chosenBps !== null) offered.add(budget.chosenBps);
|
||||
return [...offered].sort((a, b) => a - b);
|
||||
}
|
||||
|
||||
export function resolveUserVideoTabScreenShareState(input: UserVideoTabScreenShareInput): UserVideoTabScreenShareState {
|
||||
const target = resolveScreenShareTarget({...input.quality, sourceDimensions: null, hintSetting: input.hintSetting});
|
||||
const target = resolveScreenShareTarget({
|
||||
...input.quality,
|
||||
sourceDimensions: null,
|
||||
hintSetting: input.hintSetting,
|
||||
bitrate: input.bitrate,
|
||||
});
|
||||
const resolution = offeredScreenShareResolution(target.resolution);
|
||||
return {
|
||||
resolution,
|
||||
@@ -95,6 +115,8 @@ export function resolveUserVideoTabScreenShareState(input: UserVideoTabScreenSha
|
||||
resolution,
|
||||
),
|
||||
frameRateOptions: buildFrameRateOptions(input.quality.entitled, target.frameRate),
|
||||
bitrate: input.bitrate.chosenBps,
|
||||
bitrateOptions: buildBitrateOptions(input.bitrate),
|
||||
preset: input.quality.mode === 'custom' ? null : input.quality.mode,
|
||||
presetOverriddenByContext: selectStreamSettingsPresetOverriddenByContext(input.quality.mode, input.quality.context),
|
||||
saved: target.tierLimited
|
||||
|
||||
+1
-6
@@ -149,12 +149,8 @@ const SVC_DESCRIPTOR = msg({
|
||||
message: 'SVC',
|
||||
comment: 'Settings search synonym. Used to match this term when the user types it in the settings search bar.',
|
||||
});
|
||||
const BITRATE_DESCRIPTOR = msg({
|
||||
message: 'Bitrate',
|
||||
comment: 'Settings search synonym. Used to match this term when the user types it in the settings search bar.',
|
||||
});
|
||||
const TUNE_LOW_LEVEL_SCREEN_SHARE_ENCODER_BEHAVIOR_FOR_THE_NEXT_STREAM_DESCRIPTOR = msg({
|
||||
message: 'Encoder, SVC, and bitrate presets',
|
||||
message: 'Encoder path, SVC mode, and content hint',
|
||||
comment: 'Settings search entry description. One-line summary of what the settings search entry controls.',
|
||||
});
|
||||
|
||||
@@ -244,7 +240,6 @@ export const voiceVideoIndex: Array<SearchableSettingDescriptor> = [
|
||||
SOFTWARE_ENCODER_DESCRIPTOR,
|
||||
HARDWARE_ENCODER_DESCRIPTOR,
|
||||
SVC_DESCRIPTOR,
|
||||
BITRATE_DESCRIPTOR,
|
||||
PRODUCT_NAME,
|
||||
],
|
||||
description: TUNE_LOW_LEVEL_SCREEN_SHARE_ENCODER_BEHAVIOR_FOR_THE_NEXT_STREAM_DESCRIPTOR,
|
||||
|
||||
+5
@@ -231,6 +231,10 @@ const FRAME_RATE_DESCRIPTOR = msg({
|
||||
message: 'Frame rate',
|
||||
comment: 'Settings search synonym. Used to match this term when the user types it in the settings search bar.',
|
||||
});
|
||||
const BITRATE_DESCRIPTOR = msg({
|
||||
message: 'Bitrate',
|
||||
comment: 'Settings search synonym. Used to match this term when the user types it in the settings search bar.',
|
||||
});
|
||||
const FPS_DESCRIPTOR = msg({
|
||||
message: 'FPS',
|
||||
comment: 'Settings search synonym. Used to match this term when the user types it in the settings search bar.',
|
||||
@@ -342,6 +346,7 @@ export const voiceVideoSections = [
|
||||
STREAMING_DESCRIPTOR,
|
||||
FRAME_RATE_DESCRIPTOR,
|
||||
FPS_DESCRIPTOR,
|
||||
BITRATE_DESCRIPTOR,
|
||||
HD_DESCRIPTOR,
|
||||
MESSAGE_1080P_DESCRIPTOR,
|
||||
MESSAGE_1440P_DESCRIPTOR,
|
||||
|
||||
@@ -60,6 +60,7 @@ type VoiceSettingsPatch = Partial<{
|
||||
screenShareContentHint: ScreenShareContentHint;
|
||||
screenShareEncoderMode: ScreenShareEncoderMode;
|
||||
screenShareScalabilityMode: ScreenShareScalabilityModePreference;
|
||||
screenShareBitrate: number | null;
|
||||
vadThreshold: number;
|
||||
vadAutoSensitivity: boolean;
|
||||
vadEnhanced: boolean;
|
||||
|
||||
@@ -356,6 +356,7 @@ export const StreamSettingsMenuContent = observer(
|
||||
...quality,
|
||||
sourceDimensions: null,
|
||||
hintSetting: VoiceSettings.getScreenShareContentHint(),
|
||||
bitrate: VoiceSettings.getScreenShareBitrateBudget(),
|
||||
});
|
||||
const presetOverriddenByContext = selectStreamSettingsPresetOverriddenByContext(currentMode, shareContext);
|
||||
const captureAudioEnabled = isAppShare
|
||||
|
||||
@@ -1343,6 +1343,7 @@ const ScreenSharePickerModalLoadedContent = observer(
|
||||
context: shareContext,
|
||||
sourceDimensions: null,
|
||||
hintSetting: VoiceSettings.getScreenShareContentHint(),
|
||||
bitrate: VoiceSettings.getScreenShareBitrateBudget(),
|
||||
});
|
||||
const streamSummaryTitle =
|
||||
streamSummary.mode === 'gaming'
|
||||
|
||||
@@ -172,8 +172,11 @@ export function useStatsForNerds({enabled = true}: UseStatsForNerdsOptions = {})
|
||||
scalabilityMode: VoiceSettings.getScreenShareScalabilityMode(),
|
||||
maxBitrateMbps:
|
||||
(getPublishedScreenShareMaxBitrateBps(localParticipant) ??
|
||||
getScreenShareBitrateBps(effectiveScreenShareSettings.resolution, effectiveScreenShareSettings.frameRate)) /
|
||||
1000000,
|
||||
getScreenShareBitrateBps(
|
||||
effectiveScreenShareSettings.resolution,
|
||||
effectiveScreenShareSettings.frameRate,
|
||||
VoiceSettings.getScreenShareBitrateBudget(),
|
||||
)) / 1000000,
|
||||
audioSourceMode: VoiceSettings.getScreenShareAudioSourceMode(),
|
||||
audioIncludeSources: VoiceSettings.getScreenShareAudioIncludeSources(),
|
||||
audioExcludeSources: VoiceSettings.getScreenShareAudioExcludeSources(),
|
||||
|
||||
@@ -468,9 +468,11 @@ export function useVoiceCallTracksAndLayout({channel, expandedUserIds}: UseVoice
|
||||
useEffect(() => {
|
||||
if (!pinnedParticipantIdentity) return;
|
||||
if (cameraTracksAll.length === 0) return;
|
||||
const stillExists = cameraTracksAll.some((tr) => tr.participant.identity === pinnedParticipantIdentity);
|
||||
if (!stillExists) VoiceCallLayoutCommands.setPinnedParticipant(null);
|
||||
}, [cameraTracksAll, pinnedParticipantIdentity]);
|
||||
if (cameraTracksAll.some((tr) => tr.participant.identity === pinnedParticipantIdentity)) return;
|
||||
const {connectionId} = parseVoiceParticipantIdentity(pinnedParticipantIdentity);
|
||||
if (connectionVoiceStates[connectionId]?.channel_id === channel.id) return;
|
||||
VoiceCallLayoutCommands.setPinnedParticipant(null);
|
||||
}, [cameraTracksAll, channel.id, connectionVoiceStates, pinnedParticipantIdentity]);
|
||||
const {
|
||||
mainTrack: focusMainTrack,
|
||||
carouselTracks,
|
||||
|
||||
@@ -801,6 +801,7 @@ class MediaEngineFacade extends Store {
|
||||
restoreStream: boolean;
|
||||
screenShareSnapshot: ScreenShareReconnectSnapshot | null;
|
||||
toastWhenStreamNotRestored: boolean;
|
||||
sendUpdateWhenStreamNotRestored: boolean;
|
||||
}): Promise<void> {
|
||||
assert.equal(typeof args.restoreCamera, 'boolean', 'restoreLocalMedia requires a camera flag');
|
||||
assert.equal(typeof args.restoreStream, 'boolean', 'restoreLocalMedia requires a stream flag');
|
||||
@@ -828,7 +829,9 @@ class MediaEngineFacade extends Store {
|
||||
}
|
||||
if (restored) return;
|
||||
if (streamRestoreFailed || args.screenShareSnapshot !== null) {
|
||||
voiceEngineV2AppMediaStateAdapter.applyScreenShareState(false, {sendUpdate: false});
|
||||
voiceEngineV2AppMediaStateAdapter.applyScreenShareState(false, {
|
||||
sendUpdate: args.sendUpdateWhenStreamNotRestored,
|
||||
});
|
||||
}
|
||||
if (args.toastWhenStreamNotRestored && this.i18n) {
|
||||
ToastCommands.createToast({
|
||||
@@ -1690,7 +1693,7 @@ class MediaEngineFacade extends Store {
|
||||
}
|
||||
voiceEngineV2AppMediaExecutionAdapter.resetMicrophoneFailureLatch();
|
||||
this.reconcileLocalAudioStateInBackground('region hot-swap complete');
|
||||
if (isConversion) void this.reapplyVideoQualityLimits(newRoom);
|
||||
if (isConversion) void this.finishMeshConversion(currentRoom, newRoom);
|
||||
},
|
||||
(_guildId, _channelId, _connectionId, _attemptId, error) => {
|
||||
logger.warn('LiveKit connect failed, clearing gateway voice state', {error});
|
||||
@@ -2715,6 +2718,19 @@ class MediaEngineFacade extends Store {
|
||||
}
|
||||
}
|
||||
|
||||
private async finishMeshConversion(meshRoom: Room, room: Room): Promise<void> {
|
||||
await this.restoreLocalMedia({
|
||||
reason: 'mesh conversion',
|
||||
room,
|
||||
restoreCamera: false,
|
||||
restoreStream: false,
|
||||
screenShareSnapshot: voiceEngineV2AppScreenShareExecutionAdapter.prepareScreenShareReconnect(meshRoom),
|
||||
toastWhenStreamNotRestored: true,
|
||||
sendUpdateWhenStreamNotRestored: true,
|
||||
});
|
||||
await this.reapplyVideoQualityLimits(room);
|
||||
}
|
||||
|
||||
private async restoreLocalMediaState(roomOverride?: Room | null): Promise<void> {
|
||||
const room = roomOverride ?? voiceEngineV2AppConnectionHostAdapter.room;
|
||||
const participant = room?.localParticipant ?? null;
|
||||
@@ -2728,6 +2744,7 @@ class MediaEngineFacade extends Store {
|
||||
restoreStream: LocalVoiceState.getSelfStream() && !participant.isScreenShareEnabled,
|
||||
screenShareSnapshot: pendingScreenShareReconnect,
|
||||
toastWhenStreamNotRestored: false,
|
||||
sendUpdateWhenStreamNotRestored: false,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2744,6 +2761,7 @@ class MediaEngineFacade extends Store {
|
||||
restoreStream: pendingRestore.restoreStream,
|
||||
screenShareSnapshot: null,
|
||||
toastWhenStreamNotRestored: true,
|
||||
sendUpdateWhenStreamNotRestored: false,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -284,6 +284,20 @@ export function bindRoomEvents(
|
||||
participantSpeakingDisposers.get(identity)?.dispose();
|
||||
participantSpeakingDisposers.delete(identity);
|
||||
};
|
||||
const observeRemoteScreenSharePublication = (participant: Participant, pub: RemoteTrackPublication): void => {
|
||||
reportScreenSharePublicationObserved(participant.identity, pub.trackSid ?? null);
|
||||
const streamKey = getStreamKeyForParticipantIdentity(guildId, channelId, participant.identity);
|
||||
if (streamKey) {
|
||||
cancelDeferredStopWatchingStreamKey(streamKey);
|
||||
}
|
||||
};
|
||||
const observeExistingRemoteScreenSharePublications = (): void => {
|
||||
room.remoteParticipants.forEach((participant) => {
|
||||
for (const pub of participant.trackPublications.values()) {
|
||||
if (pub.source === Track.Source.ScreenShare) observeRemoteScreenSharePublication(participant, pub);
|
||||
}
|
||||
});
|
||||
};
|
||||
const endScreenShareIfPublicationDidNotReturn = (): void => {
|
||||
const publication = screenSharePublicationAwaitingReconnect;
|
||||
screenSharePublicationAwaitingReconnect = null;
|
||||
@@ -305,6 +319,7 @@ export function bindRoomEvents(
|
||||
bindParticipantSpeakingEvents(room.localParticipant);
|
||||
room.remoteParticipants.forEach((participant) => bindParticipantSpeakingEvents(participant));
|
||||
dependencies.remoteSpeaking.hydrateFromRoom(room);
|
||||
observeExistingRemoteScreenSharePublications();
|
||||
bindScreenShareNegotiation();
|
||||
dependencies.permissions.applyDeafen(room, getEffectiveAudioState().effectiveDeaf);
|
||||
dependencies.connection.markConnected();
|
||||
@@ -596,11 +611,7 @@ export function bindRoomEvents(
|
||||
pub.setSubscribed(true);
|
||||
}
|
||||
if (pub.source === Track.Source.ScreenShare && !participant.isLocal) {
|
||||
reportScreenSharePublicationObserved(participant.identity, pub.trackSid ?? null);
|
||||
const streamKey = getStreamKeyForParticipantIdentity(guildId, channelId, participant.identity);
|
||||
if (streamKey) {
|
||||
cancelDeferredStopWatchingStreamKey(streamKey);
|
||||
}
|
||||
observeRemoteScreenSharePublication(participant, pub);
|
||||
dependencies.subscriptions.reattachScreenShareAfterPublish(participant.identity, pub);
|
||||
dependencies.subscriptions.reconcileSubscriptions();
|
||||
}
|
||||
@@ -615,6 +626,7 @@ export function bindRoomEvents(
|
||||
}),
|
||||
);
|
||||
if (room.state === ConnectionState.Connected) {
|
||||
guard(attemptId, observeExistingRemoteScreenSharePublications)();
|
||||
guard(attemptId, bindScreenShareNegotiation)();
|
||||
}
|
||||
}
|
||||
@@ -320,6 +320,7 @@ export class VoiceMeshEngine extends RTCEngine {
|
||||
handlePeerStatus(peer: VoiceMeshPeer): void {
|
||||
if (this.peers.get(peer.connectionId) !== peer) return;
|
||||
const {status} = peer;
|
||||
if (status === 'failed' && this.ownP2p() === false) return;
|
||||
VoiceMeshPeers.setStatus(peer.connectionId, status);
|
||||
if (status === 'connecting') return;
|
||||
this.reportPeer(peer, status);
|
||||
@@ -395,28 +396,30 @@ export class VoiceMeshEngine extends RTCEngine {
|
||||
const serverMuted =
|
||||
src === 'microphone' &&
|
||||
voiceEngineV2AppVoiceStateAdapter.getVoiceStateByConnectionId(peer.connectionId)?.mute === true;
|
||||
if (receiver && receiver.track.readyState === 'live' && publication.isDesired && !serverMuted) {
|
||||
if (publication.track?.mediaStreamTrack !== receiver.track) {
|
||||
participant.addSubscribedMediaTrack(receiver.track, info.sid, new MediaStream([receiver.track]), receiver);
|
||||
}
|
||||
return;
|
||||
const live = receiver !== null && receiver.track.readyState === 'live' && publication.isDesired && !serverMuted;
|
||||
if (live && publication.track?.mediaStreamTrack === receiver.track) return;
|
||||
if (publication.track) {
|
||||
publication.track.stop();
|
||||
publication.setTrack(undefined);
|
||||
}
|
||||
if (live) {
|
||||
participant.addSubscribedMediaTrack(receiver.track, info.sid, new MediaStream([receiver.track]), receiver);
|
||||
}
|
||||
if (!publication.track) return;
|
||||
publication.track.stop();
|
||||
publication.setTrack(undefined);
|
||||
}
|
||||
|
||||
private readonly syncRoster = (): void => {
|
||||
if (!this.room) return;
|
||||
const {connectionId, channelId, guildId} = this.target;
|
||||
const own = voiceEngineV2AppVoiceStateAdapter.getVoiceStateByConnectionId(connectionId);
|
||||
const ownP2p = own?.channel_id === channelId ? own.p2p : undefined;
|
||||
const ownP2p = this.ownP2p();
|
||||
this.syncConversionWatchdog(ownP2p === false && !this.conversionHeld);
|
||||
const roster = new Map<string, NormalizedVoiceState>();
|
||||
if (ownP2p === true) {
|
||||
if (ownP2p !== undefined) {
|
||||
const states = voiceEngineV2AppVoiceStateAdapter.getAllVoiceStatesInChannel(guildId ?? ME, channelId);
|
||||
for (const state of Object.values(states)) {
|
||||
if (state.p2p === true && state.connection_id !== connectionId) roster.set(state.connection_id, state);
|
||||
if (state.connection_id === connectionId) continue;
|
||||
if (this.peers.has(state.connection_id) || (ownP2p && state.p2p === true)) {
|
||||
roster.set(state.connection_id, state);
|
||||
}
|
||||
}
|
||||
}
|
||||
const before = this.peers.size;
|
||||
@@ -431,6 +434,12 @@ export class VoiceMeshEngine extends RTCEngine {
|
||||
for (const peer of this.peers.values()) this.syncPeerReceiver(peer, 'microphone');
|
||||
};
|
||||
|
||||
private ownP2p(): boolean | undefined {
|
||||
const {connectionId, channelId} = this.target;
|
||||
const own = voiceEngineV2AppVoiceStateAdapter.getVoiceStateByConnectionId(connectionId);
|
||||
return own?.channel_id === channelId ? own.p2p : undefined;
|
||||
}
|
||||
|
||||
private addPeer(state: NormalizedVoiceState): void {
|
||||
const peer = new VoiceMeshPeer(this, state.connection_id, state.user_id, this.target.connectionId);
|
||||
this.peers.set(peer.connectionId, peer);
|
||||
|
||||
@@ -3,7 +3,11 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import Authentication from '@app/features/auth/state/Authentication';
|
||||
import {Logger} from '@app/features/platform/utils/AppLogger';
|
||||
import {createVoiceMeshRoom, holdVoiceMeshConversion} from '@app/features/voice/engine/mesh/VoiceMeshRoom';
|
||||
import {
|
||||
createVoiceMeshRoom,
|
||||
holdVoiceMeshConversion,
|
||||
isVoiceMeshRoom,
|
||||
} from '@app/features/voice/engine/mesh/VoiceMeshRoom';
|
||||
import {Store} from '@app/features/voice/engine/Store';
|
||||
import {sendVoiceStateDisconnect} from '@app/features/voice/engine/VoiceChannelConnector';
|
||||
import {
|
||||
@@ -41,12 +45,12 @@ import {
|
||||
getRoomVideoPublishDefaults,
|
||||
} from '@app/features/voice/utils/CodecCapabilityDetector';
|
||||
import {getH264HardwareProfilesSync} from '@app/features/voice/utils/GpuEncoderCapabilities';
|
||||
import {SCREEN_SHARE_MAX_VIDEO_BITRATE_BPS} from '@app/features/voice/utils/ScreenShareOptions';
|
||||
import {
|
||||
clearScreenShareDecodeFailures,
|
||||
getVideoDecoderExclusionsSync,
|
||||
loadVideoDecoderExclusions,
|
||||
} from '@app/features/voice/utils/VideoDecoderCapabilities';
|
||||
import {getScreenShareBitrateCeilingBps} from '@app/features/voice/utils/VideoQualityEntitlement';
|
||||
import type {
|
||||
ExternalE2EEKeyProvider,
|
||||
LocalTrack,
|
||||
@@ -145,7 +149,7 @@ function createWebAudioMixOption(): RoomOptions['webAudioMix'] {
|
||||
function createRoomPublishDefaults(): RoomOptions['publishDefaults'] {
|
||||
return {
|
||||
screenShareEncoding: {
|
||||
maxBitrate: SCREEN_SHARE_MAX_VIDEO_BITRATE_BPS,
|
||||
maxBitrate: getScreenShareBitrateCeilingBps(),
|
||||
maxFramerate: 30,
|
||||
priority: 'high',
|
||||
},
|
||||
@@ -785,8 +789,13 @@ export class VoiceEngineV2AppConnectionHostAdapter extends Store {
|
||||
logger.warn('Region hot-swap: missing participant for track republishing');
|
||||
return;
|
||||
}
|
||||
const isMeshConversion = isVoiceMeshRoom(oldRoom);
|
||||
const publications = selectLocalMediaPublicationsForConnectionRepublish(
|
||||
Array.from(oldParticipant.trackPublications.values()),
|
||||
).filter(
|
||||
(publication) =>
|
||||
!isMeshConversion ||
|
||||
(publication.source !== Track.Source.ScreenShare && publication.source !== Track.Source.ScreenShareAudio),
|
||||
);
|
||||
const errors: Array<{source: string; error: unknown}> = [];
|
||||
let codecPolicyFailure: Error | null = null;
|
||||
|
||||
@@ -244,7 +244,10 @@ vi.mock('@app/features/user/components/modals/tabs/components/CompactComboboxRow
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock('@app/features/voice/utils/VideoQualityEntitlement', () => ({hasHigherVideoQuality: () => menuEntitled}));
|
||||
vi.mock('@app/features/voice/utils/VideoQualityEntitlement', () => ({
|
||||
hasHigherVideoQuality: () => menuEntitled,
|
||||
getScreenShareBitrateCeilingBps: () => 9_000_000,
|
||||
}));
|
||||
|
||||
vi.mock('@app/features/voice/engine/ScreenShareCodecNegotiation', () => ({
|
||||
default: {
|
||||
@@ -726,7 +729,12 @@ describe('the video settings tab', () => {
|
||||
{value: 'source', isDisabled: true},
|
||||
];
|
||||
const stateOf = (quality: Parameters<typeof resolveScreenShareQualityPick>[0], selfHosted = false) =>
|
||||
resolveUserVideoTabScreenShareState({quality, hintSetting: 'auto', selfHosted});
|
||||
resolveUserVideoTabScreenShareState({
|
||||
quality,
|
||||
hintSetting: 'auto',
|
||||
bitrate: {ceilingBps: 9_000_000, chosenBps: null},
|
||||
selfHosted,
|
||||
});
|
||||
|
||||
it('shows a free account the clamped values, the saved ones and no preset note', () => {
|
||||
const quality = {
|
||||
@@ -741,6 +749,8 @@ describe('the video settings tab', () => {
|
||||
frameRate: 30,
|
||||
resolutionOptions: FREE_RESOLUTION_OPTIONS,
|
||||
frameRateOptions: [15, 30],
|
||||
bitrate: null,
|
||||
bitrateOptions: [2_000_000, 4_000_000, 6_000_000, 8_000_000, 9_000_000],
|
||||
preset: null,
|
||||
presetOverriddenByContext: false,
|
||||
saved: {resolution: 'source', frameRate: 30},
|
||||
|
||||
@@ -23,7 +23,6 @@ import {
|
||||
resolveScreenShareLayering,
|
||||
resolveScreenShareSenderCodec,
|
||||
resolveScreenShareTarget,
|
||||
SCREEN_SHARE_MAX_VIDEO_BITRATE_BPS,
|
||||
type ScreenShareContext,
|
||||
type ScreenShareLayering,
|
||||
type ScreenShareLimitClass,
|
||||
@@ -195,13 +194,11 @@ export async function releaseScreenShareCaptureCleanup(snapshot: ScreenShareCapt
|
||||
}
|
||||
}
|
||||
|
||||
function clampScreenShareEncoding(encoding: VideoEncoding): VideoEncoding {
|
||||
function clampScreenShareEncoding(encoding: VideoEncoding, ceilingBps: number): VideoEncoding {
|
||||
return {
|
||||
...encoding,
|
||||
maxBitrate:
|
||||
typeof encoding.maxBitrate === 'number'
|
||||
? Math.min(encoding.maxBitrate, SCREEN_SHARE_MAX_VIDEO_BITRATE_BPS)
|
||||
: encoding.maxBitrate,
|
||||
typeof encoding.maxBitrate === 'number' ? Math.min(encoding.maxBitrate, ceilingBps) : encoding.maxBitrate,
|
||||
priority: encoding.priority ?? 'high',
|
||||
};
|
||||
}
|
||||
@@ -222,6 +219,7 @@ export function resolveConfiguredScreenShareTarget(
|
||||
context,
|
||||
sourceDimensions,
|
||||
hintSetting: VoiceSettings.getScreenShareContentHint(),
|
||||
bitrate: VoiceSettings.getScreenShareBitrateBudget(),
|
||||
codec: getPreferredScreenShareCodec(),
|
||||
softwareEncoderClamp: ActiveScreenShareSource.isSoftwareEncoderClamped(),
|
||||
});
|
||||
@@ -261,7 +259,7 @@ function getStatsKind(
|
||||
|
||||
function resolveScreenShareEncoding(target: ScreenShareTarget, publishOptions?: TrackPublishOptions): VideoEncoding {
|
||||
if (publishOptions?.screenShareEncoding) {
|
||||
return clampScreenShareEncoding(publishOptions.screenShareEncoding);
|
||||
return clampScreenShareEncoding(publishOptions.screenShareEncoding, target.bitrate.ceilingBps);
|
||||
}
|
||||
return {maxBitrate: target.maxBitrate, maxFramerate: target.frameRate, priority: 'high'};
|
||||
}
|
||||
|
||||
@@ -14,7 +14,11 @@ import {
|
||||
isVoiceNoiseSuppressionBackend,
|
||||
type VoiceNoiseSuppressionBackend,
|
||||
} from '@app/features/voice/utils/noise_suppression/NoiseSuppressionBackends';
|
||||
import {hasHigherVideoQuality} from '@app/features/voice/utils/VideoQualityEntitlement';
|
||||
import type {ScreenShareBitrateBudget} from '@app/features/voice/utils/ScreenShareOptions';
|
||||
import {
|
||||
getScreenShareBitrateCeilingBps,
|
||||
hasHigherVideoQuality,
|
||||
} from '@app/features/voice/utils/VideoQualityEntitlement';
|
||||
import {areVoiceBackgroundsAvailable} from '@app/features/voice/utils/VoiceBackgroundAvailability';
|
||||
import {
|
||||
DEFAULT_VOICE_PROCESSING_MODE,
|
||||
@@ -104,6 +108,7 @@ type VoiceSettingsUpdate = Partial<{
|
||||
screenShareContentHint: ScreenShareContentHint;
|
||||
screenShareEncoderMode: ScreenShareEncoderMode;
|
||||
screenShareScalabilityMode: ScreenShareScalabilityModePreference;
|
||||
screenShareBitrate: number | null;
|
||||
vadThreshold: number;
|
||||
vadAutoSensitivity: boolean;
|
||||
vadEnhanced: boolean;
|
||||
@@ -478,6 +483,7 @@ class VoiceSettings {
|
||||
screenShareSoftwareQualityRetiredV1 = false;
|
||||
screenShareEncoderModePrefV2: ScreenShareEncoderMode = DEFAULT_SCREEN_SHARE_ENCODER_MODE;
|
||||
screenShareScalabilityModePrefV2: ScreenShareScalabilityModePreference = DEFAULT_SCREEN_SHARE_SCALABILITY_MODE;
|
||||
screenShareBitrate: number | null = null;
|
||||
vadThreshold = 50;
|
||||
vadAutoSensitivity = true;
|
||||
vadEnhanced = true;
|
||||
@@ -533,6 +539,8 @@ class VoiceSettings {
|
||||
getScreenShareEncoderMode: false,
|
||||
getScreenShareScalabilityMode: false,
|
||||
getScreenShareScalabilityModeOverride: false,
|
||||
getScreenShareBitrate: false,
|
||||
getScreenShareBitrateBudget: false,
|
||||
getVadThreshold: false,
|
||||
getVadAutoSensitivity: false,
|
||||
getVadEnhanced: false,
|
||||
@@ -651,6 +659,7 @@ class VoiceSettings {
|
||||
'screenShareSoftwareQualityRetiredV1',
|
||||
'screenShareEncoderModePrefV2',
|
||||
'screenShareScalabilityModePrefV2',
|
||||
'screenShareBitrate',
|
||||
'vadThreshold',
|
||||
'vadAutoSensitivity',
|
||||
'vadEnhanced',
|
||||
@@ -896,6 +905,19 @@ class VoiceSettings {
|
||||
return mode === 'auto' ? undefined : mode;
|
||||
}
|
||||
|
||||
getScreenShareBitrate(): number | null {
|
||||
return validateScreenShareBitrate(this.screenShareBitrate);
|
||||
}
|
||||
|
||||
getScreenShareBitrateBudget(): ScreenShareBitrateBudget {
|
||||
const ceilingBps = getScreenShareBitrateCeilingBps();
|
||||
const chosen = this.getScreenShareBitrate();
|
||||
return {
|
||||
ceilingBps,
|
||||
chosenBps: chosen !== null && hasHigherVideoQuality() ? Math.min(chosen, ceilingBps) : null,
|
||||
};
|
||||
}
|
||||
|
||||
getVadThreshold(): number {
|
||||
return this.vadThreshold;
|
||||
}
|
||||
@@ -1031,6 +1053,7 @@ class VoiceSettings {
|
||||
if (validated.screenShareEncoderMode !== undefined) this.screenShareEncoderMode = validated.screenShareEncoderMode;
|
||||
if (validated.screenShareScalabilityMode !== undefined)
|
||||
this.screenShareScalabilityMode = validated.screenShareScalabilityMode;
|
||||
if (validated.screenShareBitrate !== undefined) this.screenShareBitrate = validated.screenShareBitrate;
|
||||
if (validated.vadThreshold !== undefined) this.vadThreshold = validated.vadThreshold;
|
||||
if (validated.vadAutoSensitivity !== undefined) this.vadAutoSensitivity = validated.vadAutoSensitivity;
|
||||
if (validated.vadEnhanced !== undefined) this.vadEnhanced = validated.vadEnhanced;
|
||||
@@ -1160,6 +1183,10 @@ class VoiceSettings {
|
||||
),
|
||||
screenShareEncoderMode,
|
||||
screenShareScalabilityMode,
|
||||
screenShareBitrate:
|
||||
data.screenShareBitrate === undefined
|
||||
? this.screenShareBitrate
|
||||
: validateScreenShareBitrate(data.screenShareBitrate),
|
||||
vadThreshold: Math.max(0, Math.min(100, data.vadThreshold ?? this.vadThreshold)),
|
||||
vadAutoSensitivity: data.vadAutoSensitivity ?? this.vadAutoSensitivity,
|
||||
vadEnhanced: data.vadEnhanced ?? this.vadEnhanced,
|
||||
@@ -1225,6 +1252,10 @@ function validateScreenShareScalabilityMode(mode: unknown): ScreenShareScalabili
|
||||
: DEFAULT_SCREEN_SHARE_SCALABILITY_MODE;
|
||||
}
|
||||
|
||||
function validateScreenShareBitrate(value: unknown): number | null {
|
||||
return typeof value === 'number' && Number.isFinite(value) && value > 0 ? Math.round(value) : null;
|
||||
}
|
||||
|
||||
function validateScreenShareContentHint(hint: unknown): ScreenShareContentHint {
|
||||
return hint === 'detail' || hint === 'motion' || hint === 'text' || hint === 'auto'
|
||||
? hint
|
||||
|
||||
@@ -38,6 +38,7 @@ function targetOf(overrides: {mode?: 'gaming' | 'screenshare' | 'custom'; softwa
|
||||
context: 'display',
|
||||
sourceDimensions: null,
|
||||
hintSetting: 'auto',
|
||||
bitrate: {ceilingBps: 9_000_000, chosenBps: null},
|
||||
...(overrides.softwareEncoderClamp === undefined ? {} : {softwareEncoderClamp: overrides.softwareEncoderClamp}),
|
||||
});
|
||||
}
|
||||
@@ -62,6 +63,7 @@ describe('display capture constraints', () => {
|
||||
const {captureOptions} = buildScreenShareOptions({
|
||||
resolution: 'high',
|
||||
frameRate: 60,
|
||||
maxBitrate: 6_000_000,
|
||||
context: 'display',
|
||||
includeAudio: true,
|
||||
contentHint: 'text',
|
||||
|
||||
@@ -6,6 +6,7 @@ import type {
|
||||
ScreenShareScalabilityModePreference,
|
||||
} from '@app/features/voice/utils/CodecCapabilityDetector';
|
||||
import {getH264HardwareProfilesSync} from '@app/features/voice/utils/GpuEncoderCapabilities';
|
||||
import {MAX_SCREEN_SHARE_BITRATE} from '@fluxer/constants/src/LimitConstants';
|
||||
import type {ScreenShareCaptureOptions, TrackPublishOptions, VideoCodec} from 'livekit-client';
|
||||
|
||||
const DIMENSIONS: Record<
|
||||
@@ -22,11 +23,15 @@ const DIMENSIONS: Record<
|
||||
ultra: {width: 2560, height: 1440},
|
||||
source: {width: 3840, height: 2160},
|
||||
};
|
||||
export const SCREEN_SHARE_MAX_VIDEO_BITRATE_BPS = 9_000_000;
|
||||
export const SUPPORTED_SCREEN_SHARE_FRAME_RATES = [15, 30, 60, 90, 120] as const;
|
||||
|
||||
export type SupportedScreenShareFrameRate = (typeof SUPPORTED_SCREEN_SHARE_FRAME_RATES)[number];
|
||||
|
||||
export interface ScreenShareBitrateBudget {
|
||||
ceilingBps: number;
|
||||
chosenBps: number | null;
|
||||
}
|
||||
|
||||
const SCREEN_SHARE_BITS_PER_PIXEL_PER_FRAME = 0.02;
|
||||
const SCREEN_SHARE_MIN_MAINTAIN_FRAMERATE_BITRATE_BPS = 500_000;
|
||||
const SOFTWARE_H264_MAX_RESOLUTION: ScreenshareResolution = 'medium';
|
||||
@@ -73,22 +78,22 @@ function computeScreenShareBitrateBps(
|
||||
pixels: number,
|
||||
rung: ScreenshareResolution,
|
||||
frameRate: SupportedScreenShareFrameRate,
|
||||
budget: ScreenShareBitrateBudget,
|
||||
): number {
|
||||
const rungFloor = BITRATE_KBPS[rung][frameRate] * 1000;
|
||||
const computed = Math.round(SCREEN_SHARE_BITS_PER_PIXEL_PER_FRAME * pixels * frameRate);
|
||||
return Math.min(SCREEN_SHARE_MAX_VIDEO_BITRATE_BPS, Math.max(rungFloor, computed));
|
||||
if (budget.chosenBps !== null) return Math.min(budget.chosenBps, budget.ceilingBps);
|
||||
const scale = Math.max(1, budget.ceilingBps / MAX_SCREEN_SHARE_BITRATE);
|
||||
const rungFloor = BITRATE_KBPS[rung][frameRate] * 1000 * scale;
|
||||
const computed = SCREEN_SHARE_BITS_PER_PIXEL_PER_FRAME * pixels * frameRate * scale;
|
||||
return Math.min(budget.ceilingBps, Math.round(Math.max(rungFloor, computed)));
|
||||
}
|
||||
|
||||
export function getScreenShareBitrateBps(
|
||||
resolution: ScreenshareResolution,
|
||||
frameRate: SupportedScreenShareFrameRate,
|
||||
sourceDimensions?: {
|
||||
width: number;
|
||||
height: number;
|
||||
} | null,
|
||||
budget: ScreenShareBitrateBudget,
|
||||
): number {
|
||||
const fit = resolveEffectiveScreenShareDimensions(resolution, sourceDimensions);
|
||||
return computeScreenShareBitrateBps(fit.width * fit.height, fit.rung, frameRate);
|
||||
const fit = resolveEffectiveScreenShareDimensions(resolution);
|
||||
return computeScreenShareBitrateBps(fit.width * fit.height, fit.rung, frameRate, budget);
|
||||
}
|
||||
|
||||
const STREAMING_MODE_PRESETS: Record<
|
||||
@@ -120,6 +125,7 @@ export interface BuiltScreenShareOptions {
|
||||
export interface ScreenShareBuildConfig {
|
||||
resolution: ScreenshareResolution;
|
||||
frameRate: number;
|
||||
maxBitrate: number;
|
||||
context: ScreenShareContext;
|
||||
includeAudio: boolean;
|
||||
contentHint?: ScreenShareCaptureOptions['contentHint'];
|
||||
@@ -181,7 +187,6 @@ export function resolveEffectiveScreenShareDimensions(
|
||||
export function buildScreenShareOptions(config: ScreenShareBuildConfig): BuiltScreenShareOptions {
|
||||
const {width, height, rung} = resolveEffectiveScreenShareDimensions(config.resolution, config.sourceDimensions);
|
||||
const resolvedFrameRate = resolveScreenShareFrameRate(config.frameRate);
|
||||
const maxBitrate = computeScreenShareBitrateBps(width * height, rung, resolvedFrameRate);
|
||||
const video: ScreenShareVideoOptions = {
|
||||
cursor: resolveScreenShareCursorCapture(config.preferredDisplaySurface),
|
||||
...(config.preferredDisplaySurface ? {displaySurface: config.preferredDisplaySurface} : {}),
|
||||
@@ -203,10 +208,10 @@ export function buildScreenShareOptions(config: ScreenShareBuildConfig): BuiltSc
|
||||
context: config.context,
|
||||
rung,
|
||||
contentHint: config.contentHint,
|
||||
maxBitrate,
|
||||
maxBitrate: config.maxBitrate,
|
||||
degradationPreference: config.degradationPreference,
|
||||
}),
|
||||
screenShareEncoding: {maxBitrate, maxFramerate: resolvedFrameRate, priority: 'high'},
|
||||
screenShareEncoding: {maxBitrate: config.maxBitrate, maxFramerate: resolvedFrameRate, priority: 'high'},
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -289,6 +294,7 @@ export interface ScreenShareQualityInput {
|
||||
|
||||
export interface ScreenShareTargetInput extends ScreenShareQualityInput {
|
||||
sourceDimensions: {width: number; height: number} | null;
|
||||
bitrate: ScreenShareBitrateBudget;
|
||||
hintSetting: ScreenShareContentHint;
|
||||
codec?: VideoCodec;
|
||||
softwareEncoderClamp?: boolean;
|
||||
@@ -303,6 +309,7 @@ export interface ScreenShareTarget {
|
||||
height: number;
|
||||
rung: ScreenshareResolution;
|
||||
maxBitrate: number;
|
||||
bitrate: ScreenShareBitrateBudget;
|
||||
contentHint: ScreenShareCaptureOptions['contentHint'];
|
||||
degradationPreference: NonNullable<TrackPublishOptions['degradationPreference']>;
|
||||
softwareEncoderClamped: boolean;
|
||||
@@ -392,7 +399,7 @@ export function resolveScreenShareTarget(input: ScreenShareTargetInput): ScreenS
|
||||
const configuredOnDisplay = resolveEffectiveScreenShareQuality({...input, context: 'display'});
|
||||
const onDisplay = clamped ? clampToSoftwareH264Budget(configuredOnDisplay) : configuredOnDisplay;
|
||||
const fit = resolveEffectiveScreenShareDimensions(effective.resolution, input.sourceDimensions);
|
||||
const maxBitrate = computeScreenShareBitrateBps(fit.width * fit.height, fit.rung, effective.frameRate);
|
||||
const maxBitrate = computeScreenShareBitrateBps(fit.width * fit.height, fit.rung, effective.frameRate, input.bitrate);
|
||||
const contentHint = resolveScreenShareContentHint(effective.mode, input.hintSetting, input.context);
|
||||
return {
|
||||
mode: effective.mode,
|
||||
@@ -403,6 +410,7 @@ export function resolveScreenShareTarget(input: ScreenShareTargetInput): ScreenS
|
||||
height: fit.height,
|
||||
rung: fit.rung,
|
||||
maxBitrate,
|
||||
bitrate: input.bitrate,
|
||||
contentHint,
|
||||
degradationPreference: resolveScreenShareDegradationPreference({
|
||||
context: input.context,
|
||||
@@ -538,7 +546,12 @@ export function buildScreenShareSenderParameters(input: ScreenShareSenderParamet
|
||||
sentPixels !== null && sentPixels < targetPixels * SENT_PIXEL_FILL_RATIO
|
||||
? Math.min(
|
||||
input.target.maxBitrate,
|
||||
computeScreenShareBitrateBps(sentPixels, resolveBitrateRungForPixels(sentPixels), input.target.frameRate),
|
||||
computeScreenShareBitrateBps(
|
||||
sentPixels,
|
||||
resolveBitrateRungForPixels(sentPixels),
|
||||
input.target.frameRate,
|
||||
input.target.bitrate,
|
||||
),
|
||||
)
|
||||
: input.target.maxBitrate;
|
||||
const bitrates = distributeScreenShareBitrate(input.encodings, maxBitrate);
|
||||
|
||||
@@ -331,6 +331,7 @@ export function buildConfiguredScreenShareOptions(input: ScreenShareOptionsBuild
|
||||
const {captureOptions, publishOptions} = buildScreenShareOptions({
|
||||
resolution: input.target.resolution,
|
||||
frameRate: input.target.frameRate,
|
||||
maxBitrate: input.target.maxBitrate,
|
||||
context: input.target.context,
|
||||
includeAudio: input.includeAudio,
|
||||
contentHint: input.target.contentHint,
|
||||
|
||||
@@ -300,7 +300,11 @@ async function collectVoiceSettingsMetadata(): Promise<Record<string, unknown>>
|
||||
screenShareEncoderMode: VoiceSettings.getScreenShareEncoderMode(),
|
||||
screenShareScalabilityMode: VoiceSettings.getScreenShareScalabilityMode(),
|
||||
screenShareMaxBitrateMbps:
|
||||
getScreenShareBitrateBps(configuredScreenShare.resolution, configuredScreenShare.frameRate) / 1000000,
|
||||
getScreenShareBitrateBps(
|
||||
configuredScreenShare.resolution,
|
||||
configuredScreenShare.frameRate,
|
||||
VoiceSettings.getScreenShareBitrateBudget(),
|
||||
) / 1000000,
|
||||
linuxAudioCapture: {
|
||||
workaround: VoiceSettings.getLinuxAudioCaptureWorkaround(),
|
||||
onlySpeakers: VoiceSettings.getLinuxAudioCaptureOnlySpeakers(),
|
||||
@@ -505,8 +509,11 @@ export function collectStatsForNerdsSnapshot(): StatsForNerdsData {
|
||||
scalabilityMode: VoiceSettings.getScreenShareScalabilityMode(),
|
||||
maxBitrateMbps:
|
||||
(getPublishedScreenShareMaxBitrateBps(localParticipant) ??
|
||||
getScreenShareBitrateBps(effectiveScreenShareSettings.resolution, effectiveScreenShareSettings.frameRate)) /
|
||||
1000000,
|
||||
getScreenShareBitrateBps(
|
||||
effectiveScreenShareSettings.resolution,
|
||||
effectiveScreenShareSettings.frameRate,
|
||||
VoiceSettings.getScreenShareBitrateBudget(),
|
||||
)) / 1000000,
|
||||
audioSourceMode: VoiceSettings.getScreenShareAudioSourceMode(),
|
||||
audioIncludeSources: VoiceSettings.getScreenShareAudioIncludeSources(),
|
||||
audioExcludeSources: VoiceSettings.getScreenShareAudioExcludeSources(),
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import {LimitResolver} from '@app/features/app/utils/LimitResolverAdapter';
|
||||
import {isLimitToggleEnabled} from '@app/features/app/utils/LimitUtils';
|
||||
import {isActiveVoiceChannelP2p} from '@app/features/voice/state/ChannelP2pStatus';
|
||||
import {MAX_SCREEN_SHARE_BITRATE} from '@fluxer/constants/src/LimitConstants';
|
||||
|
||||
export function hasHigherVideoQuality(): boolean {
|
||||
return (
|
||||
@@ -18,3 +19,7 @@ export function hasHigherVideoQuality(): boolean {
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
export function getScreenShareBitrateCeilingBps(): number {
|
||||
return LimitResolver.resolve({key: 'max_screen_share_bitrate', fallback: MAX_SCREEN_SHARE_BITRATE});
|
||||
}
|
||||
@@ -385,6 +385,7 @@ Each key names one limit. A key whose name begins with `feature_` is a feature g
|
||||
| max_private_channels_per_user | Maximum direct message channels per user, in user scope |
|
||||
| max_reactions_per_message | Maximum distinct reactions per message, in guild scope |
|
||||
| max_relationships | Maximum friend and blocked relationships, in user scope |
|
||||
| max_screen_share_bitrate | Highest screen share video bitrate in bits per second, from 1000000 to 50000000, in user scope |
|
||||
| max_users_per_message_reaction | Maximum users who can use the same reaction on a message, in guild scope |
|
||||
| max_voice_message_duration | Maximum voice message duration in seconds, in user and guild scope |
|
||||
| max_webhooks_per_channel | Maximum webhooks per channel, in guild scope |
|
||||
|
||||
@@ -175,7 +175,7 @@ impl CacheTelemetry {
|
||||
|
||||
fn next_generation(&self) -> u64 {
|
||||
self.next_generation
|
||||
.fetch_update(METRICS_ORDERING, METRICS_ORDERING, |generation| {
|
||||
.try_update(METRICS_ORDERING, METRICS_ORDERING, |generation| {
|
||||
generation.checked_add(1)
|
||||
})
|
||||
.expect("GIF cache generation exhausted")
|
||||
|
||||
@@ -43,7 +43,7 @@ impl ByteBudgetInner {
|
||||
assert!(amount <= self.limit);
|
||||
let released = self
|
||||
.used
|
||||
.fetch_update(Ordering::AcqRel, Ordering::Acquire, |used| {
|
||||
.try_update(Ordering::AcqRel, Ordering::Acquire, |used| {
|
||||
used.checked_sub(amount)
|
||||
});
|
||||
assert!(released.is_ok());
|
||||
|
||||
@@ -171,11 +171,13 @@ fn gif_animation_status(input: &[u8]) -> NativeStatus {
|
||||
})
|
||||
}
|
||||
|
||||
fn probe_animated_status(input: &[u8]) -> (NativeStatus, c_int, c_int, c_int) {
|
||||
fn probe_animated_status(input: &[u8]) -> (NativeStatus, c_int, c_int, c_int, c_int) {
|
||||
ensure_vips_init().expect("libvips initialises");
|
||||
let mut width = c_int::MAX;
|
||||
let mut height = c_int::MAX;
|
||||
let mut pages = c_int::MAX;
|
||||
let mut bands = c_int::MAX;
|
||||
let mut format = c_int::MAX;
|
||||
let status = NativeStatus::from_code(unsafe {
|
||||
native::fluxer_vips_probe_animated(
|
||||
input.as_ptr().cast(),
|
||||
@@ -183,10 +185,12 @@ fn probe_animated_status(input: &[u8]) -> (NativeStatus, c_int, c_int, c_int) {
|
||||
&mut width,
|
||||
&mut height,
|
||||
&mut pages,
|
||||
&mut bands,
|
||||
&mut format,
|
||||
)
|
||||
});
|
||||
unsafe { native::fluxer_vips_error_clear() };
|
||||
(status, width, height, pages)
|
||||
(status, width, height, pages, bands)
|
||||
}
|
||||
|
||||
fn apng_decode_status(input: &[u8]) -> (NativeStatus, *mut native::VipsImage, u32) {
|
||||
@@ -286,16 +290,18 @@ fn every_remaining_native_validator_zeroes_its_out_params_on_failure() {
|
||||
"input {bytes:?}"
|
||||
);
|
||||
|
||||
let (status, width, height, pages) = probe_animated_status(&bytes);
|
||||
let (status, width, height, pages, bands) = probe_animated_status(&bytes);
|
||||
assert_eq!(decodable, status == NativeStatus::Ok, "input {bytes:?}");
|
||||
if decodable {
|
||||
assert_eq!(1, width, "input {bytes:?}");
|
||||
assert_eq!(1, height, "input {bytes:?}");
|
||||
assert_eq!(1, pages, "input {bytes:?}");
|
||||
assert!(bands > 0, "input {bytes:?}");
|
||||
} else {
|
||||
assert_eq!(0, width, "input {bytes:?}");
|
||||
assert_eq!(0, height, "input {bytes:?}");
|
||||
assert_eq!(0, pages, "input {bytes:?}");
|
||||
assert_eq!(0, bands, "input {bytes:?}");
|
||||
}
|
||||
|
||||
let (status, out, num_plays) = apng_decode_status(&bytes);
|
||||
|
||||
@@ -15,8 +15,9 @@ pub const DEFAULT_IMAGE_SIZE: u32 = 128;
|
||||
pub const MAX_ANIMATED_FRAMES_DEFAULT: u32 = 20_000;
|
||||
pub const MAX_ANIMATED_TOTAL_PIXELS_DEFAULT: usize = 4 * MAX_MEDIA_IMAGE_PIXELS_DEFAULT;
|
||||
pub const MAX_JXL_DECODE_PIXELS: usize = 4096 * 4096;
|
||||
pub const MAX_JXL_SIMPLE_DECODE_PIXELS: usize = 8192 * 6144;
|
||||
pub const MAX_STATIC_OUTPUT_PIXELS: usize = 6144 * 4096;
|
||||
pub const MAX_GIF_RESIZE_OUTPUT_PIXELS: usize = 16 << 20;
|
||||
pub const MAX_ANIMATED_OUTPUT_PIXELS: usize = 16 << 20;
|
||||
pub const SVG_RASTER_MAX_DIMENSION: u32 = 4096;
|
||||
pub const LARGE_SOURCE_LOG_PIXELS: usize = 4096 * 4096;
|
||||
const _: () = assert!(MAX_ANIMATED_FRAMES_DEFAULT >= 20_000);
|
||||
|
||||
@@ -14,10 +14,15 @@ use std::time::Duration;
|
||||
|
||||
pub type HttpClient = ClientWithMiddleware;
|
||||
|
||||
const EXTERNAL_CONNECT_TIMEOUT_MS: u64 = 3_000;
|
||||
const EXTERNAL_READ_TIMEOUT_MS: u64 = 10_000;
|
||||
const EXTERNAL_RETRY_WINDOW_MS: u64 = 15_000;
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub struct HTTPClientOptions {
|
||||
connect_timeout_ms: NonZeroU64,
|
||||
request_timeout_ms: NonZeroU64,
|
||||
read_timeout_ms: Option<NonZeroU64>,
|
||||
retries: HTTPRetryPolicy,
|
||||
address_policy: HTTPAddressPolicy,
|
||||
}
|
||||
@@ -27,6 +32,7 @@ struct HTTPRetryPolicy {
|
||||
max_retries: NonZeroU32,
|
||||
min_delay_ms: NonZeroU64,
|
||||
max_delay_ms: NonZeroU64,
|
||||
window_ms: Option<NonZeroU64>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
@@ -44,6 +50,18 @@ impl HTTPClientOptions {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn external(request_timeout_ms: NonZeroU64) -> Self {
|
||||
let mut options = Self::new(
|
||||
NonZeroU64::new(EXTERNAL_CONNECT_TIMEOUT_MS)
|
||||
.expect("external connection timeout must be nonzero"),
|
||||
request_timeout_ms,
|
||||
)
|
||||
.restrict_to_public();
|
||||
options.read_timeout_ms = NonZeroU64::new(EXTERNAL_READ_TIMEOUT_MS);
|
||||
options.retries.window_ms = NonZeroU64::new(EXTERNAL_RETRY_WINDOW_MS);
|
||||
options
|
||||
}
|
||||
|
||||
pub fn restrict_to_public(mut self) -> Self {
|
||||
self.address_policy = HTTPAddressPolicy::PublicOnly;
|
||||
self
|
||||
@@ -57,6 +75,7 @@ impl Default for HTTPClientOptions {
|
||||
.expect("default connection timeout must be nonzero"),
|
||||
request_timeout_ms: NonZeroU64::new(30_000)
|
||||
.expect("default request timeout must be nonzero"),
|
||||
read_timeout_ms: None,
|
||||
retries: HTTPRetryPolicy {
|
||||
max_retries: NonZeroU32::new(2)
|
||||
.expect("default maximum retry count must be nonzero"),
|
||||
@@ -64,6 +83,7 @@ impl Default for HTTPClientOptions {
|
||||
.expect("default minimum retry delay must be nonzero"),
|
||||
max_delay_ms: NonZeroU64::new(500)
|
||||
.expect("default maximum retry delay must be nonzero"),
|
||||
window_ms: None,
|
||||
},
|
||||
address_policy: HTTPAddressPolicy::Any,
|
||||
}
|
||||
@@ -80,6 +100,9 @@ pub fn build_raw(options: HTTPClientOptions) -> Result<reqwest::Client, reqwest:
|
||||
.timeout(Duration::from_millis(options.request_timeout_ms.get()))
|
||||
.redirect(reqwest::redirect::Policy::none())
|
||||
.user_agent(crate::constants::OUTBOUND_USER_AGENT);
|
||||
if let Some(read_timeout_ms) = options.read_timeout_ms {
|
||||
builder = builder.read_timeout(Duration::from_millis(read_timeout_ms.get()));
|
||||
}
|
||||
if options.address_policy == HTTPAddressPolicy::PublicOnly {
|
||||
builder = builder.dns_resolver(Arc::new(PinnedDnsResolver));
|
||||
}
|
||||
@@ -96,6 +119,7 @@ pub fn build(
|
||||
max_retries,
|
||||
min_delay_ms,
|
||||
max_delay_ms,
|
||||
window_ms,
|
||||
} = options.retries;
|
||||
let retry_policy = ExponentialBackoff::builder()
|
||||
.retry_bounds(
|
||||
@@ -105,7 +129,11 @@ pub fn build(
|
||||
.build_with_max_retries(max_retries.get());
|
||||
Ok(builder
|
||||
.with(RetryTransientMiddleware::new_with_policy_and_strategy(
|
||||
ObservableRetryPolicy::new(retry_policy, Arc::clone(&metrics)),
|
||||
ObservableRetryPolicy::new(
|
||||
retry_policy,
|
||||
window_ms.map(|window| Duration::from_millis(window.get())),
|
||||
Arc::clone(&metrics),
|
||||
),
|
||||
MediaProxyRetryStrategy::new(metrics),
|
||||
))
|
||||
.build())
|
||||
@@ -157,4 +185,24 @@ mod tests {
|
||||
.expect_err("the pinned resolver rejects a loopback host");
|
||||
assert!(crate::public_net_policy::is_pinned_dns_failure(&error));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn the_external_client_fails_fast_on_slow_hosts() {
|
||||
let options = HTTPClientOptions::external(millis(30_000));
|
||||
assert_eq!(
|
||||
EXTERNAL_CONNECT_TIMEOUT_MS,
|
||||
options.connect_timeout_ms.get()
|
||||
);
|
||||
assert_eq!(30_000, options.request_timeout_ms.get());
|
||||
assert_eq!(
|
||||
Some(EXTERNAL_READ_TIMEOUT_MS),
|
||||
options.read_timeout_ms.map(NonZeroU64::get)
|
||||
);
|
||||
assert_eq!(
|
||||
Some(EXTERNAL_RETRY_WINDOW_MS),
|
||||
options.retries.window_ms.map(NonZeroU64::get)
|
||||
);
|
||||
assert_eq!(HTTPAddressPolicy::PublicOnly, options.address_policy);
|
||||
build_raw(options).expect("the external client configuration is valid");
|
||||
}
|
||||
}
|
||||
@@ -8,22 +8,40 @@ use reqwest_retry::{
|
||||
};
|
||||
use std::io::ErrorKind;
|
||||
use std::sync::Arc;
|
||||
use std::time::SystemTime;
|
||||
use std::time::{Duration, SystemTime};
|
||||
|
||||
pub(super) struct ObservableRetryPolicy {
|
||||
inner: ExponentialBackoff,
|
||||
retry_window: Option<Duration>,
|
||||
metrics: Arc<HTTPClientMetrics>,
|
||||
}
|
||||
|
||||
impl ObservableRetryPolicy {
|
||||
pub(super) fn new(inner: ExponentialBackoff, metrics: Arc<HTTPClientMetrics>) -> Self {
|
||||
Self { inner, metrics }
|
||||
pub(super) fn new(
|
||||
inner: ExponentialBackoff,
|
||||
retry_window: Option<Duration>,
|
||||
metrics: Arc<HTTPClientMetrics>,
|
||||
) -> Self {
|
||||
Self {
|
||||
inner,
|
||||
retry_window,
|
||||
metrics,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RetryPolicy for ObservableRetryPolicy {
|
||||
fn should_retry(&self, request_start_time: SystemTime, n_past_retries: u32) -> RetryDecision {
|
||||
let decision = self.inner.should_retry(request_start_time, n_past_retries);
|
||||
let window_spent = self.retry_window.is_some_and(|window| {
|
||||
request_start_time
|
||||
.elapsed()
|
||||
.is_ok_and(|elapsed| elapsed >= window)
|
||||
});
|
||||
let decision = if window_spent {
|
||||
RetryDecision::DoNotRetry
|
||||
} else {
|
||||
self.inner.should_retry(request_start_time, n_past_retries)
|
||||
};
|
||||
match decision {
|
||||
RetryDecision::Retry { .. } => self.metrics.record_retry(),
|
||||
RetryDecision::DoNotRetry => self.metrics.record_retries_exhausted(),
|
||||
@@ -263,7 +281,7 @@ mod tests {
|
||||
let backoff = ExponentialBackoff::builder()
|
||||
.retry_bounds(Duration::from_millis(1), Duration::from_millis(2))
|
||||
.build_with_max_retries(1);
|
||||
let policy = ObservableRetryPolicy::new(backoff, metrics.http_client());
|
||||
let policy = ObservableRetryPolicy::new(backoff, None, metrics.http_client());
|
||||
let started = SystemTime::now();
|
||||
assert!(matches!(
|
||||
policy.should_retry(started, 0),
|
||||
@@ -329,4 +347,38 @@ mod tests {
|
||||
Some(Retryable::Transient)
|
||||
));
|
||||
}
|
||||
|
||||
fn policy(window: Option<Duration>) -> ObservableRetryPolicy {
|
||||
ObservableRetryPolicy::new(
|
||||
ExponentialBackoff::builder().build_with_max_retries(2),
|
||||
window,
|
||||
Arc::new(HTTPClientMetrics::new()),
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_request_past_its_retry_window_is_not_retried() {
|
||||
let started = SystemTime::now() - Duration::from_secs(20);
|
||||
assert!(matches!(
|
||||
policy(Some(Duration::from_secs(15))).should_retry(started, 0),
|
||||
RetryDecision::DoNotRetry
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_request_inside_its_retry_window_is_retried() {
|
||||
assert!(matches!(
|
||||
policy(Some(Duration::from_secs(15))).should_retry(SystemTime::now(), 0),
|
||||
RetryDecision::Retry { .. }
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_policy_without_a_window_keeps_retrying_slow_requests() {
|
||||
let started = SystemTime::now() - Duration::from_secs(60);
|
||||
assert!(matches!(
|
||||
policy(None).should_retry(started, 0),
|
||||
RetryDecision::Retry { .. }
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,7 @@ pub struct MediaLimits {
|
||||
animated_frames: u32,
|
||||
animated_total_pixels: usize,
|
||||
max_media_proxy_bytes: usize,
|
||||
native_memory_budget_bytes: usize,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
@@ -59,9 +60,17 @@ impl MediaLimits {
|
||||
animated_frames,
|
||||
animated_total_pixels,
|
||||
max_media_proxy_bytes,
|
||||
native_memory_budget_bytes: usize::MAX,
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn with_native_memory_budget(self, native_memory_budget_bytes: usize) -> Self {
|
||||
Self {
|
||||
native_memory_budget_bytes,
|
||||
..self
|
||||
}
|
||||
}
|
||||
|
||||
pub fn default_from_config() -> Self {
|
||||
Self::new(MediaLimitConfiguration {
|
||||
image_dimension: MAX_MEDIA_IMAGE_DIMENSION_DEFAULT,
|
||||
@@ -92,4 +101,8 @@ impl MediaLimits {
|
||||
pub fn max_media_proxy_bytes(&self) -> usize {
|
||||
self.max_media_proxy_bytes
|
||||
}
|
||||
|
||||
pub fn native_memory_budget_bytes(&self) -> usize {
|
||||
self.native_memory_budget_bytes
|
||||
}
|
||||
}
|
||||
@@ -182,7 +182,7 @@ impl GifResizeDims {
|
||||
(self.width as usize)
|
||||
.saturating_mul(self.height as usize)
|
||||
.saturating_mul(frames.max(1) as usize)
|
||||
<= constants::MAX_GIF_RESIZE_OUTPUT_PIXELS
|
||||
<= constants::MAX_ANIMATED_OUTPUT_PIXELS
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,9 +15,24 @@ pub(crate) fn probe_animated(
|
||||
media_limits: &MediaLimits,
|
||||
input: &[u8],
|
||||
) -> Result<Option<AnimatedProbe>, MediaError> {
|
||||
Ok(
|
||||
probe_header(media_limits, input)?.map(|dims| AnimatedProbe {
|
||||
width: dims.width as c_int,
|
||||
height: dims.height as c_int,
|
||||
pages: dims.pages as c_int,
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
fn probe_header(
|
||||
media_limits: &MediaLimits,
|
||||
input: &[u8],
|
||||
) -> Result<Option<ImageDimensions>, MediaError> {
|
||||
let mut width = 0;
|
||||
let mut height = 0;
|
||||
let mut pages = 0;
|
||||
let mut bands = 0;
|
||||
let mut format = 0;
|
||||
let rc = unsafe {
|
||||
native::fluxer_vips_probe_animated(
|
||||
input.as_ptr().cast(),
|
||||
@@ -25,6 +40,8 @@ pub(crate) fn probe_animated(
|
||||
&mut width,
|
||||
&mut height,
|
||||
&mut pages,
|
||||
&mut bands,
|
||||
&mut format,
|
||||
)
|
||||
};
|
||||
match native::NativeStatus::from_code(rc) {
|
||||
@@ -39,14 +56,16 @@ pub(crate) fn probe_animated(
|
||||
.expect("non-success native status must map to an error"));
|
||||
}
|
||||
}
|
||||
if pages <= 0 || width <= 0 || height <= 0 {
|
||||
if pages <= 0 || width <= 0 || height <= 0 || bands <= 0 {
|
||||
return Err(MediaError::InvalidImageDimensions);
|
||||
}
|
||||
validate_animation_geometry(media_limits, width as u32, height as u32, pages as u32)?;
|
||||
Ok(Some(AnimatedProbe {
|
||||
width,
|
||||
height,
|
||||
pages,
|
||||
Ok(Some(ImageDimensions {
|
||||
width: width as u32,
|
||||
height: height as u32,
|
||||
pages: pages as u32,
|
||||
bands: bands as u32,
|
||||
eight_bit: format == unsafe { native::fluxer_vips_format_uchar },
|
||||
}))
|
||||
}
|
||||
|
||||
@@ -55,12 +74,8 @@ pub(crate) fn probe_image_dims(
|
||||
input: &[u8],
|
||||
) -> Result<ImageDimensions, MediaError> {
|
||||
ensure_vips_init()?;
|
||||
if let Some(probe) = probe_animated(media_limits, input)? {
|
||||
return Ok(ImageDimensions {
|
||||
width: probe.width as u32,
|
||||
height: probe.height as u32,
|
||||
pages: probe.pages as u32,
|
||||
});
|
||||
if let Some(dims) = probe_header(media_limits, input)? {
|
||||
return Ok(dims);
|
||||
}
|
||||
if mime::sniff(input).mime == "image/bmp"
|
||||
&& let Some(image) = try_decode_bmp(input, media_limits)?
|
||||
@@ -89,6 +104,10 @@ fn probe_loaded_image_dims(
|
||||
width,
|
||||
height,
|
||||
pages,
|
||||
bands: unsafe { native::fluxer_vips_image_get_bands(image.as_ptr()) } as u32,
|
||||
eight_bit: unsafe {
|
||||
native::fluxer_vips_image_get_format(image.as_ptr()) == native::fluxer_vips_format_uchar
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -66,7 +66,13 @@ pub(crate) fn validate_jxl_decode_pixels(
|
||||
let pixels = (dims.width as usize)
|
||||
.saturating_mul(dims.height as usize)
|
||||
.saturating_mul(dims.pages.max(1) as usize);
|
||||
if pixels > constants::MAX_JXL_DECODE_PIXELS {
|
||||
let simple = dims.pages == 1 && matches!(dims.bands, 1 | 3) && dims.eight_bit;
|
||||
let cap = if simple {
|
||||
constants::MAX_JXL_SIMPLE_DECODE_PIXELS
|
||||
} else {
|
||||
constants::MAX_JXL_DECODE_PIXELS
|
||||
};
|
||||
if pixels > cap {
|
||||
return Err(MediaError::TooLargeToProcess);
|
||||
}
|
||||
Ok(())
|
||||
|
||||
@@ -138,6 +138,8 @@ pub struct ImageDimensions {
|
||||
pub width: u32,
|
||||
pub height: u32,
|
||||
pub pages: u32,
|
||||
pub bands: u32,
|
||||
pub eight_bit: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Error, Eq, PartialEq)]
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
use super::MediaError;
|
||||
use super::image_probe::probe_image_dims;
|
||||
use super::loaded_image::static_output_pixels;
|
||||
use super::native_runtime::ensure_vips_init;
|
||||
use super::{ImageDimensions, MediaError};
|
||||
use crate::{
|
||||
constants, image_quality::ImageQuality, image_transform::ImageOptions,
|
||||
media_limits::MediaLimits, mime, output_format::OutputFormat,
|
||||
@@ -48,7 +48,8 @@ pub fn image_transform_cost(
|
||||
let sniffed_mime = mime::sniff(input).mime;
|
||||
let dims = probe_image_dims(media_limits, input)?;
|
||||
let source_pixels = dims.width as usize * dims.height as usize;
|
||||
let output_pixels = static_output_pixels(options, dims);
|
||||
let options = fit_jxl_output(input.len(), sniffed_mime, options, dims, media_limits);
|
||||
let output_pixels = static_output_pixels(&options, dims);
|
||||
let encode = encode_bytes_per_pixel(options.format, options.quality);
|
||||
let pixel_cost = if options.is_animated() && dims.pages > 1 {
|
||||
source_pixels.max(output_pixels) * RGBA_BYTES_PER_PIXEL * ANIMATED_CANVAS_BUFFERS
|
||||
@@ -59,6 +60,38 @@ pub fn image_transform_cost(
|
||||
Ok(NativeCost::Bytes(input.len().saturating_add(pixel_cost)))
|
||||
}
|
||||
|
||||
pub(super) fn fit_jxl_output(
|
||||
input_len: usize,
|
||||
sniffed_mime: &str,
|
||||
options: &ImageOptions,
|
||||
dims: ImageDimensions,
|
||||
media_limits: &MediaLimits,
|
||||
) -> ImageOptions {
|
||||
let mut fitted = *options;
|
||||
if sniffed_mime != "image/jxl" || options.is_animated() {
|
||||
return fitted;
|
||||
}
|
||||
let source_pixels = dims.width as usize * dims.height as usize;
|
||||
let affordable_pixels = media_limits
|
||||
.native_memory_budget_bytes()
|
||||
.saturating_sub(input_len)
|
||||
.saturating_sub(source_pixels * decode_bytes_per_pixel(sniffed_mime))
|
||||
/ encode_bytes_per_pixel(options.format, options.quality);
|
||||
let max_pixels = affordable_pixels.min(constants::MAX_STATIC_OUTPUT_PIXELS);
|
||||
if max_pixels == 0 || static_output_pixels(options, dims) <= max_pixels {
|
||||
return fitted;
|
||||
}
|
||||
let (width, height) = match (options.wants_cover_crop(), options.width, options.height) {
|
||||
(true, Some(width), Some(height)) => (width, height),
|
||||
_ => (dims.width, dims.height),
|
||||
};
|
||||
let (width, height) = (f64::from(width), f64::from(height));
|
||||
let shrink = (max_pixels as f64 / (width * height)).sqrt();
|
||||
fitted.width = Some(((width * shrink).floor() as u32).max(1));
|
||||
fitted.height = Some(((height * shrink).floor() as u32).max(1));
|
||||
fitted
|
||||
}
|
||||
|
||||
pub fn av_native_cost(input_len: usize) -> NativeCost {
|
||||
NativeCost::UpToBudget(
|
||||
input_len
|
||||
|
||||
@@ -57,7 +57,9 @@ fn animated_apng_input_transforms_through_ffmpeg_decode_path() {
|
||||
ImageDimensions {
|
||||
width: 8,
|
||||
height: 8,
|
||||
pages: 1
|
||||
pages: 1,
|
||||
bands: 3,
|
||||
eight_bit: true,
|
||||
},
|
||||
probe_image_dims(&test_media_limits(), &static_webp.bytes).unwrap()
|
||||
);
|
||||
|
||||
@@ -37,7 +37,9 @@ fn animated_heic_sequence_decodes_every_frame_and_encodes_an_animation() {
|
||||
ImageDimensions {
|
||||
width: 64,
|
||||
height: 64,
|
||||
pages: 4
|
||||
pages: 4,
|
||||
bands: 3,
|
||||
eight_bit: true,
|
||||
},
|
||||
probe_image_dims(&test_media_limits(), &animated.bytes).expect("probes webp")
|
||||
);
|
||||
@@ -85,7 +87,9 @@ fn still_heic_decodes_as_a_single_frame_when_animation_is_requested() {
|
||||
ImageDimensions {
|
||||
width: 64,
|
||||
height: 64,
|
||||
pages: 1
|
||||
pages: 1,
|
||||
bands: 3,
|
||||
eight_bit: true,
|
||||
},
|
||||
probe_image_dims(&test_media_limits(), &still.bytes).expect("probes webp")
|
||||
);
|
||||
@@ -113,7 +117,9 @@ fn avif_direct_decode_applies_resize_and_crop() {
|
||||
ImageDimensions {
|
||||
width: 32,
|
||||
height: 24,
|
||||
pages: 1
|
||||
pages: 1,
|
||||
bands: 3,
|
||||
eight_bit: true,
|
||||
},
|
||||
probe_image_dims(&test_media_limits(), &resized.bytes).unwrap()
|
||||
);
|
||||
@@ -135,7 +141,9 @@ fn avif_direct_decode_applies_resize_and_crop() {
|
||||
ImageDimensions {
|
||||
width: 32,
|
||||
height: 32,
|
||||
pages: 1
|
||||
pages: 1,
|
||||
bands: 3,
|
||||
eight_bit: true,
|
||||
},
|
||||
probe_image_dims(&test_media_limits(), &cropped.bytes).unwrap()
|
||||
);
|
||||
|
||||
@@ -14,9 +14,11 @@ use crate::{
|
||||
nsfw::{NSFWClient, NSFWPolicy},
|
||||
output_format::OutputFormat,
|
||||
test_fixtures::{
|
||||
fixture_audio_mp3_with_png_cover_art, fixture_audio_mp4_with_attached_picture,
|
||||
fixture_audio_only_mp4, fixture_h264_mp4, fixture_mkv_with_png_video_stream,
|
||||
fixture_mp4_with_undecodable_video, synthetic_png, synthetic_wav,
|
||||
JXL_4100_LOSSLESS_RGB16, JXL_4100_LOSSY_ALPHA, JXL_4100_LOSSY_RGB_DEPTH,
|
||||
JXL_7000X4000_LOSSY_RGB, fixture_audio_mp3_with_png_cover_art,
|
||||
fixture_audio_mp4_with_attached_picture, fixture_audio_only_mp4, fixture_h264_mp4,
|
||||
fixture_mkv_with_png_video_stream, fixture_mp4_with_undecodable_video, synthetic_png,
|
||||
synthetic_wav,
|
||||
},
|
||||
};
|
||||
use std::{io::Write as _, sync::Arc};
|
||||
@@ -252,22 +254,37 @@ fn metadata_succeeds_without_a_placeholder_when_thumbhash_generation_fails() {
|
||||
|
||||
#[test]
|
||||
fn metadata_refuses_jxl_above_the_decode_pixel_cap() {
|
||||
let err = tokio::runtime::Builder::new_current_thread()
|
||||
.build()
|
||||
.unwrap()
|
||||
.block_on(async {
|
||||
metadata_json_with_options(
|
||||
crate::test_fixtures::JXL_4100_LOSSY_ALPHA,
|
||||
"big.jxl",
|
||||
MetadataOptions::default(),
|
||||
&test_media_limits(),
|
||||
&NSFWClient::disabled(),
|
||||
&TransformMetrics::new(),
|
||||
)
|
||||
.await
|
||||
.unwrap_err()
|
||||
});
|
||||
assert_eq!(MediaError::TooLargeToProcess, err);
|
||||
for jxl in [
|
||||
JXL_4100_LOSSY_ALPHA,
|
||||
JXL_4100_LOSSY_RGB_DEPTH,
|
||||
JXL_4100_LOSSLESS_RGB16,
|
||||
] {
|
||||
let err = tokio::runtime::Builder::new_current_thread()
|
||||
.build()
|
||||
.unwrap()
|
||||
.block_on(async {
|
||||
metadata_json_with_options(
|
||||
jxl,
|
||||
"big.jxl",
|
||||
MetadataOptions::default(),
|
||||
&test_media_limits(),
|
||||
&NSFWClient::disabled(),
|
||||
&TransformMetrics::new(),
|
||||
)
|
||||
.await
|
||||
.unwrap_err()
|
||||
});
|
||||
assert_eq!(MediaError::TooLargeToProcess, err);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn metadata_admits_8_bit_rgb_jxl_above_the_decode_pixel_cap() {
|
||||
let value = metadata_value(JXL_7000X4000_LOSSY_RGB, "big.jxl");
|
||||
assert_eq!("image/jxl", value["content_type"]);
|
||||
assert_eq!(7000, value["width"]);
|
||||
assert_eq!(4000, value["height"]);
|
||||
assert!(value["placeholder"].as_str().is_some_and(|p| !p.is_empty()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -1,15 +1,21 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
use super::super::image_probe::load_image;
|
||||
use super::super::image_probe::{load_image, probe_image_dims};
|
||||
use super::super::loaded_image::validate_jxl_decode_pixels;
|
||||
use super::super::native_runtime::ensure_vips_init;
|
||||
use super::super::transform::source_supports_pages;
|
||||
use super::super::{ImageOptions, MediaError, NativeCost, image_transform_cost};
|
||||
use super::fixtures::{animated_mode, metadata_value, png_zlib_level, transform_image};
|
||||
use super::super::{ImageDimensions, ImageOptions, MediaError, NativeCost, image_transform_cost};
|
||||
use super::fixtures::{
|
||||
animated_mode, metadata_value, png_zlib_level, test_media_limits, transform_image,
|
||||
};
|
||||
use crate::{
|
||||
constants,
|
||||
metrics::transform::TransformMetrics,
|
||||
mime, native,
|
||||
output_format::OutputFormat,
|
||||
test_fixtures::{
|
||||
JPEG_ROTATED_MISMATCHED_SCAN, JXL_64_LOSSY_ALPHA, JXL_4100_LOSSY_ALPHA, png_dimensions,
|
||||
JPEG_ROTATED_MISMATCHED_SCAN, JXL_64_LOSSY_ALPHA, JXL_4100_LOSSLESS_RGB16,
|
||||
JXL_4100_LOSSY_ALPHA, JXL_4100_LOSSY_RGB_DEPTH, JXL_7000X4000_LOSSY_RGB, png_dimensions,
|
||||
synthetic_bmp, synthetic_png,
|
||||
},
|
||||
};
|
||||
@@ -109,20 +115,131 @@ fn source_supports_pages_matches_libvips_loader_list() {
|
||||
|
||||
#[test]
|
||||
fn refuses_jxl_above_the_decode_pixel_cap_before_decoding() {
|
||||
for width in [None, Some(128)] {
|
||||
let err = transform_image(
|
||||
JXL_4100_LOSSY_ALPHA,
|
||||
&ImageOptions {
|
||||
width,
|
||||
format: OutputFormat::WebP,
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.unwrap_err();
|
||||
assert_eq!(MediaError::TooLargeToProcess, err);
|
||||
for jxl in [
|
||||
JXL_4100_LOSSY_ALPHA,
|
||||
JXL_4100_LOSSY_RGB_DEPTH,
|
||||
JXL_4100_LOSSLESS_RGB16,
|
||||
] {
|
||||
for width in [None, Some(128)] {
|
||||
let err = transform_image(
|
||||
jxl,
|
||||
&ImageOptions {
|
||||
width,
|
||||
format: OutputFormat::WebP,
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.unwrap_err();
|
||||
assert_eq!(MediaError::TooLargeToProcess, err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn jxl_decode_cap_depends_on_the_header_layout() {
|
||||
let dims = |width, height, pages, bands, eight_bit| ImageDimensions {
|
||||
width,
|
||||
height,
|
||||
pages,
|
||||
bands,
|
||||
eight_bit,
|
||||
};
|
||||
let simple_cap = (8192, 6144);
|
||||
let complex_cap = (4096, 4096);
|
||||
for bands in [1, 3] {
|
||||
let (width, height) = simple_cap;
|
||||
assert_eq!(
|
||||
Ok(()),
|
||||
validate_jxl_decode_pixels("image/jxl", dims(width, height, 1, bands, true))
|
||||
);
|
||||
assert_eq!(
|
||||
Err(MediaError::TooLargeToProcess),
|
||||
validate_jxl_decode_pixels("image/jxl", dims(width, height + 1, 1, bands, true))
|
||||
);
|
||||
}
|
||||
for (pages, bands, eight_bit) in [(1, 2, true), (1, 4, true), (1, 3, false), (2, 3, true)] {
|
||||
let (width, height) = complex_cap;
|
||||
assert_eq!(
|
||||
Ok(()),
|
||||
validate_jxl_decode_pixels(
|
||||
"image/jxl",
|
||||
dims(width, height / pages, pages, bands, eight_bit)
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
Err(MediaError::TooLargeToProcess),
|
||||
validate_jxl_decode_pixels(
|
||||
"image/jxl",
|
||||
dims(width, height / pages + 1, pages, bands, eight_bit)
|
||||
)
|
||||
);
|
||||
}
|
||||
assert_eq!(
|
||||
Ok(()),
|
||||
validate_jxl_decode_pixels("image/png", dims(16384, 16384, 1, 4, false))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn thumbnails_8_bit_rgb_jxl_above_the_decode_pixel_cap() {
|
||||
let out = transform_image(
|
||||
JXL_7000X4000_LOSSY_RGB,
|
||||
&ImageOptions {
|
||||
width: Some(550),
|
||||
format: OutputFormat::WebP,
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!("image/webp", out.content_type);
|
||||
let dims = probe_image_dims(&test_media_limits(), &out.bytes).unwrap();
|
||||
assert_eq!((550, 314), (dims.width, dims.height));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn full_size_jxl_above_the_static_output_cap_is_downscaled_to_fit() {
|
||||
let options = ImageOptions {
|
||||
format: OutputFormat::WebP,
|
||||
..Default::default()
|
||||
};
|
||||
let out = transform_image(JXL_7000X4000_LOSSY_RGB, &options).unwrap();
|
||||
assert_eq!("image/webp", out.content_type);
|
||||
let dims = probe_image_dims(&test_media_limits(), &out.bytes).unwrap();
|
||||
assert_eq!((6636, 3792), (dims.width, dims.height));
|
||||
assert!(dims.width as usize * dims.height as usize <= constants::MAX_STATIC_OUTPUT_PIXELS);
|
||||
|
||||
let cost =
|
||||
image_transform_cost(JXL_7000X4000_LOSSY_RGB, &options, &test_media_limits()).unwrap();
|
||||
assert_eq!(
|
||||
NativeCost::Bytes(JXL_7000X4000_LOSSY_RGB.len() + 7000 * 4000 * 40 + 6636 * 3792 * 28),
|
||||
cost
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn full_size_jxl_is_downscaled_to_fit_the_native_memory_budget() {
|
||||
let options = ImageOptions {
|
||||
format: OutputFormat::WebP,
|
||||
..Default::default()
|
||||
};
|
||||
let decode = JXL_7000X4000_LOSSY_RGB.len() + 7000 * 4000 * 40;
|
||||
let budget = decode + 10_000_000 * 28;
|
||||
let media_limits = test_media_limits().with_native_memory_budget(budget);
|
||||
let out = super::super::transform_image(
|
||||
JXL_7000X4000_LOSSY_RGB,
|
||||
&options,
|
||||
&media_limits,
|
||||
&TransformMetrics::new(),
|
||||
)
|
||||
.unwrap();
|
||||
let dims = probe_image_dims(&test_media_limits(), &out.bytes).unwrap();
|
||||
assert_eq!((4183, 2390), (dims.width, dims.height));
|
||||
assert_eq!(
|
||||
NativeCost::Bytes(decode + 4183 * 2390 * 28),
|
||||
image_transform_cost(JXL_7000X4000_LOSSY_RGB, &options, &media_limits).unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn transforms_jxl_within_the_decode_pixel_cap() {
|
||||
let out = transform_image(
|
||||
|
||||
@@ -13,9 +13,10 @@ use super::image_probe::{
|
||||
};
|
||||
use super::loaded_image::{
|
||||
normalize_vips_image_to_uchar, page_height, resize_loaded_image, resize_loaded_image_by_scale,
|
||||
validate_dimensions_u32, validate_jxl_decode_pixels, validate_static_output_pixels,
|
||||
validate_vips_image,
|
||||
static_output_pixels, validate_dimensions_u32, validate_jxl_decode_pixels,
|
||||
validate_static_output_pixels, validate_vips_image,
|
||||
};
|
||||
use super::native_cost::fit_jxl_output;
|
||||
use super::native_runtime::{clear_vips_error, ensure_vips_init, last_vips_error};
|
||||
use super::transform_plan::{
|
||||
AutoQualitySource, output_is_sdr, resolve_auto_quality, should_transform_animated_webp_direct,
|
||||
@@ -80,17 +81,18 @@ fn heif_source_may_be_a_sequence(sniffed: mime::SniffInfo) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
fn ensure_decode_cost_admissible(
|
||||
fn admitted_transform_options(
|
||||
input: &[u8],
|
||||
sniffed_mime: &str,
|
||||
options: &ImageOptions,
|
||||
media_limits: &MediaLimits,
|
||||
) -> Result<(), MediaError> {
|
||||
) -> Result<ImageOptions, MediaError> {
|
||||
let animated = options.is_animated();
|
||||
if animated && sniffed_mime != "image/jxl" {
|
||||
return Ok(());
|
||||
return Ok(*options);
|
||||
}
|
||||
let dims = probe_image_dims(media_limits, input)?;
|
||||
let options = &fit_jxl_output(input.len(), sniffed_mime, options, dims, media_limits);
|
||||
let source_pixels = dims.width as usize * dims.height as usize;
|
||||
if source_pixels >= constants::LARGE_SOURCE_LOG_PIXELS {
|
||||
tracing::info!(
|
||||
@@ -125,7 +127,32 @@ fn ensure_decode_cost_admissible(
|
||||
"native transform refused by decode cost limits"
|
||||
);
|
||||
}
|
||||
admitted
|
||||
admitted.map(|()| *options)
|
||||
}
|
||||
|
||||
fn ensure_animated_output_admissible(
|
||||
input: &[u8],
|
||||
options: &ImageOptions,
|
||||
media_limits: &MediaLimits,
|
||||
) -> Result<(), MediaError> {
|
||||
let dims = probe_image_dims(media_limits, input)?;
|
||||
if dims.pages <= 1 {
|
||||
return Ok(());
|
||||
}
|
||||
let output_pixels = static_output_pixels(options, dims).saturating_mul(dims.pages as usize);
|
||||
if output_pixels <= constants::MAX_ANIMATED_OUTPUT_PIXELS {
|
||||
return Ok(());
|
||||
}
|
||||
tracing::warn!(
|
||||
input_bytes = input.len(),
|
||||
width = dims.width,
|
||||
height = dims.height,
|
||||
pages = dims.pages,
|
||||
out_width = options.width.unwrap_or(0),
|
||||
out_height = options.height.unwrap_or(0),
|
||||
"animated transform refused by the output work budget"
|
||||
);
|
||||
Err(MediaError::TooLargeToProcess)
|
||||
}
|
||||
|
||||
pub fn transform_image(
|
||||
@@ -150,7 +177,7 @@ pub fn transform_image(
|
||||
ensure_vips_init()?;
|
||||
let sniffed = mime::sniff(input);
|
||||
let animated = options.is_animated();
|
||||
ensure_decode_cost_admissible(input, sniffed.mime, options, media_limits)?;
|
||||
let options = &admitted_transform_options(input, sniffed.mime, options, media_limits)?;
|
||||
let format = effective_transform_format(sniffed.mime, options.format, animated);
|
||||
let animated_avif = sniffed.mime == "image/avif" && sniffed.animated;
|
||||
let full_canvas_animation = animated
|
||||
@@ -184,6 +211,9 @@ pub fn transform_image(
|
||||
content_type: "image/gif",
|
||||
});
|
||||
}
|
||||
if animated {
|
||||
ensure_animated_output_admissible(input, options, media_limits)?;
|
||||
}
|
||||
if should_transform_animated_webp_direct(sniffed, options, format) {
|
||||
validate_dimensions_u32(media_limits, sniffed.width, sniffed.height)?;
|
||||
let resolved = resolve_auto_quality(
|
||||
|
||||
@@ -130,6 +130,8 @@ unsafe extern "C" {
|
||||
width: *mut c_int,
|
||||
height: *mut c_int,
|
||||
pages: *mut c_int,
|
||||
bands: *mut c_int,
|
||||
format: *mut c_int,
|
||||
) -> c_int;
|
||||
pub fn fluxer_apng_probe(
|
||||
buf: *const c_void,
|
||||
|
||||
@@ -41,13 +41,15 @@ void fluxer_vips_tune_for_server(int per_pipeline_threads) {
|
||||
vips_leak_set(FALSE);
|
||||
}
|
||||
|
||||
int fluxer_vips_probe_animated(const void *buf, size_t len, int *width, int *height, int *pages) {
|
||||
if (width == NULL || height == NULL || pages == NULL) {
|
||||
int fluxer_vips_probe_animated(const void *buf, size_t len, int *width, int *height, int *pages, int *bands, int *format) {
|
||||
if (width == NULL || height == NULL || pages == NULL || bands == NULL || format == NULL) {
|
||||
return FLUXER_NATIVE_STATUS_CODEC_FAILURE;
|
||||
}
|
||||
*width = 0;
|
||||
*height = 0;
|
||||
*pages = 0;
|
||||
*bands = 0;
|
||||
*format = VIPS_FORMAT_NOTSET;
|
||||
if (buf == NULL || len == 0) return FLUXER_NATIVE_STATUS_CODEC_FAILURE;
|
||||
VipsImage *header = vips_image_new_from_buffer(buf, len, "n=1", NULL);
|
||||
if (header == NULL) {
|
||||
@@ -82,6 +84,8 @@ int fluxer_vips_probe_animated(const void *buf, size_t len, int *width, int *hei
|
||||
*width = display_width;
|
||||
*height = display_height;
|
||||
*pages = n_pages;
|
||||
*bands = vips_image_get_bands(display_header);
|
||||
*format = vips_image_get_format(display_header);
|
||||
g_object_unref(display_header);
|
||||
g_object_unref(header);
|
||||
return FLUXER_NATIVE_STATUS_OK;
|
||||
|
||||
@@ -42,7 +42,12 @@ pub(in crate::server) fn transform_static_quality_default(
|
||||
) -> ImageQuality {
|
||||
if matches!(
|
||||
source_ext,
|
||||
Some(AssetExtension::Jpeg | AssetExtension::Heic | AssetExtension::Heif)
|
||||
Some(
|
||||
AssetExtension::Jpeg
|
||||
| AssetExtension::Heic
|
||||
| AssetExtension::Heif
|
||||
| AssetExtension::Jxl
|
||||
)
|
||||
) {
|
||||
ImageQuality::High
|
||||
} else {
|
||||
|
||||
@@ -63,7 +63,7 @@ impl HttpRequestDrain {
|
||||
fn begin_request(&self) -> ActiveHttpRequest {
|
||||
self.inner
|
||||
.active_requests
|
||||
.fetch_update(Ordering::AcqRel, Ordering::Acquire, |active| {
|
||||
.try_update(Ordering::AcqRel, Ordering::Acquire, |active| {
|
||||
active.checked_add(1)
|
||||
})
|
||||
.expect("http active request count must not overflow");
|
||||
|
||||
@@ -239,7 +239,7 @@ impl NativeTaskTracker {
|
||||
}
|
||||
self.inner
|
||||
.active
|
||||
.fetch_update(Ordering::AcqRel, Ordering::Acquire, |active| {
|
||||
.try_update(Ordering::AcqRel, Ordering::Acquire, |active| {
|
||||
active.checked_add(1)
|
||||
})
|
||||
.expect("native task count must not overflow");
|
||||
|
||||
@@ -42,7 +42,7 @@ impl AppState {
|
||||
NonZeroU64::new(cfg.socket_io_timeout_ms).unwrap_or(NonZeroU64::MIN);
|
||||
let store = Store::try_new(cfg.clone(), metrics.storage(), metrics.http_client())?;
|
||||
let external_client = http_client::build(
|
||||
HTTPClientOptions::new(socket_io_timeout, socket_io_timeout).restrict_to_public(),
|
||||
HTTPClientOptions::external(socket_io_timeout),
|
||||
metrics.http_client(),
|
||||
)?;
|
||||
let nsfw = NSFWClient::new(
|
||||
|
||||
@@ -93,12 +93,13 @@ impl TransformRuntime {
|
||||
cfg: &Config,
|
||||
metrics: &Arc<metrics::Metrics>,
|
||||
) -> anyhow::Result<Self> {
|
||||
let limits = MediaLimits::default_from_config();
|
||||
let memory_limit_bytes = process_memory_limit_bytes();
|
||||
let memory_budget_bytes = native_memory_budget_bytes(
|
||||
memory_limit_bytes,
|
||||
cfg.media.transform_cache_capacity_bytes,
|
||||
);
|
||||
let limits =
|
||||
MediaLimits::default_from_config().with_native_memory_budget(memory_budget_bytes);
|
||||
tracing::info!(
|
||||
memory_limit_bytes,
|
||||
transform_cache_bytes = cfg.media.transform_cache_capacity_bytes,
|
||||
@@ -574,8 +575,8 @@ async fn serve_image_transform(
|
||||
requested_download: transform.requested_download,
|
||||
});
|
||||
}
|
||||
let can_serve_original = transform.width.is_none()
|
||||
&& transform.height.is_none()
|
||||
let can_serve_original = ((transform.width.is_none() && transform.height.is_none())
|
||||
|| options.is_animated())
|
||||
&& is_browser_displayable_image(sniffed.mime);
|
||||
let mut too_large_original = None;
|
||||
let leader_original = &mut too_large_original;
|
||||
|
||||
@@ -4,7 +4,10 @@ use super::*;
|
||||
use crate::{
|
||||
constants::AssetExtension,
|
||||
server::format_policy::{default_transform_quality, transform_static_quality_default},
|
||||
test_fixtures::{JXL_4100_LOSSY_ALPHA, fixture_h264_mp4, fixture_jpeg, synthetic_png},
|
||||
test_fixtures::{
|
||||
JXL_64_LOSSY_ALPHA, JXL_4100_LOSSY_ALPHA, JXL_7000X4000_LOSSY_RGB, fixture_h264_mp4,
|
||||
fixture_jpeg, synthetic_png,
|
||||
},
|
||||
};
|
||||
use axum::body::to_bytes;
|
||||
|
||||
@@ -95,6 +98,7 @@ fn lossy_source_transform_defaults_to_lossy_output() {
|
||||
AssetExtension::Jpeg,
|
||||
AssetExtension::Heic,
|
||||
AssetExtension::Heif,
|
||||
AssetExtension::Jxl,
|
||||
] {
|
||||
assert_eq!(
|
||||
ImageQuality::High,
|
||||
@@ -150,6 +154,16 @@ async fn image_transform_route_sends_lossy_sources_to_a_lossy_encode() {
|
||||
transform_qualities_reaching_the_encoder(fixture_jpeg(), "image/jpeg", "photo.jpg").await,
|
||||
"a jpeg attachment must not be re-encoded losslessly"
|
||||
);
|
||||
assert_eq!(
|
||||
vec![ImageQuality::High],
|
||||
transform_qualities_reaching_the_encoder(
|
||||
JXL_64_LOSSY_ALPHA.to_vec(),
|
||||
"image/jxl",
|
||||
"photo.jxl"
|
||||
)
|
||||
.await,
|
||||
"a jxl attachment must not be re-encoded losslessly"
|
||||
);
|
||||
assert_eq!(
|
||||
vec![ImageQuality::Lossless],
|
||||
transform_qualities_reaching_the_encoder(synthetic_png(48, 48), "image/png", "art.png")
|
||||
@@ -307,6 +321,20 @@ async fn a_full_size_transform_too_large_to_process_never_serves_an_undisplayabl
|
||||
assert_eq!(StatusCode::BAD_REQUEST, response.status());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn a_full_size_jxl_above_the_static_output_cap_is_downscaled() {
|
||||
let response =
|
||||
attachment_transform(JXL_7000X4000_LOSSY_RGB, "big.jxl", &[("format", "webp")]).await;
|
||||
assert_eq!(StatusCode::OK, response.status());
|
||||
assert_eq!(
|
||||
Some("image/webp"),
|
||||
response
|
||||
.headers()
|
||||
.get(header::CONTENT_TYPE)
|
||||
.and_then(|value| value.to_str().ok())
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn the_budget_leaves_room_for_the_cache_and_headroom() {
|
||||
assert_eq!(
|
||||
@@ -325,3 +353,35 @@ fn a_cache_larger_than_the_pod_takes_at_most_half_of_it() {
|
||||
fn the_budget_never_drops_below_its_floor() {
|
||||
assert_eq!(128 << 20, native_memory_budget_bytes(64 << 20, 0));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn an_animated_transform_over_the_work_budget_serves_the_original() {
|
||||
let webp = crate::test_fixtures::ANIMATED_WEBP_1024_17_FRAMES;
|
||||
let response = attachment_transform(
|
||||
webp,
|
||||
"anim.webp",
|
||||
&[("format", "webp"), ("animated", "true"), ("width", "1000")],
|
||||
)
|
||||
.await;
|
||||
assert_eq!(StatusCode::OK, response.status());
|
||||
let body = to_bytes(response.into_body(), usize::MAX)
|
||||
.await
|
||||
.expect("body");
|
||||
assert_eq!(webp, body.as_ref());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn an_animated_transform_within_the_work_budget_is_transformed() {
|
||||
let webp = crate::test_fixtures::ANIMATED_WEBP_1024_17_FRAMES;
|
||||
let response = attachment_transform(
|
||||
webp,
|
||||
"anim.webp",
|
||||
&[("format", "webp"), ("animated", "true"), ("width", "128")],
|
||||
)
|
||||
.await;
|
||||
assert_eq!(StatusCode::OK, response.status());
|
||||
let body = to_bytes(response.into_body(), usize::MAX)
|
||||
.await
|
||||
.expect("body");
|
||||
assert_ne!(webp, body.as_ref());
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.3 KiB |
@@ -32,6 +32,10 @@ pub fn apng_header(frames: u32) -> Vec<u8> {
|
||||
|
||||
pub const JXL_4100_LOSSY_ALPHA: &[u8] = include_bytes!("jxl_4100_lossy_alpha.jxl");
|
||||
pub const JXL_64_LOSSY_ALPHA: &[u8] = include_bytes!("jxl_64_lossy_alpha.jxl");
|
||||
pub const JXL_7000X4000_LOSSY_RGB: &[u8] = include_bytes!("jxl_7000x4000_lossy_rgb.jxl");
|
||||
pub const JXL_4100_LOSSLESS_RGB16: &[u8] = include_bytes!("jxl_4100_lossless_rgb16.jxl");
|
||||
pub const JXL_4100_LOSSY_RGB_DEPTH: &[u8] = include_bytes!("jxl_4100_lossy_rgb_depth.jxl");
|
||||
pub const ANIMATED_WEBP_1024_17_FRAMES: &[u8] = include_bytes!("animated_webp_1024_17_frames.webp");
|
||||
pub const JPEG_ROTATED_MISMATCHED_SCAN: &[u8] = include_bytes!("jpeg_rotated_mismatched_scan.jpg");
|
||||
|
||||
pub fn synthetic_png(width: u32, height: u32) -> Vec<u8> {
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -10,10 +10,12 @@ pub use adversarial::{
|
||||
};
|
||||
pub use ffmpeg_cli::{ffmpeg_gen_media, ffmpeg_gen_mp4, ffmpeg_gen_rotated_mp4, ffmpeg_mirror_mp4};
|
||||
pub use images::{
|
||||
JPEG_ROTATED_MISMATCHED_SCAN, JXL_64_LOSSY_ALPHA, JXL_4100_LOSSY_ALPHA, animated_gif_fixture,
|
||||
animated_gif_frames, apng_header, first_webp_anim_frame_size, gif_frame_delays_cs,
|
||||
gif_loop_count, minimal_gif, png_dimensions, synthetic_bmp, synthetic_png,
|
||||
webp_animation_loop_count, webp_canvas_size, webp_chunk_payloads, webp_with_metadata_chunk,
|
||||
ANIMATED_WEBP_1024_17_FRAMES, JPEG_ROTATED_MISMATCHED_SCAN, JXL_64_LOSSY_ALPHA,
|
||||
JXL_4100_LOSSLESS_RGB16, JXL_4100_LOSSY_ALPHA, JXL_4100_LOSSY_RGB_DEPTH,
|
||||
JXL_7000X4000_LOSSY_RGB, animated_gif_fixture, animated_gif_frames, apng_header,
|
||||
first_webp_anim_frame_size, gif_frame_delays_cs, gif_loop_count, minimal_gif, png_dimensions,
|
||||
synthetic_bmp, synthetic_png, webp_animation_loop_count, webp_canvas_size, webp_chunk_payloads,
|
||||
webp_with_metadata_chunk,
|
||||
};
|
||||
pub use media::{
|
||||
fixture_audio_mp3_with_png_cover_art, fixture_audio_mp4_with_attached_picture,
|
||||
|
||||
@@ -39,7 +39,7 @@ int fluxer_vips_init(const char *argv0);
|
||||
void fluxer_vips_error_clear(void);
|
||||
const char *fluxer_vips_error_buffer(void);
|
||||
void fluxer_vips_tune_for_server(int per_pipeline_threads);
|
||||
int fluxer_vips_probe_animated(const void *buf, size_t len, int *width, int *height, int *pages);
|
||||
int fluxer_vips_probe_animated(const void *buf, size_t len, int *width, int *height, int *pages, int *bands, int *format);
|
||||
int fluxer_apng_probe(const void *buf, size_t len, int max_frames,
|
||||
size_t max_total_pixels, int *width, int *height, int *frames);
|
||||
VipsImage *fluxer_vips_image_new_from_buffer(const void *buf, size_t len, const char *option_string);
|
||||
|
||||
@@ -214,7 +214,7 @@ impl UserCaches {
|
||||
async fn invalidate(&self, user_id: i64) {
|
||||
let generation = self
|
||||
.generation(user_id)
|
||||
.fetch_update(Ordering::SeqCst, Ordering::SeqCst, |current| {
|
||||
.try_update(Ordering::SeqCst, Ordering::SeqCst, |current| {
|
||||
current.checked_add(1)
|
||||
})
|
||||
.expect("user cache generation exhausted");
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
import {BASE64_IMAGE_MAX_SIZE, MAX_BIO_LENGTH} from '@fluxer/constants/src/LimitConstants';
|
||||
import {
|
||||
BASE64_IMAGE_MAX_SIZE,
|
||||
MAX_BIO_LENGTH,
|
||||
MAX_SCREEN_SHARE_BITRATE_CEILING,
|
||||
MIN_SCREEN_SHARE_BITRATE_CEILING,
|
||||
} from '@fluxer/constants/src/LimitConstants';
|
||||
|
||||
export const LIMIT_KEYS = [
|
||||
'avatar_max_size',
|
||||
@@ -42,6 +47,7 @@ export const LIMIT_KEYS = [
|
||||
'max_private_channels_per_user',
|
||||
'max_reactions_per_message',
|
||||
'max_relationships',
|
||||
'max_screen_share_bitrate',
|
||||
'max_users_per_message_reaction',
|
||||
'max_voice_message_duration',
|
||||
'max_webhooks_per_channel',
|
||||
@@ -92,6 +98,7 @@ export const LIMIT_KEY_SCOPES: Record<LimitKey, LimitScope> = {
|
||||
max_private_channels_per_user: 'user',
|
||||
max_reactions_per_message: 'guild',
|
||||
max_relationships: 'user',
|
||||
max_screen_share_bitrate: 'user',
|
||||
max_users_per_message_reaction: 'guild',
|
||||
max_voice_message_duration: 'both',
|
||||
max_webhooks_per_channel: 'guild',
|
||||
@@ -99,7 +106,7 @@ export const LIMIT_KEY_SCOPES: Record<LimitKey, LimitScope> = {
|
||||
sticker_max_size: 'guild',
|
||||
};
|
||||
|
||||
type LimitCategory = 'messages' | 'guilds' | 'channels' | 'expressions' | 'files' | 'social' | 'features';
|
||||
type LimitCategory = 'messages' | 'guilds' | 'channels' | 'expressions' | 'files' | 'social' | 'media' | 'features';
|
||||
|
||||
interface LimitKeyMetadata {
|
||||
key: LimitKey;
|
||||
@@ -108,7 +115,7 @@ interface LimitKeyMetadata {
|
||||
category: LimitCategory;
|
||||
scope: LimitScope;
|
||||
isToggle: boolean;
|
||||
unit?: 'bytes' | 'count';
|
||||
unit?: 'bytes' | 'count' | 'bps';
|
||||
min?: number;
|
||||
max?: number;
|
||||
}
|
||||
@@ -120,6 +127,7 @@ export const LIMIT_CATEGORY_LABELS: Record<LimitCategory, string> = {
|
||||
expressions: 'Expressions & Stickers',
|
||||
files: 'Files & Attachments',
|
||||
social: 'Social & Private',
|
||||
media: 'Voice & Video',
|
||||
features: 'Feature Toggles',
|
||||
};
|
||||
export const LIMIT_KEY_METADATA: Record<LimitKey, LimitKeyMetadata> = {
|
||||
@@ -437,6 +445,17 @@ export const LIMIT_KEY_METADATA: Record<LimitKey, LimitKeyMetadata> = {
|
||||
isToggle: false,
|
||||
unit: 'count',
|
||||
},
|
||||
max_screen_share_bitrate: {
|
||||
key: 'max_screen_share_bitrate',
|
||||
label: 'Max Screen Share Bitrate',
|
||||
description: 'Highest video bitrate a screen share can send, in bits per second',
|
||||
category: 'media',
|
||||
scope: 'user',
|
||||
isToggle: false,
|
||||
unit: 'bps',
|
||||
min: MIN_SCREEN_SHARE_BITRATE_CEILING,
|
||||
max: MAX_SCREEN_SHARE_BITRATE_CEILING,
|
||||
},
|
||||
feature_animated_avatar: {
|
||||
key: 'feature_animated_avatar',
|
||||
label: 'Animated Avatar',
|
||||
|
||||
@@ -72,6 +72,9 @@ export const MAX_FAVORITE_MEMES_NON_PREMIUM = 50;
|
||||
export const MAX_FAVORITE_MEME_TAGS = 10;
|
||||
export const MAX_FAVORITE_GIFS = 10000;
|
||||
export const MAX_VOICE_MESSAGE_DURATION = 1200;
|
||||
export const MAX_SCREEN_SHARE_BITRATE = 9_000_000;
|
||||
export const MIN_SCREEN_SHARE_BITRATE_CEILING = 1_000_000;
|
||||
export const MAX_SCREEN_SHARE_BITRATE_CEILING = 50_000_000;
|
||||
export const MAX_MEDIA_DURATION_SECONDS = 86400;
|
||||
export const EMOJI_MAX_SIZE = ASSET_FORMAT_POLICY.emoji.maxBytes;
|
||||
export const STICKER_MAX_SIZE = ASSET_FORMAT_POLICY.sticker.maxBytes;
|
||||
|
||||
Loaded 100 of 102 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user