Skip to content
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { Card } from "@/components/ui/base-ui/card"
import { Label } from "@/components/ui/base-ui/label"
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/base-ui/tooltip"
import { configFieldsAtomMap } from "@/utils/atoms/config"
import { DEFAULT_FONT_FAMILY, DEFAULT_FONT_SCALE, DEFAULT_FONT_WEIGHT, DEFAULT_SUBTITLE_COLOR } from "@/utils/constants/subtitles"
import { DEFAULT_FONT_FAMILY, DEFAULT_FONT_SCALE, DEFAULT_FONT_SHADOW_INTENSITY, DEFAULT_FONT_STROKE_WIDTH, DEFAULT_FONT_WEIGHT, DEFAULT_SUBTITLE_COLOR } from "@/utils/constants/subtitles"
import { SubtitlesTextStyleForm } from "./subtitles-text-style-form"

export function MainSubtitlesStyle() {
Expand All @@ -21,6 +21,8 @@ export function MainSubtitlesStyle() {
fontScale: DEFAULT_FONT_SCALE,
color: DEFAULT_SUBTITLE_COLOR,
fontWeight: DEFAULT_FONT_WEIGHT,
fontShadowIntensity: DEFAULT_FONT_SHADOW_INTENSITY,
fontStrokeWidth: DEFAULT_FONT_STROKE_WIDTH,
},
},
}))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { Field, FieldGroup, FieldLabel } from "@/components/ui/base-ui/field"
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/base-ui/select"
import { Slider } from "@/components/ui/base-ui/slider"
import { configFieldsAtomMap } from "@/utils/atoms/config"
import { MAX_FONT_SCALE, MAX_FONT_WEIGHT, MIN_FONT_SCALE, MIN_FONT_WEIGHT } from "@/utils/constants/subtitles"
import { MAX_FONT_SCALE, MAX_FONT_SHADOW_INTENSITY, MAX_FONT_STROKE_WIDTH, MAX_FONT_WEIGHT, MIN_FONT_SCALE, MIN_FONT_WEIGHT } from "@/utils/constants/subtitles"

const FIELD_ROW_CLASS_NAME = "gap-0"
const FIELD_ROW_CONTENT_CLASS_NAME = "flex flex-col gap-2 @xs/field-group:grid @xs/field-group:grid-cols-[8.5rem_minmax(0,1fr)] @xs/field-group:items-center @xs/field-group:gap-x-4"
Expand All @@ -18,6 +18,9 @@ const FONT_FAMILY_OPTIONS: { value: SubtitlesFontFamily, label: string }[] = [
{ value: "roboto", label: "Roboto" },
{ value: "noto-sans", label: "Noto Sans" },
{ value: "noto-serif", label: "Noto Serif" },
{ value: "misans", label: "MiSans" },
{ value: "ibm-plex", label: "IBM Plex" },
{ value: "tsuku-ard-gothic", label: "TsukuARdGothic Std" },
]

interface SubtitlesTextStyleFormProps {
Expand All @@ -29,6 +32,8 @@ export function SubtitlesTextStyleForm({ type }: SubtitlesTextStyleFormProps) {
const textStyle = videoSubtitlesConfig.style[type]
const [draftFontScale, setDraftFontScale] = useState(textStyle.fontScale)
const [draftFontWeight, setDraftFontWeight] = useState(textStyle.fontWeight)
const [draftShadowIntensity, setDraftShadowIntensity] = useState(textStyle.fontShadowIntensity)
const [draftStrokeWidth, setDraftStrokeWidth] = useState(textStyle.fontStrokeWidth)

useEffect(() => {
// eslint-disable-next-line react/set-state-in-effect
Expand All @@ -40,6 +45,16 @@ export function SubtitlesTextStyleForm({ type }: SubtitlesTextStyleFormProps) {
setDraftFontWeight(textStyle.fontWeight)
}, [textStyle.fontWeight])

useEffect(() => {
// eslint-disable-next-line react/set-state-in-effect
setDraftShadowIntensity(textStyle.fontShadowIntensity)
}, [textStyle.fontShadowIntensity])

useEffect(() => {
// eslint-disable-next-line react/set-state-in-effect
setDraftStrokeWidth(textStyle.fontStrokeWidth)
}, [textStyle.fontStrokeWidth])

const handleChange = (style: Partial<SubtitleTextStyle>) => {
void setVideoSubtitlesConfig(deepmerge(videoSubtitlesConfig, { style: { [type]: style } }))
}
Expand Down Expand Up @@ -128,6 +143,48 @@ export function SubtitlesTextStyleForm({ type }: SubtitlesTextStyleFormProps) {
</div>
</div>
</Field>

<Field className={FIELD_ROW_CLASS_NAME}>
<div className={FIELD_ROW_CONTENT_CLASS_NAME}>
<FieldLabel className={FIELD_LABEL_CLASS_NAME}>{i18n.t("options.videoSubtitles.style.shadowIntensity")}</FieldLabel>
<div className="flex min-w-0 items-center gap-2">
<Slider
min={0}
max={MAX_FONT_SHADOW_INTENSITY}
step={0.5}
value={draftShadowIntensity}
onValueChange={value => setDraftShadowIntensity(value as number)}
onValueCommitted={value => handleChange({ fontShadowIntensity: value as number })}
className="flex-1"
/>
<span className="w-10 text-sm text-right">
{draftShadowIntensity}
px
</span>
</div>
</div>
</Field>

<Field className={FIELD_ROW_CLASS_NAME}>
<div className={FIELD_ROW_CONTENT_CLASS_NAME}>
<FieldLabel className={FIELD_LABEL_CLASS_NAME}>{i18n.t("options.videoSubtitles.style.strokeWidth")}</FieldLabel>
<div className="flex min-w-0 items-center gap-2">
<Slider
min={0}
max={MAX_FONT_STROKE_WIDTH}
step={0.5}
value={draftStrokeWidth}
onValueChange={value => setDraftStrokeWidth(value as number)}
onValueCommitted={value => handleChange({ fontStrokeWidth: value as number })}
className="flex-1"
/>
<span className="w-10 text-sm text-right">
{draftStrokeWidth}
px
</span>
</div>
</div>
</Field>
</FieldGroup>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { Card } from "@/components/ui/base-ui/card"
import { Label } from "@/components/ui/base-ui/label"
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/base-ui/tooltip"
import { configFieldsAtomMap } from "@/utils/atoms/config"
import { DEFAULT_FONT_FAMILY, DEFAULT_FONT_SCALE, DEFAULT_FONT_WEIGHT, DEFAULT_SUBTITLE_COLOR } from "@/utils/constants/subtitles"
import { DEFAULT_FONT_FAMILY, DEFAULT_FONT_SCALE, DEFAULT_FONT_SHADOW_INTENSITY, DEFAULT_FONT_STROKE_WIDTH, DEFAULT_FONT_WEIGHT, DEFAULT_SUBTITLE_COLOR } from "@/utils/constants/subtitles"
import { SubtitlesTextStyleForm } from "./subtitles-text-style-form"

export function TranslationSubtitlesStyle() {
Expand All @@ -21,6 +21,8 @@ export function TranslationSubtitlesStyle() {
fontScale: DEFAULT_FONT_SCALE,
color: DEFAULT_SUBTITLE_COLOR,
fontWeight: DEFAULT_FONT_WEIGHT,
fontShadowIntensity: DEFAULT_FONT_SHADOW_INTENSITY,
fontStrokeWidth: DEFAULT_FONT_STROKE_WIDTH,
},
},
}))
Expand Down
5 changes: 5 additions & 0 deletions src/entrypoints/subtitles.content/ui/subtitle-lines.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,16 @@ interface SubtitleLineProps {
}

function getTextStyles(textStyle: SubtitleTextStyle) {
const hasShadow = textStyle.fontShadowIntensity > 0
const si = textStyle.fontShadowIntensity
return {
fontFamily: SUBTITLE_FONT_FAMILIES[textStyle.fontFamily] || SUBTITLE_FONT_FAMILIES.system,
fontSize: `${textStyle.fontScale / 100}em`,
color: textStyle.color,
fontWeight: textStyle.fontWeight,
textShadow: hasShadow ? `${Math.max(1, si * 0.25).toFixed(1)}px ${Math.max(1, si * 0.5).toFixed(1)}px ${si}px rgba(0,0,0,${(0.5 + (si / 8) * 0.5).toFixed(2)})` : "none",
WebkitTextStroke: textStyle.fontStrokeWidth > 0 ? `${textStyle.fontStrokeWidth}px rgba(0,0,0,0.8)` : "0",
paintOrder: "stroke fill" as const,
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,20 @@ import {
DEFAULT_DISPLAY_MODE,
DEFAULT_FONT_FAMILY,
DEFAULT_FONT_SCALE,
DEFAULT_FONT_SHADOW_INTENSITY,
DEFAULT_FONT_STROKE_WIDTH,
DEFAULT_FONT_WEIGHT,
DEFAULT_SUBTITLE_COLOR,
DEFAULT_TRANSLATION_POSITION,
MAX_BACKGROUND_OPACITY,
MAX_FONT_SCALE,
MAX_FONT_SHADOW_INTENSITY,
MAX_FONT_STROKE_WIDTH,
MAX_FONT_WEIGHT,
MIN_BACKGROUND_OPACITY,
MIN_FONT_SCALE,
MIN_FONT_SHADOW_INTENSITY,
MIN_FONT_STROKE_WIDTH,
MIN_FONT_WEIGHT,
SUBTITLE_FONT_FAMILIES,
} from "@/utils/constants/subtitles"
Expand Down Expand Up @@ -153,6 +159,26 @@ function TextStyleGroup({ icon, title, textStyle, onChange, onReset, portalConta
step={100}
onChange={v => onChange({ fontWeight: v })}
/>

<SliderRow
label={i18n.t("options.videoSubtitles.style.shadowIntensity")}
value={textStyle.fontShadowIntensity}
display={`${textStyle.fontShadowIntensity}px`}
min={MIN_FONT_SHADOW_INTENSITY}
max={MAX_FONT_SHADOW_INTENSITY}
step={0.5}
onChange={v => onChange({ fontShadowIntensity: v })}
/>

<SliderRow
label={i18n.t("options.videoSubtitles.style.strokeWidth")}
value={textStyle.fontStrokeWidth}
display={`${textStyle.fontStrokeWidth}px`}
min={MIN_FONT_STROKE_WIDTH}
max={MAX_FONT_STROKE_WIDTH}
step={0.5}
onChange={v => onChange({ fontStrokeWidth: v })}
/>
</SettingsGroup>
)
}
Expand All @@ -162,6 +188,8 @@ const DEFAULT_TEXT_STYLE: SubtitleTextStyle = {
fontScale: DEFAULT_FONT_SCALE,
color: DEFAULT_SUBTITLE_COLOR,
fontWeight: DEFAULT_FONT_WEIGHT,
fontShadowIntensity: DEFAULT_FONT_SHADOW_INTENSITY,
fontStrokeWidth: DEFAULT_FONT_STROKE_WIDTH,
}

export function StyleView() {
Expand Down
2 changes: 2 additions & 0 deletions src/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -900,6 +900,8 @@ options:
color: Color
fontWeight: Font Weight
backgroundOpacity: Background Opacity
shadowIntensity: Shadow
strokeWidth: Outline
reset: Reset to Default
aiSegmentation:
title: AI Smart Segmentation
Expand Down
2 changes: 2 additions & 0 deletions src/locales/es.yml
Original file line number Diff line number Diff line change
Expand Up @@ -900,6 +900,8 @@ options:
color: Color
fontWeight: Grosor de fuente
backgroundOpacity: Opacidad del fondo
shadowIntensity: Sombra
strokeWidth: Contorno
reset: Restablecer a predeterminado
aiSegmentation:
title: Segmentación inteligente de IA
Expand Down
2 changes: 2 additions & 0 deletions src/locales/ja.yml
Original file line number Diff line number Diff line change
Expand Up @@ -785,6 +785,8 @@ options:
color: 色
fontWeight: フォントウェイト
backgroundOpacity: 背景の透明度
shadowIntensity: シャドウ
strokeWidth: 輪郭
reset: デフォルトにリセット
aiSegmentation:
title: AI スマート区切り
Expand Down
2 changes: 2 additions & 0 deletions src/locales/ko.yml
Original file line number Diff line number Diff line change
Expand Up @@ -785,6 +785,8 @@ options:
color: 색상
fontWeight: 글꼴 굵기
backgroundOpacity: 배경 투명도
shadowIntensity: 그림자
strokeWidth: 윤곽선
reset: 기본값으로 재설정
aiSegmentation:
title: AI 스마트 분할
Expand Down
2 changes: 2 additions & 0 deletions src/locales/ru.yml
Original file line number Diff line number Diff line change
Expand Up @@ -785,6 +785,8 @@ options:
color: Цвет
fontWeight: Толщина шрифта
backgroundOpacity: Прозрачность фона
shadowIntensity: Тень
strokeWidth: Контур
reset: Сбросить по умолчанию
aiSegmentation:
title: AI Умная сегментация
Expand Down
2 changes: 2 additions & 0 deletions src/locales/tr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -785,6 +785,8 @@ options:
color: Renk
fontWeight: Yazı Kalınlığı
backgroundOpacity: Arka Plan Şeffaflığı
shadowIntensity: Gölge
strokeWidth: Anahat
reset: Varsayılana Sıfırla
aiSegmentation:
title: AI Akıllı Bölümlendirme
Expand Down
2 changes: 2 additions & 0 deletions src/locales/vi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -785,6 +785,8 @@ options:
color: Màu sắc
fontWeight: Độ đậm chữ
backgroundOpacity: Độ trong suốt nền
shadowIntensity: Đổ bóng
strokeWidth: Viền
reset: Đặt lại về mặc định
aiSegmentation:
title: AI Phân đoạn thông minh
Expand Down
2 changes: 2 additions & 0 deletions src/locales/zh-CN.yml
Original file line number Diff line number Diff line change
Expand Up @@ -900,6 +900,8 @@ options:
color: 颜色
fontWeight: 字体粗细
backgroundOpacity: 背景透明度
shadowIntensity: 阴影
strokeWidth: 描边
reset: 重置为默认
aiSegmentation:
title: AI 智能断句
Expand Down
2 changes: 2 additions & 0 deletions src/locales/zh-TW.yml
Original file line number Diff line number Diff line change
Expand Up @@ -785,6 +785,8 @@ options:
color: 顏色
fontWeight: 字重
backgroundOpacity: 背景透明度
shadowIntensity: 陰影
strokeWidth: 描邊
reset: 重設為預設值
aiSegmentation:
title: AI 智慧斷句
Expand Down
6 changes: 4 additions & 2 deletions src/types/config/subtitles.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
import { z } from "zod"
import { MAX_BACKGROUND_OPACITY, MAX_FONT_SCALE, MAX_FONT_WEIGHT, MIN_BACKGROUND_OPACITY, MIN_FONT_SCALE, MIN_FONT_WEIGHT } from "@/utils/constants/subtitles"
import { MAX_BACKGROUND_OPACITY, MAX_FONT_SCALE, MAX_FONT_SHADOW_INTENSITY, MAX_FONT_STROKE_WIDTH, MAX_FONT_WEIGHT, MIN_BACKGROUND_OPACITY, MIN_FONT_SCALE, MIN_FONT_WEIGHT } from "@/utils/constants/subtitles"
import { batchQueueConfigSchema, customPromptsConfigSchema, requestQueueConfigSchema } from "./translate"

export const subtitlesDisplayModeSchema = z.enum(["bilingual", "originalOnly", "translationOnly"])
export const subtitlesTranslationPositionSchema = z.enum(["above", "below"])
export const subtitlesFontFamilySchema = z.enum(["system", "roboto", "noto-sans", "noto-serif"])
export const subtitlesFontFamilySchema = z.enum(["system", "roboto", "noto-sans", "noto-serif", "misans", "ibm-plex", "tsuku-ard-gothic"])

export const subtitleTextStyleSchema = z.object({
fontFamily: subtitlesFontFamilySchema,
fontScale: z.number().min(MIN_FONT_SCALE).max(MAX_FONT_SCALE),
color: z.string(),
fontWeight: z.number().min(MIN_FONT_WEIGHT).max(MAX_FONT_WEIGHT),
fontShadowIntensity: z.number().min(0).max(MAX_FONT_SHADOW_INTENSITY),
fontStrokeWidth: z.number().min(0).max(MAX_FONT_STROKE_WIDTH),
})

export const subtitleContainerStyleSchema = z.object({
Expand Down
8 changes: 6 additions & 2 deletions src/utils/constants/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { DEFAULT_TRANSLATE_PROMPTS_CONFIG } from "./prompt"
import { DEFAULT_PROVIDER_CONFIG_LIST } from "./providers"
import { DEFAULT_SELECTION_OVERLAY_OPACITY } from "./selection"
import { DEFAULT_SIDE_CONTENT_WIDTH } from "./side"
import { DEFAULT_BACKGROUND_OPACITY, DEFAULT_DISPLAY_MODE, DEFAULT_FONT_FAMILY, DEFAULT_FONT_SCALE, DEFAULT_FONT_WEIGHT, DEFAULT_SUBTITLE_COLOR, DEFAULT_SUBTITLE_POSITION, DEFAULT_TRANSLATION_POSITION } from "./subtitles"
import { DEFAULT_BACKGROUND_OPACITY, DEFAULT_DISPLAY_MODE, DEFAULT_FONT_FAMILY, DEFAULT_FONT_SCALE, DEFAULT_FONT_SHADOW_INTENSITY, DEFAULT_FONT_STROKE_WIDTH, DEFAULT_FONT_WEIGHT, DEFAULT_SUBTITLE_COLOR, DEFAULT_SUBTITLE_POSITION, DEFAULT_TRANSLATION_POSITION } from "./subtitles"
import { DEFAULT_AUTO_TRANSLATE_SHORTCUT_KEY, DEFAULT_BATCH_CONFIG, DEFAULT_MIN_CHARACTERS_PER_NODE, DEFAULT_MIN_WORDS_PER_NODE, DEFAULT_PRELOAD_MARGIN, DEFAULT_PRELOAD_THRESHOLD, DEFAULT_REQUEST_CAPACITY, DEFAULT_REQUEST_RATE } from "./translate"
import { TRANSLATION_NODE_STYLE_ON_INSTALLED } from "./translation-node-style"
import { DEFAULT_TTS_CONFIG } from "./tts"
Expand All @@ -18,7 +18,7 @@ export const GOOGLE_DRIVE_TOKEN_STORAGE_KEY = "__googleDriveToken"

export const THEME_STORAGE_KEY = "theme"
export const DEFAULT_DETECTED_CODE = "eng" as const
export const CONFIG_SCHEMA_VERSION = 75
export const CONFIG_SCHEMA_VERSION = 76

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Add the v75→v76 migration before bumping schema

When an installed user upgrades from schema 75, this bump makes initializeConfig call runMigration(76, ...), but repo-wide search of src/utils/config/migration-scripts shows the latest script is v074-to-v075.ts and there is no v075-to-v076.ts. runMigration therefore throws, the loop advances anyway, and the stricter subtitle schema rejects the old config because fontShadowIntensity and fontStrokeWidth are missing, causing the extension to fall back to DEFAULT_CONFIG and lose the user's settings; migrateConfig paths such as Google Drive sync/import will throw the missing-migration error directly.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Add v076 migration example data

When this schema bump is present, all-migrations.test.ts derives latestVersionStr from CONFIG_SCHEMA_VERSION and imports src/utils/config/__tests__/example/v076.ts, but repo-wide inspection of src/utils/config/__tests__/example shows the newest fixture is still v075.ts. As a result, the migration test suite fails before validating the new v75→v76 script; add a v076 fixture (with the new subtitle style fields) alongside the migration.

Useful? React with 👍 / 👎.


export const DEFAULT_FLOATING_BUTTON_POSITION = 0.66
export const DEFAULT_FLOATING_BUTTON_SIDE: FloatingButtonSide = "right"
Expand Down Expand Up @@ -144,12 +144,16 @@ export const DEFAULT_CONFIG: Config = {
fontScale: DEFAULT_FONT_SCALE,
color: DEFAULT_SUBTITLE_COLOR,
fontWeight: DEFAULT_FONT_WEIGHT,
fontShadowIntensity: DEFAULT_FONT_SHADOW_INTENSITY,
fontStrokeWidth: DEFAULT_FONT_STROKE_WIDTH,
},
translation: {
fontFamily: DEFAULT_FONT_FAMILY,
fontScale: DEFAULT_FONT_SCALE,
color: DEFAULT_SUBTITLE_COLOR,
fontWeight: DEFAULT_FONT_WEIGHT,
fontShadowIntensity: DEFAULT_FONT_SHADOW_INTENSITY,
fontStrokeWidth: DEFAULT_FONT_STROKE_WIDTH,
},
container: {
backgroundOpacity: DEFAULT_BACKGROUND_OPACITY,
Expand Down
11 changes: 10 additions & 1 deletion src/utils/constants/subtitles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,13 @@ export const MAX_FONT_WEIGHT = 700
export const DEFAULT_FONT_WEIGHT = 400
export const MIN_BACKGROUND_OPACITY = 0
export const MAX_BACKGROUND_OPACITY = 100
export const DEFAULT_BACKGROUND_OPACITY = 75
export const DEFAULT_BACKGROUND_OPACITY = 0
export const MIN_FONT_SHADOW_INTENSITY = 0
export const MAX_FONT_SHADOW_INTENSITY = 8
export const DEFAULT_FONT_SHADOW_INTENSITY = 3
export const MIN_FONT_STROKE_WIDTH = 0
export const MAX_FONT_STROKE_WIDTH = 8
export const DEFAULT_FONT_STROKE_WIDTH = 2.5
export const DEFAULT_FONT_FAMILY = "system" as const
export const DEFAULT_SUBTITLE_COLOR = "#FFFFFF"
export const DEFAULT_DISPLAY_MODE = "bilingual" as const
Expand All @@ -74,4 +80,7 @@ export const SUBTITLE_FONT_FAMILIES = {
"roboto": "Roboto, sans-serif",
"noto-sans": "\"Noto Sans\", \"Noto Sans SC\", \"Noto Sans JP\", \"Noto Sans KR\", sans-serif",
"noto-serif": "\"Noto Serif\", \"Noto Serif SC\", \"Noto Serif JP\", \"Noto Serif KR\", serif",
"misans": "\"MiSans\", \"MiSans Latin\", \"MiSans TC\", \"MiSans L3\", \"MiSans Tibetan\", \"MiSans Arabic\", \"MiSans Devanagari\", \"MiSans Gurmukhi\", \"MiSans Thai\", \"MiSans Lao\", \"MiSans Myanmar\", \"MiSans Khmer\", sans-serif",
"ibm-plex": "\"IBM Plex Sans SC\", \"IBM Plex Sans TC\", \"IBM Plex Sans JP\", \"IBM Plex Sans KR\", \"IBM Plex Sans\", \"IBM Plex Sans Condensed\", \"IBM Plex Sans Arabic\", \"IBM Plex Sans Devanagari\", \"IBM Plex Sans Hebrew\", \"IBM Plex Sans Thai\", \"IBM Plex Sans Thai Looped\", sans-serif",
"tsuku-ard-gothic": "\"TsukuARdGothic Std\", \"筑紫A丸\", sans-serif",
}
6 changes: 5 additions & 1 deletion src/utils/subtitles/fetchers/youtube/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -407,7 +407,11 @@ export class YoutubeSubtitlesFetcher implements SubtitlesFetcher {
}
}

const data = await response.json()
const text = await response.text()
if (!text) {
throw new Error("YouTube subtitle API returned an empty response")
}
const data = JSON.parse(text)
const parsed = youtubeSubtitlesResponseSchema.safeParse(data)
if (!parsed.success) {
throw new Error("Invalid response format")
Expand Down