Make video_sources optional for div-video

commit_hash:93f331ca17fa8a0ac8f9f794b9276810781d2700
This commit is contained in:
denlvovich
2026-03-16 16:50:19 +03:00
parent abb6ae5ade
commit 0a6ebe80a3
5 changed files with 25 additions and 36 deletions
@@ -19,6 +19,12 @@ extension DivVideo: DivBlockModeling {
return EmptyBlock()
}
if videoSources == nil, playerSettingsPayload == nil {
context.addError(
message: "Neither 'video_sources' nor 'player_settings_payload' are specified for video with id: '\(id ?? "null")'."
)
}
let resumeActions = resumeActions?.uiActions(context: context) ?? []
let pauseActions = pauseActions?.uiActions(context: context) ?? []
let bufferingActions = bufferingActions?.uiActions(context: context) ?? []
@@ -33,7 +39,9 @@ extension DivVideo: DivBlockModeling {
context.makeBinding(variableName: $0, defaultValue: 0)
}
let preview: Image? = resolvePreview(resolver).flatMap(_makeImage(base64:))
let videoData = VideoData(videos: videoSources.compactMap { $0.makeVideo(resolver: resolver) })
let videoData = VideoData(videos: videoSources?
.compactMap { $0.makeVideo(resolver: resolver) } ?? []
)
let playbackConfig = PlaybackConfig(
autoPlay: autostart,
@@ -131,7 +131,7 @@ extension DivText.Image: ResourceDiv {
extension DivVideo: ResourceDiv {
func resolvePreloadURLs(_ resolver: ExpressionResolver) -> [URL?] {
videoSources.map { $0.resolveUrl(resolver) }
videoSources?.map { $0.resolveUrl(resolver) } ?? []
}
}
@@ -49,7 +49,7 @@ public final class DivVideo: DivBase, @unchecked Sendable {
public let transitionTriggers: [DivTransitionTrigger]? // at least 1 elements
public let variableTriggers: [DivTrigger]?
public let variables: [DivVariable]?
public let videoSources: [DivVideoSource] // at least 1 elements
public let videoSources: [DivVideoSource]?
public let visibility: Expression<DivVisibility> // default value: visible
public let visibilityAction: DivVisibilityAction?
public let visibilityActions: [DivVisibilityAction]?
@@ -123,9 +123,6 @@ public final class DivVideo: DivBase, @unchecked Sendable {
static let transitionTriggersValidator: AnyArrayValueValidator<DivTransitionTrigger> =
makeArrayValidator(minItems: 1)
static let videoSourcesValidator: AnyArrayValueValidator<DivVideoSource> =
makeArrayValidator(minItems: 1)
public convenience init(dictionary: [String: Any], context: ParsingContext) throws {
self.init(
accessibility: try dictionary.getOptionalField("accessibility", transform: { (dict: [String: Any]) in try DivAccessibility(dictionary: dict, context: context) }),
@@ -171,7 +168,7 @@ public final class DivVideo: DivBase, @unchecked Sendable {
transitionTriggers: try dictionary.getOptionalArray("transition_triggers", validator: Self.transitionTriggersValidator, context: context),
variableTriggers: try dictionary.getOptionalArray("variable_triggers", transform: { (dict: [String: Any]) in try? DivTrigger(dictionary: dict, context: context) }),
variables: try dictionary.getOptionalArray("variables", transform: { (dict: [String: Any]) in try? DivVariable(dictionary: dict, context: context) }),
videoSources: try dictionary.getArray("video_sources", transform: { (dict: [String: Any]) in try? DivVideoSource(dictionary: dict, context: context) }, validator: Self.videoSourcesValidator, context: context),
videoSources: try dictionary.getOptionalArray("video_sources", transform: { (dict: [String: Any]) in try? DivVideoSource(dictionary: dict, context: context) }),
visibility: try dictionary.getOptionalExpressionField("visibility", context: context),
visibilityAction: try dictionary.getOptionalField("visibility_action", transform: { (dict: [String: Any]) in try DivVisibilityAction(dictionary: dict, context: context) }),
visibilityActions: try dictionary.getOptionalArray("visibility_actions", transform: { (dict: [String: Any]) in try? DivVisibilityAction(dictionary: dict, context: context) }),
@@ -223,7 +220,7 @@ public final class DivVideo: DivBase, @unchecked Sendable {
transitionTriggers: [DivTransitionTrigger]? = nil,
variableTriggers: [DivTrigger]? = nil,
variables: [DivVariable]? = nil,
videoSources: [DivVideoSource],
videoSources: [DivVideoSource]? = nil,
visibility: Expression<DivVisibility>? = nil,
visibilityAction: DivVisibilityAction? = nil,
visibilityActions: [DivVisibilityAction]? = nil,
@@ -448,7 +445,7 @@ extension DivVideo: Serializable {
result["transition_triggers"] = transitionTriggers?.map { $0.rawValue }
result["variable_triggers"] = variableTriggers?.map { $0.toDictionary() }
result["variables"] = variables?.map { $0.toDictionary() }
result["video_sources"] = videoSources.map { $0.toDictionary() }
result["video_sources"] = videoSources?.map { $0.toDictionary() }
result["visibility"] = visibility.toValidSerializationValue()
result["visibility_action"] = visibilityAction?.toDictionary()
result["visibility_actions"] = visibilityActions?.map { $0.toDictionary() }
@@ -50,7 +50,7 @@ public final class DivVideoTemplate: TemplateValue, @unchecked Sendable {
public let transitionTriggers: Field<[DivTransitionTrigger]>? // at least 1 elements
public let variableTriggers: Field<[DivTriggerTemplate]>?
public let variables: Field<[DivVariableTemplate]>?
public let videoSources: Field<[DivVideoSourceTemplate]>? // at least 1 elements
public let videoSources: Field<[DivVideoSourceTemplate]>?
public let visibility: Field<Expression<DivVisibility>>? // default value: visible
public let visibilityAction: Field<DivVisibilityActionTemplate>?
public let visibilityActions: Field<[DivVisibilityActionTemplate]>?
@@ -256,12 +256,12 @@ public final class DivVideoTemplate: TemplateValue, @unchecked Sendable {
let transitionTriggersValue = parent?.transitionTriggers?.resolveOptionalValue(context: context, validator: ResolvedValue.transitionTriggersValidator) ?? .noValue
let variableTriggersValue = parent?.variableTriggers?.resolveOptionalValue(context: context, useOnlyLinks: true) ?? .noValue
let variablesValue = parent?.variables?.resolveOptionalValue(context: context, useOnlyLinks: true) ?? .noValue
let videoSourcesValue = parent?.videoSources?.resolveValue(context: context, validator: ResolvedValue.videoSourcesValidator, useOnlyLinks: true) ?? .noValue
let videoSourcesValue = parent?.videoSources?.resolveOptionalValue(context: context, useOnlyLinks: true) ?? .noValue
let visibilityValue = parent?.visibility?.resolveOptionalValue(context: context) ?? .noValue
let visibilityActionValue = parent?.visibilityAction?.resolveOptionalValue(context: context, useOnlyLinks: true) ?? .noValue
let visibilityActionsValue = parent?.visibilityActions?.resolveOptionalValue(context: context, useOnlyLinks: true) ?? .noValue
let widthValue = parent?.width?.resolveOptionalValue(context: context, useOnlyLinks: true) ?? .noValue
var errors = mergeErrors(
let errors = mergeErrors(
accessibilityValue.errorsOrWarnings?.map { .nestedObjectError(field: "accessibility", error: $0) },
alignmentHorizontalValue.errorsOrWarnings?.map { .nestedObjectError(field: "alignment_horizontal", error: $0) },
alignmentVerticalValue.errorsOrWarnings?.map { .nestedObjectError(field: "alignment_vertical", error: $0) },
@@ -311,14 +311,6 @@ public final class DivVideoTemplate: TemplateValue, @unchecked Sendable {
visibilityActionsValue.errorsOrWarnings?.map { .nestedObjectError(field: "visibility_actions", error: $0) },
widthValue.errorsOrWarnings?.map { .nestedObjectError(field: "width", error: $0) }
)
if case .noValue = videoSourcesValue {
errors.append(.requiredFieldIsMissing(field: "video_sources"))
}
guard
let videoSourcesNonNil = videoSourcesValue.value
else {
return .failure(NonEmptyArray(errors)!)
}
let result = DivVideo(
accessibility: accessibilityValue.value,
alignmentHorizontal: alignmentHorizontalValue.value,
@@ -363,7 +355,7 @@ public final class DivVideoTemplate: TemplateValue, @unchecked Sendable {
transitionTriggers: transitionTriggersValue.value,
variableTriggers: variableTriggersValue.value,
variables: variablesValue.value,
videoSources: videoSourcesNonNil,
videoSources: videoSourcesValue.value,
visibility: visibilityValue.value,
visibilityAction: visibilityActionValue.value,
visibilityActions: visibilityActionsValue.value,
@@ -513,7 +505,7 @@ public final class DivVideoTemplate: TemplateValue, @unchecked Sendable {
case "variables":
variablesValue = deserialize(__dictValue, templates: context.templates, templateToType: context.templateToType, type: DivVariableTemplate.self).merged(with: variablesValue)
case "video_sources":
videoSourcesValue = deserialize(__dictValue, templates: context.templates, templateToType: context.templateToType, validator: ResolvedValue.videoSourcesValidator, type: DivVideoSourceTemplate.self).merged(with: videoSourcesValue)
videoSourcesValue = deserialize(__dictValue, templates: context.templates, templateToType: context.templateToType, type: DivVideoSourceTemplate.self).merged(with: videoSourcesValue)
case "visibility":
visibilityValue = deserialize(__dictValue).merged(with: visibilityValue)
case "visibility_action":
@@ -609,7 +601,7 @@ public final class DivVideoTemplate: TemplateValue, @unchecked Sendable {
case parent?.variables?.link:
variablesValue = variablesValue.merged(with: { deserialize(__dictValue, templates: context.templates, templateToType: context.templateToType, type: DivVariableTemplate.self) })
case parent?.videoSources?.link:
videoSourcesValue = videoSourcesValue.merged(with: { deserialize(__dictValue, templates: context.templates, templateToType: context.templateToType, validator: ResolvedValue.videoSourcesValidator, type: DivVideoSourceTemplate.self) })
videoSourcesValue = videoSourcesValue.merged(with: { deserialize(__dictValue, templates: context.templates, templateToType: context.templateToType, type: DivVideoSourceTemplate.self) })
case parent?.visibility?.link:
visibilityValue = visibilityValue.merged(with: { deserialize(__dictValue) })
case parent?.visibilityAction?.link:
@@ -649,12 +641,12 @@ public final class DivVideoTemplate: TemplateValue, @unchecked Sendable {
_ = transitionOutValue = transitionOutValue.merged(with: { parent.transitionOut?.resolveOptionalValue(context: context, useOnlyLinks: true) })
_ = variableTriggersValue = variableTriggersValue.merged(with: { parent.variableTriggers?.resolveOptionalValue(context: context, useOnlyLinks: true) })
_ = variablesValue = variablesValue.merged(with: { parent.variables?.resolveOptionalValue(context: context, useOnlyLinks: true) })
_ = videoSourcesValue = videoSourcesValue.merged(with: { parent.videoSources?.resolveValue(context: context, validator: ResolvedValue.videoSourcesValidator, useOnlyLinks: true) })
_ = videoSourcesValue = videoSourcesValue.merged(with: { parent.videoSources?.resolveOptionalValue(context: context, useOnlyLinks: true) })
_ = visibilityActionValue = visibilityActionValue.merged(with: { parent.visibilityAction?.resolveOptionalValue(context: context, useOnlyLinks: true) })
_ = visibilityActionsValue = visibilityActionsValue.merged(with: { parent.visibilityActions?.resolveOptionalValue(context: context, useOnlyLinks: true) })
_ = widthValue = widthValue.merged(with: { parent.width?.resolveOptionalValue(context: context, useOnlyLinks: true) })
}
var errors = mergeErrors(
let errors = mergeErrors(
accessibilityValue.errorsOrWarnings?.map { .nestedObjectError(field: "accessibility", error: $0) },
alignmentHorizontalValue.errorsOrWarnings?.map { .nestedObjectError(field: "alignment_horizontal", error: $0) },
alignmentVerticalValue.errorsOrWarnings?.map { .nestedObjectError(field: "alignment_vertical", error: $0) },
@@ -704,14 +696,6 @@ public final class DivVideoTemplate: TemplateValue, @unchecked Sendable {
visibilityActionsValue.errorsOrWarnings?.map { .nestedObjectError(field: "visibility_actions", error: $0) },
widthValue.errorsOrWarnings?.map { .nestedObjectError(field: "width", error: $0) }
)
if case .noValue = videoSourcesValue {
errors.append(.requiredFieldIsMissing(field: "video_sources"))
}
guard
let videoSourcesNonNil = videoSourcesValue.value
else {
return .failure(NonEmptyArray(errors)!)
}
let result = DivVideo(
accessibility: accessibilityValue.value,
alignmentHorizontal: alignmentHorizontalValue.value,
@@ -756,7 +740,7 @@ public final class DivVideoTemplate: TemplateValue, @unchecked Sendable {
transitionTriggers: transitionTriggersValue.value,
variableTriggers: variableTriggersValue.value,
variables: variablesValue.value,
videoSources: videoSourcesNonNil,
videoSources: videoSourcesValue.value,
visibility: visibilityValue.value,
visibilityAction: visibilityActionValue.value,
visibilityActions: visibilityActionsValue.value,
@@ -873,7 +857,7 @@ public final class DivVideoTemplate: TemplateValue, @unchecked Sendable {
transitionTriggers: merged.transitionTriggers,
variableTriggers: merged.variableTriggers?.tryResolveParent(templates: templates),
variables: merged.variables?.tryResolveParent(templates: templates),
videoSources: try merged.videoSources?.resolveParent(templates: templates),
videoSources: merged.videoSources?.tryResolveParent(templates: templates),
visibility: merged.visibility,
visibilityAction: merged.visibilityAction?.tryResolveParent(templates: templates),
visibilityActions: merged.visibilityActions?.tryResolveParent(templates: templates),
@@ -591,7 +591,7 @@ public func solidBackground(_ color: RGBAColor) -> DivBackground {
public func divVideo(
id: String? = nil,
videoSources: [DivVideoSource],
videoSources: [DivVideoSource]?,
preloadRequired: Bool? = nil,
preloadRequiredExpression: String? = nil
) -> Div {