175 lines
5.5 KiB
Swift
175 lines
5.5 KiB
Swift
import Foundation
|
|
|
|
final class LocalizedWebsiteGenerator {
|
|
|
|
let language: ContentLanguage
|
|
|
|
private let localizedPostSettings: LocalizedPostSettings
|
|
|
|
private var outputDirectory: URL {
|
|
content.settings.outputDirectory
|
|
}
|
|
|
|
private var postsPerPage: Int {
|
|
content.settings.posts.postsPerPage
|
|
}
|
|
|
|
private var mainContentMaximumWidth: CGFloat {
|
|
CGFloat(content.settings.posts.contentWidth)
|
|
}
|
|
|
|
private let content: Content
|
|
|
|
private let imageGenerator: ImageGenerator
|
|
|
|
private var navigationBarLinks: [NavigationBar.Link] {
|
|
content.settings.navigationTags.map {
|
|
let localized = $0.localized(in: language)
|
|
return .init(text: localized.name, url: content.absoluteUrlToTag($0, language: language))
|
|
}
|
|
}
|
|
|
|
init(content: Content, language: ContentLanguage) {
|
|
self.language = language
|
|
self.content = content
|
|
self.localizedPostSettings = content.settings.localized(in: language)
|
|
self.imageGenerator = ImageGenerator(
|
|
storage: content.storage,
|
|
relativeImageOutputPath: content.settings.paths.imagesOutputFolderPath)
|
|
}
|
|
|
|
func generateWebsite(callback: (String) -> Void) -> Bool {
|
|
guard imageGenerator.prepareForGeneration() else {
|
|
return false
|
|
}
|
|
guard createMainPostFeedPages() else {
|
|
return false
|
|
}
|
|
#warning("Generate content pages")
|
|
guard generateTagPages() else {
|
|
return false
|
|
}
|
|
guard imageGenerator.runJobs(callback: callback) else {
|
|
return false
|
|
}
|
|
return imageGenerator.save()
|
|
}
|
|
|
|
private func createMainPostFeedPages() -> Bool {
|
|
let generator = PostListPageGenerator(
|
|
language: language,
|
|
content: content,
|
|
imageGenerator: imageGenerator,
|
|
navigationBarLinks: navigationBarLinks,
|
|
showTitle: false,
|
|
pageTitle: localizedPostSettings.title,
|
|
pageDescription: localizedPostSettings.description,
|
|
pageUrlPrefix: localizedPostSettings.feedUrlPrefix)
|
|
return generator.createPages(for: content.posts)
|
|
}
|
|
|
|
private func generateTagPages() -> Bool {
|
|
for tag in content.tags {
|
|
let posts = content.posts.filter { $0.tags.contains(tag) }
|
|
guard posts.count > 0 else { continue }
|
|
|
|
let localized = tag.localized(in: language)
|
|
|
|
let urlPrefix = content.absoluteUrlPrefixForTag(tag, language: language)
|
|
|
|
let generator = PostListPageGenerator(
|
|
language: language,
|
|
content: content,
|
|
imageGenerator: imageGenerator,
|
|
navigationBarLinks: navigationBarLinks,
|
|
showTitle: true,
|
|
pageTitle: localized.name,
|
|
pageDescription: localized.description ?? "",
|
|
pageUrlPrefix: urlPrefix)
|
|
guard generator.createPages(for: posts) else {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
private func generatePagesFolderIfNeeded() -> Bool {
|
|
let relativePath = content.settings.pages.pageUrlPrefix
|
|
|
|
return content.storage.write(in: .outputPath) { folder in
|
|
let outputFile = folder.appendingPathComponent(relativePath, isDirectory: true)
|
|
do {
|
|
try outputFile.ensureFolderExistence()
|
|
return true
|
|
} catch {
|
|
return false
|
|
}
|
|
}
|
|
}
|
|
|
|
func generate(page: Page) -> Bool {
|
|
guard generatePagesFolderIfNeeded() else {
|
|
print("Failed to generate output folder")
|
|
return false
|
|
}
|
|
let pageGenerator = PageGenerator(
|
|
content: content,
|
|
imageGenerator: imageGenerator,
|
|
navigationBarLinks: navigationBarLinks)
|
|
|
|
let content: String
|
|
let results: PageGenerationResults
|
|
do {
|
|
(content, results) = try pageGenerator.generate(page: page, language: language)
|
|
} catch {
|
|
print("Failed to generate page \(page.id) in language \(language): \(error)")
|
|
return false
|
|
}
|
|
guard !content.trimmed.isEmpty else {
|
|
#warning("Generate page with placeholder content")
|
|
return true
|
|
}
|
|
|
|
let path = self.content.absoluteUrlToPage(page, language: language) + ".html"
|
|
guard save(content, to: path) else {
|
|
print("Failed to save page")
|
|
return false
|
|
}
|
|
guard imageGenerator.runJobs(callback: { _ in }) else {
|
|
return false
|
|
}
|
|
guard copy(requiredFiles: results.files) else {
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
private func copy(requiredFiles: Set<FileResource>) -> Bool {
|
|
//print("Copying \(requiredVideoFiles.count) files...")
|
|
for file in requiredFiles {
|
|
guard !file.isExternallyStored else {
|
|
continue
|
|
}
|
|
|
|
let outputPath = content.absoluteUrlToFile(file)
|
|
do {
|
|
try content.storage.copy(file: file.id, to: outputPath)
|
|
} catch {
|
|
print("Failed to copy file \(file.id): \(error)")
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
private func save(_ content: String, to relativePath: String) -> Bool {
|
|
do {
|
|
try self.content.storage.write(content: content, to: relativePath)
|
|
return true
|
|
} catch {
|
|
print("Failed to write page \(relativePath)")
|
|
return false
|
|
}
|
|
}
|
|
}
|