283 lines
8.6 KiB
Swift
283 lines
8.6 KiB
Swift
import Foundation
|
|
|
|
extension Content {
|
|
|
|
func generateWebsiteInAllLanguages() {
|
|
performGenerationIfIdle {
|
|
self.generatePagesInternal()
|
|
self.generatePostFeedPagesInternal()
|
|
self.generateTagPagesInternal()
|
|
self.generateTagOverviewPagesInternal()
|
|
|
|
self.copyRequiredFiles()
|
|
self.generateRequiredImages()
|
|
self.status("Generation completed")
|
|
}
|
|
}
|
|
|
|
func endCurrentGeneration() {
|
|
guard isGeneratingWebsite, shouldGenerateWebsite else {
|
|
return
|
|
}
|
|
DispatchQueue.main.async {
|
|
self.set(shouldGenerate: false)
|
|
}
|
|
}
|
|
|
|
func generatePostFeedPages() {
|
|
performGenerationIfIdle {
|
|
self.generatePostFeedPagesInternal()
|
|
}
|
|
}
|
|
|
|
func check(content: String, of page: Page, for language: ContentLanguage, onComplete: @escaping (PageGenerationResults) -> Void) {
|
|
performGenerationIfIdle {
|
|
let results = self.results.makeResults(for: page, in: language)
|
|
let generator = PageContentParser(content: page.content, language: language, results: results)
|
|
_ = generator.generatePage(from: content)
|
|
DispatchQueue.main.async {
|
|
onComplete(results)
|
|
}
|
|
}
|
|
}
|
|
|
|
private func copyRequiredFiles() {
|
|
let count = results.requiredFiles.count
|
|
var completed = 0
|
|
for file in results.requiredFiles {
|
|
guard shouldGenerateWebsite else { return }
|
|
defer {
|
|
completed += 1
|
|
status("Copying required files: \(completed) / \(count)")
|
|
}
|
|
guard !file.isExternallyStored else {
|
|
continue
|
|
}
|
|
let path = file.absoluteUrl
|
|
if !storage.copy(file: file.id, to: path) {
|
|
results.general.unsavedOutput(path, source: .general)
|
|
}
|
|
}
|
|
}
|
|
|
|
private func generateRequiredImages() {
|
|
let imageGenerator = ImageGenerator(
|
|
storage: storage,
|
|
settings: settings)
|
|
|
|
let images = results.imagesToGenerate.sorted()
|
|
let count = images.count
|
|
var completed = 0
|
|
for image in images {
|
|
guard shouldGenerateWebsite else { return }
|
|
defer {
|
|
completed += 1
|
|
status("Generating required images: \(completed) / \(count)")
|
|
}
|
|
if imageGenerator.generate(version: image) {
|
|
continue
|
|
}
|
|
results.failed(image: image)
|
|
}
|
|
|
|
imageGenerator.save()
|
|
imageGenerator.printAvifCommands()
|
|
//let images = Set(self.images.map { $0.id })
|
|
//imageGenerator.recalculateGeneratedImages(by: images)
|
|
}
|
|
|
|
func generateAllPages() {
|
|
performGenerationIfIdle {
|
|
self.generatePagesInternal()
|
|
}
|
|
}
|
|
|
|
func generatePage(_ page: Page) {
|
|
performGenerationIfIdle {
|
|
for language in ContentLanguage.allCases {
|
|
self.generateInternal(page, in: language)
|
|
}
|
|
self.copyRequiredFiles()
|
|
self.generateRequiredImages()
|
|
}
|
|
}
|
|
|
|
func generatePage(_ page: Page, in language: ContentLanguage) {
|
|
performGenerationIfIdle {
|
|
self.generateInternal(page, in: language)
|
|
}
|
|
}
|
|
|
|
// MARK: Find items by id
|
|
|
|
func page(_ pageId: String) -> Page? {
|
|
pages.first { $0.id == pageId }
|
|
}
|
|
|
|
func image(_ imageId: String) -> FileResource? {
|
|
files.first { $0.id == imageId && $0.type.isImage }
|
|
}
|
|
|
|
func video(_ videoId: String) -> FileResource? {
|
|
files.first { $0.id == videoId && $0.type.isVideo }
|
|
}
|
|
|
|
func file(_ fileId: String) -> FileResource? {
|
|
files.first { $0.id == fileId }
|
|
}
|
|
|
|
func tag(_ tagId: String) -> Tag? {
|
|
tags.first { $0.id == tagId }
|
|
}
|
|
|
|
// MARK: Generation input
|
|
|
|
func navigationBar(in language: ContentLanguage) -> [NavigationBar.Link] {
|
|
settings.navigation.navigationItems.map {
|
|
.init(text: $0.title(in: language),
|
|
url: $0.absoluteUrl(in: language))
|
|
}
|
|
}
|
|
|
|
var defaultPageHeaders: Set<HeaderElement> {
|
|
var result: Set<HeaderElement> = [.charset, .viewport]
|
|
if let defaultCss = settings.posts.defaultCssFile {
|
|
result.insert(.css(file: defaultCss, order: HeaderElement.defaultCssFileOrder))
|
|
}
|
|
return result
|
|
}
|
|
|
|
// MARK: Generation
|
|
|
|
private func performGenerationIfIdle(_ operation: @escaping () -> ()) {
|
|
DispatchQueue.main.async {
|
|
guard !self.isGeneratingWebsite else {
|
|
return
|
|
}
|
|
self.set(isGenerating: true)
|
|
self.set(shouldGenerate: true)
|
|
DispatchQueue.global(qos: .userInitiated).async {
|
|
operation()
|
|
DispatchQueue.main.async {
|
|
self.set(isGenerating: false)
|
|
self.set(shouldGenerate: false)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private func status(_ message: String) {
|
|
DispatchQueue.main.async {
|
|
self.generationStatus = message
|
|
}
|
|
}
|
|
|
|
/**
|
|
- Note: Run on background thread
|
|
*/
|
|
private func generatePagesInternal() {
|
|
let count = pages.count
|
|
for index in pages.indices {
|
|
guard shouldGenerateWebsite else { return }
|
|
let page = pages[index]
|
|
status("Generating pages: \(index) / \(count)")
|
|
guard !page.isExternalUrl else {
|
|
continue
|
|
}
|
|
for language in ContentLanguage.allCases {
|
|
generateInternal(page, in: language)
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
- Note: Run on background thread
|
|
*/
|
|
private func generatePostFeedPagesInternal() {
|
|
status("Generating post feed")
|
|
for language in ContentLanguage.allCases {
|
|
guard shouldGenerateWebsite else { return }
|
|
let results = results.makeResults(for: .feed, in: language)
|
|
let source = FeedGeneratorSource(
|
|
language: language,
|
|
content: self,
|
|
results: results)
|
|
|
|
let generator = PostListPageGenerator(source: source)
|
|
generator.createPages(for: posts)
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
- Note: Run on background thread
|
|
*/
|
|
private func generateTagPagesInternal() {
|
|
let count = tags.count
|
|
for index in tags.indices {
|
|
guard shouldGenerateWebsite else { return }
|
|
let tag = tags[index]
|
|
status("Generating tag pages: \(index) / \(count)")
|
|
generatePagesInternal(for: tag)
|
|
}
|
|
}
|
|
|
|
/**
|
|
- Note: Run on background thread
|
|
*/
|
|
private func generatePagesInternal(for tag: Tag) {
|
|
for language in ContentLanguage.allCases {
|
|
let results = results.makeResults(for: tag, in: language)
|
|
|
|
let posts = posts.filter { $0.tags.contains(tag) }
|
|
guard posts.count > 0 else { continue }
|
|
|
|
let source = TagPageGeneratorSource(
|
|
language: language,
|
|
content: self,
|
|
results: results,
|
|
tag: tag)
|
|
let generator = PostListPageGenerator(source: source)
|
|
generator.createPages(for: posts)
|
|
}
|
|
}
|
|
|
|
/**
|
|
- Note: Run on background thread
|
|
*/
|
|
private func generateTagOverviewPagesInternal() {
|
|
guard let tagOverview else {
|
|
print("Generator: No tag overview page to generate")
|
|
return
|
|
}
|
|
status("Generating tag overview page")
|
|
for language in ContentLanguage.allCases {
|
|
guard shouldGenerateWebsite else { return }
|
|
let results = results.makeResults(for: .tagOverview, in: language)
|
|
let generator = TagOverviewGenerator(content: self, language: language, results: results)
|
|
generator.generatePage(tags: tags, overview: tagOverview)
|
|
}
|
|
}
|
|
|
|
/**
|
|
- Note: Run on background thread
|
|
*/
|
|
private func generateInternal(_ page: Page, in language: ContentLanguage) {
|
|
let results = results.makeResults(for: page, in: language)
|
|
let pageGenerator = PageGenerator(content: self)
|
|
|
|
results.require(files: page.requiredFiles)
|
|
|
|
guard let content = pageGenerator.generate(page: page, language: language, results: results) else {
|
|
print("Failed to generate page \(page.id) in language \(language)")
|
|
return
|
|
}
|
|
|
|
let path = page.absoluteUrl(in: language) + ".html"
|
|
guard storage.write(content, to: path) else {
|
|
print("Failed to save page \(page.id)")
|
|
return
|
|
}
|
|
}
|
|
}
|