Implement BumperEndpoints and remove deprecated bumper-related functionality
Added new BumperEndpoints to the API for managing bumper templates and variants, enhancing the channel management capabilities. Removed outdated bumper-related commands and handlers from the application, streamlining the codebase and improving maintainability. Updated ChannelEndpoints to reflect these changes and ensure proper routing for the new endpoints.
This commit is contained in:
@@ -20,7 +20,6 @@ export const qk = {
|
||||
detail: (id: string) => ['admin', 'channels', id] as const,
|
||||
template: (id: string) => ['admin', 'channels', id, 'template'] as const,
|
||||
schedule: (id: string) => ['admin', 'channels', id, 'schedule'] as const,
|
||||
junctions: (id: string) => ['admin', 'channels', id, 'junctions'] as const,
|
||||
issues: (id: string) => ['admin', 'channels', id, 'issues'] as const,
|
||||
diff: (id: string) => ['admin', 'channels', id, 'diff'] as const,
|
||||
preview: (id: string, days: number) => ['admin', 'channels', id, 'preview', days] as const,
|
||||
@@ -29,6 +28,14 @@ export const qk = {
|
||||
['admin', 'channels', id, 'grid-plan', profile, mode] as const,
|
||||
},
|
||||
|
||||
junctions: {
|
||||
all: ['admin', 'junctions'] as const,
|
||||
},
|
||||
|
||||
bumpers: {
|
||||
all: ['admin', 'bumpers'] as const,
|
||||
},
|
||||
|
||||
gridProfiles: {
|
||||
all: ['admin', 'grid-profiles'] as const,
|
||||
},
|
||||
|
||||
@@ -430,37 +430,36 @@ export type ShowDto = {
|
||||
// ── Каналы ────────────────────────────────────────────────────────────────
|
||||
type ScheduleEntryKind = 'Program' | 'Ad' | 'Bumper' | 'Fallback' | 'SignOff'
|
||||
export type BumperFont = 'Sans' | 'Serif'
|
||||
export type BumperSelection = 'Random' | 'AlwaysFirst' | 'WeightedRandom'
|
||||
export type BumperTextKind = 'NowNext' | 'Free'
|
||||
export type BumperTrigger = 'OnShowChange' | 'BetweenEpisodes' | 'Both'
|
||||
export type BumperLineStyle = 'Label' | 'Title' | 'Caption'
|
||||
export type BumperLineColor = 'Accent' | 'Text'
|
||||
/** Что за картинка под текстом: фон блока, постер следующего или предыдущего шоу. */
|
||||
export type BumperBackground = 'Template' | 'NextPoster' | 'NowPoster'
|
||||
|
||||
/** Общие для канала настройки заставок (стиль/звук/текст — на блоках и подблоках). */
|
||||
/** Условия показа (как часто, на смене шоу или между сериями) живут на элементе стыка, не здесь. */
|
||||
export type BumperSettings = {
|
||||
font: BumperFont
|
||||
selection: BumperSelection
|
||||
/** Строка заставки: роль, цвет из палитры блока и текст с плейсхолдерами. */
|
||||
export type BumperLineDto = {
|
||||
style: BumperLineStyle
|
||||
color: BumperLineColor
|
||||
text: string
|
||||
}
|
||||
|
||||
/** Подблок (текст-вариант): свой текст + правило показа поверх стиля/звука блока. */
|
||||
/** Подблок (текст-вариант): свои строки, фон и правило показа поверх оформления блока. */
|
||||
export type BumperTextVariantDto = {
|
||||
id: string
|
||||
position: number
|
||||
name: string
|
||||
kind: BumperTextKind
|
||||
nowLabel: string
|
||||
nextLabel: string
|
||||
line1: string
|
||||
line2: string
|
||||
trigger: BumperTrigger
|
||||
/** Вес при стратегии выбора «случайно взвешенный» (0 — не выбирается). */
|
||||
background: BumperBackground
|
||||
/** Вес при выборе подблока на переходе (0 — не выбирается никогда). */
|
||||
weight: number
|
||||
lines: BumperLineDto[]
|
||||
}
|
||||
|
||||
/** Блок заставки — общий для всех каналов, как группа. */
|
||||
export type BumperTemplateDto = {
|
||||
id: string
|
||||
position: number
|
||||
isDefault: boolean
|
||||
name: string
|
||||
font: BumperFont
|
||||
backgroundColor: string
|
||||
backgroundColor2: string
|
||||
accentColor: string
|
||||
@@ -468,6 +467,8 @@ export type BumperTemplateDto = {
|
||||
backgroundImageId: string | null
|
||||
hasAudio: boolean
|
||||
audioDurationSeconds: number | null
|
||||
/** Во скольких врезках стыков используется блок — блоки общие, и это надо видеть до правки. */
|
||||
usageCount: number
|
||||
variants: BumperTextVariantDto[]
|
||||
}
|
||||
|
||||
@@ -490,9 +491,6 @@ export type ChannelDto = {
|
||||
/** Начало вещательных суток в времени канала («06:00:00»). */
|
||||
dayStartTime: string
|
||||
templateId: string | null
|
||||
bumpersEnabled: boolean
|
||||
bumper: BumperSettings
|
||||
bumperTemplates: BumperTemplateDto[]
|
||||
fillerAssetId: string | null
|
||||
viewer: ViewerSettings
|
||||
}
|
||||
@@ -547,10 +545,16 @@ export type SlotDto = {
|
||||
export type JunctionElementKind = 'Ad' | 'Promo' | 'Bumper' | 'Filler'
|
||||
export type JunctionAmountMode = 'Count' | 'Duration'
|
||||
|
||||
/** Окно суток канала; допускает переход через полночь («с 23:00 до 06:00»). */
|
||||
export type JunctionTimeWindow = { from: string; to: string }
|
||||
|
||||
/** Условия показа врезки — структурные поля, а не выражение-строка. */
|
||||
export type JunctionConditions = {
|
||||
onlyOnElementChange: boolean
|
||||
minMinutesBetween: number
|
||||
dayparts?: Daypart[] | null
|
||||
timeWindow?: JunctionTimeWindow | null
|
||||
chance: number
|
||||
}
|
||||
|
||||
export type JunctionElementDto = {
|
||||
@@ -561,15 +565,25 @@ export type JunctionElementDto = {
|
||||
groupName: string | null
|
||||
bumperTemplateId: string | null
|
||||
bumperTemplateName: string | null
|
||||
/** Конкретный подблок заставки; null — выбирается по триггеру перехода и весам. */
|
||||
bumperVariantId: string | null
|
||||
bumperVariantName: string | null
|
||||
amountMode: JunctionAmountMode
|
||||
amountValue: number
|
||||
isRequired: boolean
|
||||
/** Метка развилки: из врезок с одной меткой играет одна, выбранная по весам. */
|
||||
choiceKey: string | null
|
||||
choiceWeight: number
|
||||
conditions: JunctionConditions | null
|
||||
}
|
||||
|
||||
/** Стык — общий для всех каналов; канал только ссылается на него слотами. */
|
||||
export type JunctionTemplateDto = {
|
||||
id: string
|
||||
name: string
|
||||
maxTotalSeconds: number | null
|
||||
/** Сколько каналов ссылается на стык — он общий, и это надо видеть до правки. */
|
||||
channelUsageCount: number
|
||||
elements: JunctionElementDto[]
|
||||
}
|
||||
|
||||
|
||||
@@ -457,8 +457,6 @@ export const en = {
|
||||
everyDay: 'every day',
|
||||
daypart: 'Daypart',
|
||||
slotKind: 'Slot type',
|
||||
group: 'Group',
|
||||
pickGroup: 'pick a group',
|
||||
strategy: 'Strategy',
|
||||
cooldownDays: 'Cooldown, days',
|
||||
cooldownHint: 'Skip what already aired within this period.',
|
||||
@@ -475,8 +473,6 @@ export const en = {
|
||||
maxDrift: 'Allowance, min',
|
||||
snap: 'Snap',
|
||||
snapOff: 'off',
|
||||
bumperConditionsHint:
|
||||
'How often a bumper is inserted and on which transitions is a junction-element condition, not a channel setting.',
|
||||
resizeSlot: 'Drag the edge to change duration',
|
||||
copyDay: 'Copy day',
|
||||
copyDayFrom: 'Copy {{day}} to:',
|
||||
@@ -497,7 +493,6 @@ export const en = {
|
||||
grid: 'Grid',
|
||||
rules: 'Rules',
|
||||
junctions: 'Junctions',
|
||||
bumpers: 'Bumpers',
|
||||
viewer: 'Viewer',
|
||||
settings: 'Settings',
|
||||
air: 'On air',
|
||||
@@ -603,30 +598,12 @@ export const en = {
|
||||
'What plays between programmes: ads, promos, bumpers. A slot may pick its own junction, otherwise the default one is used.',
|
||||
defaultJunction: 'Default junction',
|
||||
noJunction: 'no junction',
|
||||
newJunctionName: 'New junction',
|
||||
addJunctionElement: '+ break',
|
||||
junctionEmpty: 'empty',
|
||||
junctionFrom: 'end',
|
||||
junctionTo: 'start',
|
||||
junctionElement: 'Break',
|
||||
junctionKind: 'Kind',
|
||||
junctionKinds: { Ad: 'Ad', Promo: 'Promo', Bumper: 'Bumper', Filler: 'Filler' },
|
||||
junctionAmountMode: 'Measured in',
|
||||
junctionAmountModes: { Count: 'Units', Duration: 'Minutes' },
|
||||
junctionCount: 'How many units',
|
||||
junctionMinutes: 'How many minutes',
|
||||
junctionAmountHint:
|
||||
'For a mixed group (clips and ready-made blocks) count in minutes: one "unit" there is either a clip or a whole block.',
|
||||
junctionRequired: 'Required — never dropped when time runs short',
|
||||
junctionOnlyOnChange: 'Only when the show changes',
|
||||
junctionMinInterval: 'No more often than once per, min',
|
||||
junctionMinIntervalHint: '0 — no limit.',
|
||||
junctionBetween: 'Junction inside the slot',
|
||||
junctionAfter: 'Junction after the slot',
|
||||
junctionDefault: 'default',
|
||||
bumperTemplate: 'Bumper block',
|
||||
pickBumperTemplate: 'pick a block',
|
||||
minutesShort: ' min',
|
||||
junctionsUsed: 'Used by this channel',
|
||||
junctionsNoneUsed: 'The channel references no junction — nothing plays between programmes.',
|
||||
openJunctionEditor: 'Junction editor',
|
||||
pendingChanges: 'Rules changed — the air still follows the old ones.',
|
||||
restore: 'Discard changes',
|
||||
restoreConfirm:
|
||||
@@ -677,64 +654,150 @@ export const en = {
|
||||
enabled: 'On air',
|
||||
enabledLabel: 'Channel on air',
|
||||
settings: 'Settings',
|
||||
bumpers: 'TV bumpers',
|
||||
bumpersLabel: 'Transition bumpers',
|
||||
bumpersHint: 'Short “Now / Next” bumper between different shows',
|
||||
bumperSelection: 'Block selection',
|
||||
bumperSelectionRandom: 'Random',
|
||||
bumperSelectionWeighted: 'Weighted random',
|
||||
bumperSelectionAlwaysFirst: 'Always first',
|
||||
bumperFont: 'Font',
|
||||
bumperFontSans: 'Sans',
|
||||
bumperFontSerif: 'Serif',
|
||||
bumperNowLabel: '“Now” label',
|
||||
bumperNextLabel: '“Next” label',
|
||||
bumperBg: 'Background (color 1)',
|
||||
bumperBg2: 'Background (color 2)',
|
||||
bumperAccent: 'Accent',
|
||||
bumperText: 'Text',
|
||||
bumperTemplates: 'Bumper blocks',
|
||||
bumperTemplatesHint:
|
||||
'Each block has its own sound and style. The first block is the default and cannot be removed. Bumper length follows the sound length.',
|
||||
bumperAddTemplate: 'Add block',
|
||||
bumperTemplateName: 'Name',
|
||||
bumperVariants: 'Sub-blocks (text)',
|
||||
bumperVariantsHint:
|
||||
'Different text over the same music and style. Each sub-block has its own show rule.',
|
||||
bumperAddVariant: 'Add text',
|
||||
bumperVariantName: 'Name',
|
||||
bumperTextKind: 'Text mode',
|
||||
bumperKindNowNext: 'Now / Next',
|
||||
bumperKindFree: 'Free text',
|
||||
bumperLine1: 'Line 1',
|
||||
bumperLine2: 'Line 2',
|
||||
bumperTrigger: 'Show on',
|
||||
bumperTriggerOnShowChange: 'Show change',
|
||||
bumperTriggerBetweenEpisodes: 'Between episodes',
|
||||
bumperTriggerBoth: 'Both',
|
||||
bumperVariantWeight: 'Weight',
|
||||
bumperVariantWeightHint:
|
||||
'For the “weighted random” strategy: higher = more often (0 — never picked)',
|
||||
bumperDefault: 'default',
|
||||
bumperSeconds: 's',
|
||||
bumperDefaultDuration: '≈8 s (jingle)',
|
||||
bumperAudio: 'Sound',
|
||||
bumperAudioHint: 'Bumper sound; otherwise a synthesized jingle',
|
||||
bumperPreview: 'Render samples',
|
||||
bumperPreviewRendering: 'Rendering…',
|
||||
bumperPreviewHint:
|
||||
'Samples of all sub-blocks with sound and animation (example show names). Uses saved settings.',
|
||||
bumperBackground: 'Background image',
|
||||
bumperBackgroundHint: 'Background image; otherwise the show poster or a gradient',
|
||||
bumperBackgroundPick: 'Pick from gallery',
|
||||
bumperFileLoaded: 'loaded',
|
||||
bumperFileDefault: 'default',
|
||||
bumperUpload: 'Upload',
|
||||
bumperReset: 'Reset',
|
||||
filler: 'Filler',
|
||||
noFiller: 'No filler',
|
||||
noSchedule: 'Schedule not built yet',
|
||||
},
|
||||
junctions: {
|
||||
title: 'Junctions',
|
||||
hint: 'What plays between programmes: ads, promos, bumpers. A junction is shared across channels — a channel only picks which one a slot uses.',
|
||||
newName: 'New junction',
|
||||
empty0: 'No junctions yet.',
|
||||
empty: 'empty',
|
||||
from: 'end',
|
||||
to: 'start',
|
||||
fork: 'fork',
|
||||
addElement: '+ break',
|
||||
maxTotal: 'Cap, s',
|
||||
usedInChannels: 'in channels: {{count}}',
|
||||
cannotDeleteUsed: 'The junction is used by channels — drop the references first.',
|
||||
splitOut: 'Take out of the fork',
|
||||
mergeIntoFork: 'Merge with the previous one into a fork',
|
||||
element: 'Break',
|
||||
kind: 'Type',
|
||||
kinds: {
|
||||
Ad: 'Ad',
|
||||
Promo: 'Promo',
|
||||
Bumper: 'Bumper',
|
||||
Filler: 'Filler',
|
||||
},
|
||||
group: 'Group',
|
||||
pickGroup: 'pick a group',
|
||||
bumperTemplate: 'Bumper block',
|
||||
pickBumper: 'pick a block',
|
||||
bumperVariant: 'Text variant',
|
||||
bumperVariantAuto: 'by trigger and weights',
|
||||
bumperVariantHint:
|
||||
'Keep "by trigger and weights" so show changes and episode breaks get different texts.',
|
||||
amountMode: 'Measured in',
|
||||
amountModes: { Count: 'Units', Duration: 'Minutes' },
|
||||
count: 'How many units',
|
||||
minutes: 'How many minutes',
|
||||
minutesShort: ' min',
|
||||
amountHint:
|
||||
'For a mixed group (spots and ready-made blocks) count in minutes: one unit there is either a spot or a whole block.',
|
||||
required: 'Required',
|
||||
requiredHint:
|
||||
'Required only decides what gets dropped when time runs short. It does not affect the order — that is the position in the chain.',
|
||||
choiceWeight: 'Weight in the fork',
|
||||
choiceWeightHint: 'The higher, the more often this break plays (0 — never picked).',
|
||||
conditions: 'Conditions',
|
||||
onlyOnChange: 'Only on show change',
|
||||
chance: 'Chance, %',
|
||||
chanceHint:
|
||||
'Chance and interval are per break; the roll comes from the generation seed, so rebuilds do not reshuffle breaks.',
|
||||
minInterval: 'No more often than once per, min',
|
||||
dayparts: 'Dayparts',
|
||||
daypartsHint: 'Nothing selected — the break plays in any daypart.',
|
||||
timeWindow: 'Channel time window',
|
||||
clearWindow: 'Clear',
|
||||
timeWindowHint: 'Empty — any time. The window may cross midnight.',
|
||||
badgeOnChange: 'on change',
|
||||
badgeInterval: 'once per {{minutes}} min',
|
||||
},
|
||||
bumpers: {
|
||||
title: 'Bumpers',
|
||||
hint: 'Bumper blocks are shared across channels: look and sound belong to the block, text to its variants. A bumper reaches air as a junction break.',
|
||||
empty: 'No bumper blocks yet.',
|
||||
newName: 'New block',
|
||||
newNamePlaceholder: 'Block name',
|
||||
newVariantName: 'New text',
|
||||
sampleChannel: 'Preview as channel',
|
||||
sampleChannelNone: 'no channel',
|
||||
sampleChannelHint: 'The block is shared, but sample values come from the selected channel.',
|
||||
name: 'Name',
|
||||
font: 'Font',
|
||||
fontSans: 'Sans',
|
||||
fontSerif: 'Serif',
|
||||
colorBg: 'Background (colour 1)',
|
||||
colorBg2: 'Background (colour 2)',
|
||||
colorAccent: 'Accent',
|
||||
colorText: 'Text',
|
||||
saveStyle: 'Save look',
|
||||
seconds: 's',
|
||||
defaultDuration: '≈8 s (jingle)',
|
||||
variantsCount: 'texts: {{count}}',
|
||||
usedInJunctions: 'in breaks: {{count}}',
|
||||
cannotDeleteUsed: 'The block is used by junction breaks — drop the references first.',
|
||||
audio: 'Sound',
|
||||
audioHint: 'The sound length sets the bumper duration; without it a jingle is synthesised.',
|
||||
background: 'Background',
|
||||
backgroundFieldHint: 'Block background image; otherwise a palette gradient or a show poster.',
|
||||
backgroundPick: 'Pick from gallery',
|
||||
backgrounds: {
|
||||
Template: 'Block background',
|
||||
NextPoster: 'Next show poster',
|
||||
NowPoster: 'Previous show poster',
|
||||
},
|
||||
fileLoaded: 'loaded',
|
||||
fileDefault: 'default',
|
||||
upload: 'Upload',
|
||||
reset: 'Reset',
|
||||
variants: 'Text variants',
|
||||
variantsHint:
|
||||
'Different text over the same music and look. Trigger and background are per variant.',
|
||||
addVariant: 'Add text',
|
||||
variantName: 'Name',
|
||||
trigger: 'Show on',
|
||||
triggers: {
|
||||
OnShowChange: 'Show change',
|
||||
BetweenEpisodes: 'Between episodes',
|
||||
Both: 'Both',
|
||||
},
|
||||
weight: 'Weight',
|
||||
lineStyles: { Label: 'Label', Title: 'Title', Caption: 'Caption' },
|
||||
lineColors: { Accent: 'Accent', Text: 'Text' },
|
||||
addLine: 'Line',
|
||||
presets: 'Presets',
|
||||
preset_nowNext: 'Now / Next',
|
||||
preset_nextAt: 'Next at …',
|
||||
preset_channel: 'Channel ident',
|
||||
presetNow: 'NOW',
|
||||
presetNext: 'NEXT',
|
||||
presetNextAt: 'NEXT AT',
|
||||
framePreview: 'Frame',
|
||||
framePreviewHint: 'Sample substitution: this is how the line looks on air.',
|
||||
unknownPlaceholder: 'Unknown placeholder: {{tokens}}',
|
||||
volatileHint: 'every airing is unique — the render cache stops working',
|
||||
render: 'Render samples',
|
||||
rendering: 'Rendering…',
|
||||
renderHint: 'A real ffmpeg render of every variant with sound — takes a few seconds.',
|
||||
tokens: {
|
||||
channel: 'Channel name',
|
||||
'channel.number': 'Channel number',
|
||||
'now.title': 'Current show',
|
||||
'next.title': 'Next show',
|
||||
'now.episode': 'Current episode',
|
||||
'next.episode': 'Next episode',
|
||||
'next.year': 'Next show year',
|
||||
'next.genre': 'Next show genre',
|
||||
'next.time': 'Next start time',
|
||||
time: 'Bumper airing time',
|
||||
date: 'Date',
|
||||
weekday: 'Weekday',
|
||||
slot: 'Slot title',
|
||||
},
|
||||
},
|
||||
maintenance: {
|
||||
title: 'Maintenance',
|
||||
warning: 'These actions are irreversible — data and files are deleted permanently.',
|
||||
|
||||
@@ -457,8 +457,6 @@ export const ru = {
|
||||
everyDay: 'каждый день',
|
||||
daypart: 'Дейпарт',
|
||||
slotKind: 'Тип слота',
|
||||
group: 'Группа',
|
||||
pickGroup: 'выберите группу',
|
||||
strategy: 'Стратегия',
|
||||
cooldownDays: 'Остывание, дней',
|
||||
cooldownHint: 'Не брать то, что уже выходило за этот срок.',
|
||||
@@ -475,8 +473,6 @@ export const ru = {
|
||||
maxDrift: 'Допуск, мин',
|
||||
snap: 'Округление',
|
||||
snapOff: 'нет',
|
||||
bumperConditionsHint:
|
||||
'Как часто ставить заставку и на каких переходах — условия элемента стыка, а не настройка канала.',
|
||||
resizeSlot: 'Потянуть за край — длительность',
|
||||
copyDay: 'Копировать день',
|
||||
copyDayFrom: 'Копировать {{day}} в:',
|
||||
@@ -497,7 +493,6 @@ export const ru = {
|
||||
grid: 'Сетка',
|
||||
rules: 'Правила',
|
||||
junctions: 'Стыки',
|
||||
bumpers: 'Заставки',
|
||||
viewer: 'Зритель',
|
||||
settings: 'Настройки',
|
||||
air: 'Эфир',
|
||||
@@ -603,35 +598,12 @@ export const ru = {
|
||||
'Что играет между программами: реклама, анонсы, заставки. Слот может взять свой стык, иначе берётся стык по умолчанию.',
|
||||
defaultJunction: 'Стык по умолчанию',
|
||||
noJunction: 'без стыка',
|
||||
newJunctionName: 'Новый стык',
|
||||
addJunctionElement: '+ врезка',
|
||||
junctionEmpty: 'пусто',
|
||||
junctionFrom: 'конец',
|
||||
junctionTo: 'начало',
|
||||
junctionElement: 'Врезка',
|
||||
junctionKind: 'Тип',
|
||||
junctionKinds: {
|
||||
Ad: 'Реклама',
|
||||
Promo: 'Анонс',
|
||||
Bumper: 'Заставка',
|
||||
Filler: 'Заполнитель',
|
||||
},
|
||||
junctionAmountMode: 'Чем меряется',
|
||||
junctionAmountModes: { Count: 'Единиц', Duration: 'Минут' },
|
||||
junctionCount: 'Сколько единиц',
|
||||
junctionMinutes: 'Сколько минут',
|
||||
junctionAmountHint:
|
||||
'В смешанной группе (ролики и готовые блоки) считайте минутами: одна «единица» там — то ли ролик, то ли блок.',
|
||||
junctionRequired: 'Обязательная — не выбрасывать при нехватке времени',
|
||||
junctionOnlyOnChange: 'Только при смене шоу',
|
||||
junctionMinInterval: 'Не чаще, чем раз в, мин',
|
||||
junctionMinIntervalHint: '0 — без ограничения.',
|
||||
junctionBetween: 'Стык внутри слота',
|
||||
junctionAfter: 'Стык после слота',
|
||||
junctionDefault: 'по умолчанию',
|
||||
bumperTemplate: 'Блок заставки',
|
||||
pickBumperTemplate: 'выберите блок',
|
||||
minutesShort: ' мин',
|
||||
junctionsUsed: 'Используются в этом канале',
|
||||
junctionsNoneUsed: 'Канал не ссылается ни на один стык — между программами ничего не играет.',
|
||||
openJunctionEditor: 'Редактор стыков',
|
||||
pendingChanges: 'Правила изменены — эфир идёт по старым.',
|
||||
restore: 'Сбросить изменения',
|
||||
restoreConfirm:
|
||||
@@ -682,64 +654,150 @@ export const ru = {
|
||||
enabled: 'В эфире',
|
||||
enabledLabel: 'Канал в эфире',
|
||||
settings: 'Настройки',
|
||||
bumpers: 'ТВ-заставки',
|
||||
bumpersLabel: 'Заставки на переходах',
|
||||
bumpersHint: 'Короткая заставка «Сейчас / Далее» между разными шоу',
|
||||
bumperSelection: 'Выбор блока',
|
||||
bumperSelectionRandom: 'Случайно',
|
||||
bumperSelectionWeighted: 'Случайно взвешенный',
|
||||
bumperSelectionAlwaysFirst: 'Всегда первый',
|
||||
bumperFont: 'Шрифт',
|
||||
bumperFontSans: 'Гротеск',
|
||||
bumperFontSerif: 'Антиква',
|
||||
bumperNowLabel: 'Подпись «Сейчас»',
|
||||
bumperNextLabel: 'Подпись «Далее»',
|
||||
bumperBg: 'Фон (цвет 1)',
|
||||
bumperBg2: 'Фон (цвет 2)',
|
||||
bumperAccent: 'Акцент',
|
||||
bumperText: 'Текст',
|
||||
bumperTemplates: 'Блоки заставок',
|
||||
bumperTemplatesHint:
|
||||
'Каждый блок — свой звук и оформление. Первый блок дефолтный, его нельзя удалить. Длительность заставки — по длине звука.',
|
||||
bumperAddTemplate: 'Добавить блок',
|
||||
bumperTemplateName: 'Название',
|
||||
bumperVariants: 'Подблоки (текст)',
|
||||
bumperVariantsHint:
|
||||
'Разный текст на одной музыке и оформлении блока. Правило показа — у каждого подблока своё.',
|
||||
bumperAddVariant: 'Добавить текст',
|
||||
bumperVariantName: 'Название',
|
||||
bumperTextKind: 'Режим текста',
|
||||
bumperKindNowNext: 'Сейчас / Далее',
|
||||
bumperKindFree: 'Свободный текст',
|
||||
bumperLine1: 'Строка 1',
|
||||
bumperLine2: 'Строка 2',
|
||||
bumperTrigger: 'Показывать',
|
||||
bumperTriggerOnShowChange: 'При смене шоу',
|
||||
bumperTriggerBetweenEpisodes: 'Между сериями',
|
||||
bumperTriggerBoth: 'Оба',
|
||||
bumperVariantWeight: 'Вес',
|
||||
bumperVariantWeightHint:
|
||||
'Для стратегии «случайно взвешенный»: чем больше — тем чаще (0 — не выбирается)',
|
||||
bumperDefault: 'по умолчанию',
|
||||
bumperSeconds: 'с',
|
||||
bumperDefaultDuration: '≈8 с (джингл)',
|
||||
bumperAudio: 'Звук',
|
||||
bumperAudioHint: 'Звук заставки; иначе — синтезированный джингл',
|
||||
bumperPreview: 'Отрендерить примеры',
|
||||
bumperPreviewRendering: 'Рендерим…',
|
||||
bumperPreviewHint:
|
||||
'Примеры всех подблоков со звуком и анимацией (примерные названия шоу). Использует сохранённые настройки.',
|
||||
bumperBackground: 'Фон-картинка',
|
||||
bumperBackgroundHint: 'Картинка фона; иначе — постер шоу или градиент',
|
||||
bumperBackgroundPick: 'Выбрать из галереи',
|
||||
bumperFileLoaded: 'загружено',
|
||||
bumperFileDefault: 'по умолчанию',
|
||||
bumperUpload: 'Загрузить',
|
||||
bumperReset: 'Сбросить',
|
||||
filler: 'Заглушка',
|
||||
noFiller: 'Без заглушки',
|
||||
noSchedule: 'Расписание ещё не построено',
|
||||
},
|
||||
junctions: {
|
||||
title: 'Стыки',
|
||||
hint: 'Что играет между программами: реклама, анонсы, заставки. Стык общий для всех каналов — канал только выбирает, какой поставить в слот.',
|
||||
newName: 'Новый стык',
|
||||
empty0: 'Стыков пока нет.',
|
||||
empty: 'пусто',
|
||||
from: 'конец',
|
||||
to: 'начало',
|
||||
fork: 'развилка',
|
||||
addElement: '+ врезка',
|
||||
maxTotal: 'Потолок, с',
|
||||
usedInChannels: 'в каналах: {{count}}',
|
||||
cannotDeleteUsed: 'Стык используется каналами — сначала снимите ссылки.',
|
||||
splitOut: 'Вынести из развилки',
|
||||
mergeIntoFork: 'Объединить с предыдущей в развилку',
|
||||
element: 'Врезка',
|
||||
kind: 'Тип',
|
||||
kinds: {
|
||||
Ad: 'Реклама',
|
||||
Promo: 'Анонс',
|
||||
Bumper: 'Заставка',
|
||||
Filler: 'Заполнитель',
|
||||
},
|
||||
group: 'Группа',
|
||||
pickGroup: 'выберите группу',
|
||||
bumperTemplate: 'Блок заставки',
|
||||
pickBumper: 'выберите блок',
|
||||
bumperVariant: 'Подблок',
|
||||
bumperVariantAuto: 'по триггеру и весам',
|
||||
bumperVariantHint:
|
||||
'Оставьте «по триггеру и весам», чтобы на смене шоу и между сериями играли разные тексты.',
|
||||
amountMode: 'Чем меряется',
|
||||
amountModes: { Count: 'Единиц', Duration: 'Минут' },
|
||||
count: 'Сколько единиц',
|
||||
minutes: 'Сколько минут',
|
||||
minutesShort: ' мин',
|
||||
amountHint:
|
||||
'В смешанной группе (ролики и готовые блоки) считайте минутами: одна «единица» там — то ли ролик, то ли блок.',
|
||||
required: 'Обязательная',
|
||||
requiredHint:
|
||||
'Обязательность решает, кого выбросить при нехватке времени. На порядок показа она не влияет — он задаётся местом в цепочке.',
|
||||
choiceWeight: 'Вес в развилке',
|
||||
choiceWeightHint: 'Чем больше — тем чаще играет именно эта врезка (0 — не выбирается).',
|
||||
conditions: 'Условия показа',
|
||||
onlyOnChange: 'Только при смене шоу',
|
||||
chance: 'Вероятность, %',
|
||||
chanceHint:
|
||||
'Вероятность и интервал считаются по этой врезке отдельно; жребий берётся из seed генерации, поэтому пересборка не тасует врезки.',
|
||||
minInterval: 'Не чаще, чем раз в, мин',
|
||||
dayparts: 'Дейпарты',
|
||||
daypartsHint: 'Ничего не выбрано — врезка идёт в любых дейпартах.',
|
||||
timeWindow: 'Окно суток канала',
|
||||
clearWindow: 'Сбросить',
|
||||
timeWindowHint: 'Пусто — в любое время. Окно может переходить через полночь.',
|
||||
badgeOnChange: 'на смене',
|
||||
badgeInterval: 'раз в {{minutes}} мин',
|
||||
},
|
||||
bumpers: {
|
||||
title: 'Заставки',
|
||||
hint: 'Блоки заставок общие для всех каналов: оформление и звук — у блока, текст — у подблоков. В эфир заставка попадает врезкой стыка.',
|
||||
empty: 'Блоков заставок пока нет.',
|
||||
newName: 'Новый блок',
|
||||
newNamePlaceholder: 'Название блока',
|
||||
newVariantName: 'Новый текст',
|
||||
sampleChannel: 'Смотреть глазами канала',
|
||||
sampleChannelNone: 'без канала',
|
||||
sampleChannelHint: 'Блок общий, но образцы подстановки берутся у выбранного канала.',
|
||||
name: 'Название',
|
||||
font: 'Шрифт',
|
||||
fontSans: 'Гротеск',
|
||||
fontSerif: 'Антиква',
|
||||
colorBg: 'Фон (цвет 1)',
|
||||
colorBg2: 'Фон (цвет 2)',
|
||||
colorAccent: 'Акцент',
|
||||
colorText: 'Текст',
|
||||
saveStyle: 'Сохранить оформление',
|
||||
seconds: 'с',
|
||||
defaultDuration: '≈8 с (джингл)',
|
||||
variantsCount: 'текстов: {{count}}',
|
||||
usedInJunctions: 'во врезках: {{count}}',
|
||||
cannotDeleteUsed: 'Блок используется во врезках стыков — сначала снимите ссылки.',
|
||||
audio: 'Звук',
|
||||
audioHint: 'Длина звука задаёт длительность заставки; без него — синтезированный джингл.',
|
||||
background: 'Фон',
|
||||
backgroundFieldHint: 'Картинка фона блока; иначе — градиент палитры или постер шоу.',
|
||||
backgroundPick: 'Выбрать из галереи',
|
||||
backgrounds: {
|
||||
Template: 'Фон блока',
|
||||
NextPoster: 'Постер следующего шоу',
|
||||
NowPoster: 'Постер предыдущего шоу',
|
||||
},
|
||||
fileLoaded: 'загружено',
|
||||
fileDefault: 'по умолчанию',
|
||||
upload: 'Загрузить',
|
||||
reset: 'Сбросить',
|
||||
variants: 'Подблоки (тексты)',
|
||||
variantsHint:
|
||||
'Разный текст на одной музыке и оформлении. Правило показа и фон — у каждого подблока свои.',
|
||||
addVariant: 'Добавить текст',
|
||||
variantName: 'Название',
|
||||
trigger: 'Показывать',
|
||||
triggers: {
|
||||
OnShowChange: 'При смене шоу',
|
||||
BetweenEpisodes: 'Между сериями',
|
||||
Both: 'Оба',
|
||||
},
|
||||
weight: 'Вес',
|
||||
lineStyles: { Label: 'Подпись', Title: 'Название', Caption: 'Мелкая' },
|
||||
lineColors: { Accent: 'Акцент', Text: 'Текст' },
|
||||
addLine: 'Строка',
|
||||
presets: 'Пресеты',
|
||||
preset_nowNext: 'Сейчас / Далее',
|
||||
preset_nextAt: 'Далее в …',
|
||||
preset_channel: 'Логотип канала',
|
||||
presetNow: 'СЕЙЧАС',
|
||||
presetNext: 'ДАЛЕЕ',
|
||||
presetNextAt: 'ДАЛЕЕ В',
|
||||
framePreview: 'Кадр',
|
||||
framePreviewHint: 'Подстановка образцами: так строка будет выглядеть в эфире.',
|
||||
unknownPlaceholder: 'Неизвестный плейсхолдер: {{tokens}}',
|
||||
volatileHint: 'каждый показ уникален — кэш рендера не работает',
|
||||
render: 'Отрендерить примеры',
|
||||
rendering: 'Рендерим…',
|
||||
renderHint: 'Настоящий ffmpeg-рендер всех подблоков со звуком — несколько секунд.',
|
||||
tokens: {
|
||||
channel: 'Название канала',
|
||||
'channel.number': 'Номер канала',
|
||||
'now.title': 'Текущее шоу',
|
||||
'next.title': 'Следующее шоу',
|
||||
'now.episode': 'Серия текущего',
|
||||
'next.episode': 'Серия следующего',
|
||||
'next.year': 'Год следующего',
|
||||
'next.genre': 'Жанр следующего',
|
||||
'next.time': 'Время старта следующего',
|
||||
time: 'Время показа заставки',
|
||||
date: 'Дата',
|
||||
weekday: 'День недели',
|
||||
slot: 'Название слота',
|
||||
},
|
||||
},
|
||||
maintenance: {
|
||||
title: 'Обслуживание',
|
||||
warning: 'Операции необратимы — удаляют данные и файлы навсегда.',
|
||||
|
||||
Reference in New Issue
Block a user