Files
NetNewsWire/Modules/Account/Sources/Account/OPMLFile.swift
2024-09-24 22:31:21 -07:00

121 lines
2.5 KiB
Swift

//
// OPMLFile.swift
// Account
//
// Created by Maurice Parker on 9/12/19.
// Copyright © 2019 Ranchero Software, LLC. All rights reserved.
//
import Foundation
import os
import Parser
import Core
@MainActor final class OPMLFile {
private let fileURL: URL
private let account: Account
private let dataFile: DataFile
private let logger = Logger(subsystem: Bundle.main.bundleIdentifier!, category: "OPMLFile")
init(filename: String, account: Account) {
self.account = account
self.fileURL = URL(fileURLWithPath: filename)
self.dataFile = DataFile(fileURL: self.fileURL)
self.dataFile.delegate = self
}
func markAsDirty() {
dataFile.markAsDirty()
}
func opmlItems() -> [OPMLItem]? {
guard let fileData = opmlFileData() else {
return nil
}
return parsedOPMLItems(fileData: fileData)
}
func save() {
dataFile.save()
}
}
private extension OPMLFile {
func opmlFileData() -> Data? {
var fileData: Data? = nil
do {
fileData = try Data(contentsOf: fileURL)
} catch {
logger.error("OPML read from disk failed for \(self.fileURL): \(error.localizedDescription)")
}
return fileData
}
func parsedOPMLItems(fileData: Data) -> [OPMLItem]? {
let parserData = ParserData(url: fileURL.absoluteString, data: fileData)
let opmlDocument = OPMLParser.document(with: parserData)
return opmlDocument?.items
}
func opmlDocument() -> String {
let escapedTitle = account.nameForDisplay.escapingSpecialXMLCharacters
let openingText =
"""
<?xml version="1.0" encoding="UTF-8"?>
<!-- OPML generated by NetNewsWire -->
<opml version="1.1">
<head>
<title>\(escapedTitle)</title>
</head>
<body>
"""
let middleText = account.OPMLString(indentLevel: 0, allowCustomAttributes: true)
let closingText =
"""
</body>
</opml>
"""
let opml = openingText + middleText + closingText
return opml
}
}
extension OPMLFile: DataFileDelegate {
func data(for dataFile: DataFile) -> Data? {
guard !account.isDeleted else {
return nil
}
let opmlDocumentString = opmlDocument()
guard let data = opmlDocumentString.data(using: .utf8, allowLossyConversion: true) else {
assertionFailure("OPML String conversion to Data failed for \(self.fileURL).")
logger.error("OPML String conversion to Data failed for \(self.fileURL)")
return nil
}
return data
}
func dataFileWriteToDiskDidFail(for dataFile: DataFile, error: Error) {
logger.error("OPML save to disk failed for \(self.fileURL): \(error.localizedDescription)")
}
}