Refactor content

This commit is contained in:
Christoph Hagen 2024-11-30 08:44:12 +01:00
parent f1e1538167
commit 0e3fea9b0d
4 changed files with 132 additions and 148 deletions

View File

@ -24,6 +24,7 @@
E218502B2CF790B30090B18B /* PostContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E218502A2CF790AC0090B18B /* PostContentView.swift */; };
E218502D2CF791440090B18B /* PostImagesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E218502C2CF791440090B18B /* PostImagesView.swift */; };
E218502F2CFAF69C0090B18B /* Content+Generate.swift in Sources */ = {isa = PBXBuildFile; fileRef = E218502E2CFAF6990090B18B /* Content+Generate.swift */; };
E21850312CFAF8880090B18B /* Content+Import.swift in Sources */ = {isa = PBXBuildFile; fileRef = E21850302CFAF8840090B18B /* Content+Import.swift */; };
E24252012C50E0A40029FF16 /* HighlightedTextEditor in Frameworks */ = {isa = PBXBuildFile; productRef = E24252002C50E0A40029FF16 /* HighlightedTextEditor */; };
E24252032C5163CF0029FF16 /* Importer.swift in Sources */ = {isa = PBXBuildFile; fileRef = E24252022C5163CF0029FF16 /* Importer.swift */; };
E24252062C51684E0029FF16 /* GenericMetadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = E24252052C51684E0029FF16 /* GenericMetadata.swift */; };
@ -101,6 +102,7 @@
E218502A2CF790AC0090B18B /* PostContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostContentView.swift; sourceTree = "<group>"; };
E218502C2CF791440090B18B /* PostImagesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostImagesView.swift; sourceTree = "<group>"; };
E218502E2CFAF6990090B18B /* Content+Generate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Content+Generate.swift"; sourceTree = "<group>"; };
E21850302CFAF8840090B18B /* Content+Import.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Content+Import.swift"; sourceTree = "<group>"; };
E24252022C5163CF0029FF16 /* Importer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Importer.swift; sourceTree = "<group>"; };
E24252052C51684E0029FF16 /* GenericMetadata.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GenericMetadata.swift; sourceTree = "<group>"; };
E24252072C5168750029FF16 /* GenericMetadata+Localized.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "GenericMetadata+Localized.swift"; sourceTree = "<group>"; };
@ -258,6 +260,7 @@
children = (
E2E06DFA2CA4A6570019C2AF /* Content.swift */,
E218502E2CFAF6990090B18B /* Content+Generate.swift */,
E21850302CFAF8840090B18B /* Content+Import.swift */,
E24252092C52C9260029FF16 /* ContentLanguage.swift */,
E2A21C502CBBD53C0060935B /* FileResource.swift */,
E2A21C3A2CB9D9A50060935B /* ImageResource.swift */,
@ -473,6 +476,7 @@
E2A21C562CBBF9880060935B /* FlexibleColumnView.swift in Sources */,
E2A37D192CEA36A90000979F /* LocalizedTag.swift in Sources */,
E24252062C51684E0029FF16 /* GenericMetadata.swift in Sources */,
E21850312CFAF8880090B18B /* Content+Import.swift in Sources */,
E2A21C462CBAE2E60060935B /* FeedEntryContent.swift in Sources */,
E21850252CF38BCE0090B18B /* TextEntrySheet.swift in Sources */,
E2A37D1D2CEA922D0000979F /* LocalizedPost.swift in Sources */,

View File

@ -2,7 +2,41 @@ import Foundation
extension Content {
func generateWebsite(into folder: URL) throws {
func generateFeed(for language: ContentLanguage, bookmarkKey: String) {
let posts = posts.map { $0.feedEntry(for: language) }
DispatchQueue.global(qos: .userInitiated).async {
let navigationItems: [FeedNavigationLink] = [
.init(text: .init(en: "Projects", de: "Projekte"),
url: .init(en: "/projects", de: "/projekte")),
.init(text: .init(en: "Adventures", de: "Abenteuer"),
url: .init(en: "/adventures", de: "/abenteuer")),
.init(text: .init(en: "Services", de: "Dienste"),
url: .init(en: "/services", de: "/dienste")),
.init(text: .init(en: "Tags", de: "Kategorien"),
url: .init(en: "/tags", de: "/kategorien")),
]
let feed = Feed(
language: language,
title: .init(en: "Blog | CH", de: "Blog | CH"),
description: .init(en: "The latests posts, projects and adventures",
de: "Die neusten Beiträge, Projekte und Abenteuer"),
iconDescription: .init(en: "An icon consisting of the letters C and H in blue and orange",
de: "Ein Logo aus den Buchstaben C und H in Blau und Orange"),
navigationItems: navigationItems,
posts: posts)
let fileContent = feed.content
Content.accessFolderFromBookmark(key: bookmarkKey) { folder in
let outputFile = folder.appendingPathComponent("feed.html", isDirectory: false)
do {
try fileContent
.data(using: .utf8)!
.write(to: outputFile)
} catch {
print("Failed to save: \(error)")
}
}
}
}
}

View File

@ -0,0 +1,63 @@
import Foundation
extension Content {
func importOldContent() {
let importer = Importer()
do {
try importer.importContent()
} catch {
print(error)
return
}
for (_, file) in importer.files.sorted(by: { $0.key < $1.key }) {
storage.copyFile(at: file.url, fileId: file.name)
// TODO: Store alt text for image and videos
}
var missingPages: [String] = []
for (pageId, page) in importer.pages.sorted(by: { $0.key < $1.key }) {
storage.save(pageMetadata: page.page, for: pageId)
if FileManager.default.fileExists(atPath: page.deContentUrl.path()) {
storage.copyPageContent(from: page.deContentUrl, for: pageId, language: .german)
} else {
missingPages.append(pageId + " (DE)")
}
if FileManager.default.fileExists(atPath: page.enContentUrl.path()) {
storage.copyPageContent(from: page.enContentUrl, for: pageId, language: .english)
} else {
missingPages.append(pageId + " (EN)")
}
}
for (tagId, tag) in importer.tags {
storage.save(tagMetadata: tag, for: tagId)
}
for (postId, post) in importer.posts {
storage.save(post: post, for: postId)
}
let ignoredFiles = importer.ignoredFiles
.map { $0.path() }
.sorted()
print("Ignored files:")
for file in ignoredFiles {
print(file)
}
print("Missing pages:")
for page in missingPages {
print(page)
}
do {
try loadFromDisk()
} catch {
print("Failed to load from disk: \(error)")
}
}
}

View File

@ -79,103 +79,6 @@ final class Content: ObservableObject {
.store(in: &cancellables)
}
func generateFeed(for language: ContentLanguage, bookmarkKey: String) {
let posts = posts.map { $0.feedEntry(for: language) }
DispatchQueue.global(qos: .userInitiated).async {
let navigationItems: [FeedNavigationLink] = [
.init(text: .init(en: "Projects", de: "Projekte"),
url: .init(en: "/projects", de: "/projekte")),
.init(text: .init(en: "Adventures", de: "Abenteuer"),
url: .init(en: "/adventures", de: "/abenteuer")),
.init(text: .init(en: "Services", de: "Dienste"),
url: .init(en: "/services", de: "/dienste")),
.init(text: .init(en: "Tags", de: "Kategorien"),
url: .init(en: "/tags", de: "/kategorien")),
]
let feed = Feed(
language: language,
title: .init(en: "Blog | CH", de: "Blog | CH"),
description: .init(en: "The latests posts, projects and adventures",
de: "Die neusten Beiträge, Projekte und Abenteuer"),
iconDescription: .init(en: "An icon consisting of the letters C and H in blue and orange",
de: "Ein Logo aus den Buchstaben C und H in Blau und Orange"),
navigationItems: navigationItems,
posts: posts)
let fileContent = feed.content
Content.accessFolderFromBookmark(key: bookmarkKey) { folder in
let outputFile = folder.appendingPathComponent("feed.html", isDirectory: false)
do {
try fileContent
.data(using: .utf8)!
.write(to: outputFile)
} catch {
print("Failed to save: \(error)")
}
}
}
}
func importOldContent() {
let importer = Importer()
do {
try importer.importContent()
} catch {
print(error)
return
}
for (_, file) in importer.files.sorted(by: { $0.key < $1.key }) {
storage.copyFile(at: file.url, fileId: file.name)
// TODO: Store alt text for image and videos
}
var missingPages: [String] = []
for (pageId, page) in importer.pages.sorted(by: { $0.key < $1.key }) {
storage.save(pageMetadata: page.page, for: pageId)
if FileManager.default.fileExists(atPath: page.deContentUrl.path()) {
storage.copyPageContent(from: page.deContentUrl, for: pageId, language: .german)
} else {
missingPages.append(pageId + " (DE)")
}
if FileManager.default.fileExists(atPath: page.enContentUrl.path()) {
storage.copyPageContent(from: page.enContentUrl, for: pageId, language: .english)
} else {
missingPages.append(pageId + " (EN)")
}
}
for (tagId, tag) in importer.tags {
storage.save(tagMetadata: tag, for: tagId)
}
for (postId, post) in importer.posts {
storage.save(post: post, for: postId)
}
let ignoredFiles = importer.ignoredFiles
.map { $0.path() }
.sorted()
print("Ignored files:")
for file in ignoredFiles {
print(file)
}
print("Missing pages:")
for page in missingPages {
print(page)
}
do {
try loadFromDisk()
} catch {
print("Failed to load from disk: \(error)")
}
}
private func convert(_ tag: LocalizedTagFile) -> LocalizedTag {
LocalizedTag(
urlComponent: tag.urlComponent,
@ -186,6 +89,31 @@ final class Content: ObservableObject {
originalUrl: tag.originalURL)
}
private func convert(_ post: LocalizedPostFile, images: [String : ImageResource]) -> LocalizedPost {
LocalizedPost(
title: post.title,
content: post.content,
lastModified: post.lastModifiedDate,
images: post.images.compactMap { images[$0] },
linkPreviewImage: post.linkPreviewImage.map { images[$0] },
linkPreviewTitle: post.linkPreviewTitle,
linkPreviewDescription: post.linkPreviewDescription)
}
private func convert(_ page: LocalizedPageFile) -> LocalizedPage {
LocalizedPage(
urlString: page.url,
title: page.title,
lastModified: page.lastModifiedDate,
originalUrl: page.originalURL,
files: Set(page.files),
externalFiles: Set(page.externalFiles),
requiredFiles: Set(page.requiredFiles),
linkPreviewImage: page.linkPreviewImage,
linkPreviewTitle: page.linkPreviewTitle,
linkPreviewDescription: page.linkPreviewDescription)
}
func loadFromDisk() throws {
let storage = Storage(baseFolder: URL(filePath: contentPath))
@ -220,27 +148,8 @@ final class Content: ObservableObject {
let posts = postsData.map { postId, post in
let linkedPage = post.linkedPageId.map { pages[$0] }
let germanData = post.german
let german = LocalizedPost(
title: germanData.title,
content: germanData.content,
lastModified: germanData.lastModifiedDate,
images: germanData.images.compactMap { images[$0] },
linkPreviewImage: germanData.linkPreviewImage.map { images[$0] },
linkPreviewTitle: germanData.linkPreviewTitle,
linkPreviewDescription: germanData.linkPreviewDescription)
let englishData = post.english
let english = LocalizedPost(
title: englishData.title,
content: englishData.content,
lastModified: englishData.lastModifiedDate,
images: englishData.images.compactMap { images[$0] },
linkPreviewImage: englishData.linkPreviewImage.map { images[$0] },
linkPreviewTitle: englishData.linkPreviewTitle,
linkPreviewDescription: englishData.linkPreviewDescription)
let german = convert(post.german, images: images)
let english = convert(post.english, images: images)
return Post(
id: postId,
@ -264,40 +173,14 @@ final class Content: ObservableObject {
private func loadPages(_ pagesData: [String : PageFile], tags: [String : Tag]) -> [String : Page] {
pagesData.reduce(into: [:]) { pages, data in
let (pageId, page) = data
let german = page.german
let germanPage = LocalizedPage(
urlString: german.url,
title: german.title,
lastModified: german.lastModifiedDate,
originalUrl: german.originalURL,
files: Set(german.files),
externalFiles: Set(german.externalFiles),
requiredFiles: Set(german.requiredFiles),
linkPreviewImage: german.linkPreviewImage,
linkPreviewTitle: german.linkPreviewTitle,
linkPreviewDescription: german.linkPreviewDescription)
let english = page.english
let englishPage = LocalizedPage(
urlString: english.url,
title: english.title,
lastModified: english.lastModifiedDate,
originalUrl: english.originalURL,
files: Set(english.files),
externalFiles: Set(english.externalFiles),
requiredFiles: Set(english.requiredFiles),
linkPreviewImage: english.linkPreviewImage,
linkPreviewTitle: english.linkPreviewTitle,
linkPreviewDescription: english.linkPreviewDescription)
pages[pageId] = Page(
id: pageId,
isDraft: page.isDraft,
createdDate: page.createdDate,
startDate: page.startDate,
endDate: page.endDate,
german: germanPage,
english: englishPage,
german: convert(page.german),
english: convert(page.english),
tags: page.tags.map { tags[$0]! })
}
}