struct AudioBlock: KeyedBlockProcessor { enum Key: String { case name case artist case album case file case cover } static let blockId: ContentBlock = .audio let content: Content let results: PageGenerationResults let language: ContentLanguage init(content: Content, results: PageGenerationResults, language: ContentLanguage) { self.content = content self.results = results self.language = language } func process(_ arguments: [Key : String], markdown: Substring) -> String { guard let name = arguments[.name], let artist = arguments[.artist], let album = arguments[.album], let fileId = arguments[.file], let cover = arguments[.cover] else { invalid(markdown) return "" } guard let image = content.image(cover) else { results.missing(file: cover, source: "Audio Block") return "" } guard let file = content.file(fileId) else { results.missing(file: fileId, source: "Audio Block") return "" } let coverSize = 2 * content.settings.audioPlayer.smallCoverImageSize let coverImage = image.imageVersion(width: coverSize, height: coverSize, type: image.type) let footer = SingleFilePlayer.footer( name: name, artist: artist, album: album, url: file.absoluteUrl, cover: coverImage.outputPath) results.require(file: file) results.require(image: coverImage) results.require(footer: footer) results.require(headers: .audioPlayerJs, .audioPlayerCss) results.require(icons: .audioPlayerPlay, .audioPlayerPause) return SingleFilePlayer().content } }