feat: add new volumes when found
This commit was merged in pull request #43.
This commit is contained in:
+478
-309
@@ -269,11 +269,14 @@ final class ViewController: UIViewController, UIGestureRecognizerDelegate {
|
||||
|
||||
queue.async { [self] in
|
||||
for dir in directories {
|
||||
var foundFile = false
|
||||
if !fileManager.fileExists(atPath: dir.appendingPathComponent(metadataFilename).path) {
|
||||
getMetadataFromFilename(path: dir)
|
||||
if pendingAlert != nil {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
foundFile = true
|
||||
}
|
||||
|
||||
currentPath = dir
|
||||
@@ -288,7 +291,7 @@ final class ViewController: UIViewController, UIGestureRecognizerDelegate {
|
||||
return
|
||||
}
|
||||
var byteBuffer = ByteBuffer(data: data)
|
||||
guard let metadata: Metadata = try? getCheckedRoot(byteBuffer: &byteBuffer) else {
|
||||
guard var metadata: Metadata = try? getCheckedRoot(byteBuffer: &byteBuffer) else {
|
||||
DispatchQueue.main.async {
|
||||
alert.message =
|
||||
String(format: "Failed to read contents of metadata flatbuffer file: \(metadataPath))")
|
||||
@@ -296,6 +299,35 @@ final class ViewController: UIViewController, UIGestureRecognizerDelegate {
|
||||
pendingAlert = alert
|
||||
return
|
||||
}
|
||||
|
||||
if foundFile {
|
||||
print("found file")
|
||||
guard let archivePaths =
|
||||
getArchivePaths(volumeDir: dir.appendingPathComponent("volumes"), alert: alert)
|
||||
else {
|
||||
return
|
||||
}
|
||||
let archives = archivePaths.map { $0.lastPathComponent }
|
||||
var missing = false
|
||||
for path in metadata.volumes {
|
||||
if let nPath = path.archive {
|
||||
if !archives.contains(nPath) {
|
||||
missing = true
|
||||
}
|
||||
}
|
||||
}
|
||||
if missing {
|
||||
getMetadataFromFilename(path: dir)
|
||||
} else if archives.count != metadata.volumes.count {
|
||||
guard let nM = addNewVolumesToMetadata(
|
||||
pM: metadata, volumeURLs: archivePaths, volumeDir: dir.appendingPathComponent("volumes")
|
||||
) else {
|
||||
return
|
||||
}
|
||||
metadata = nM
|
||||
}
|
||||
}
|
||||
|
||||
metadataList[dir] = metadata
|
||||
loadLocalState()
|
||||
let volCovP = ProgressIndices(v: state[currentPath.lastPathComponent]!.progress.v, c: 0, i: 0)
|
||||
@@ -418,9 +450,306 @@ final class ViewController: UIViewController, UIGestureRecognizerDelegate {
|
||||
return CGSize(width: width, height: height)
|
||||
}
|
||||
|
||||
func getArchivePaths(volumeDir: URL, alert: UIAlertController) -> [URL]? {
|
||||
var isDir: ObjCBool = false
|
||||
if !fileManager.fileExists(atPath: volumeDir.path, isDirectory: &isDir) || !isDir.boolValue {
|
||||
alert.message = "Subdirectory volumes not found: \"\(volumeDir)\", returning"
|
||||
pendingAlert = alert
|
||||
return nil
|
||||
}
|
||||
let volumeURLs = try? fileManager.contentsOfDirectory(
|
||||
at: volumeDir,
|
||||
includingPropertiesForKeys: [.isRegularFileKey],
|
||||
options: [.skipsHiddenFiles]
|
||||
).filter { $0.pathExtension == "cbz" }
|
||||
.sorted { $0.lastPathComponent < $1.lastPathComponent }
|
||||
|
||||
guard let result = volumeURLs else {
|
||||
alert.message = String(format: "failed to read dir: \(volumeDir)")
|
||||
pendingAlert = alert
|
||||
return nil
|
||||
}
|
||||
|
||||
if result.isEmpty {
|
||||
alert.message = String(format: "found no volumes in volume dir: \(volumeDir)")
|
||||
pendingAlert = alert
|
||||
return nil
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func getMatchingPattern(filename: String, alert: UIAlertController) -> Pattern? {
|
||||
// Beautiful, is it not?
|
||||
guard let patterns: [Pattern] = try? [
|
||||
Pattern(
|
||||
pattern: NSRegularExpression(
|
||||
pattern: #"^(.*) - c([0-9]+(?:x[0-9]+)?) \(v([0-9]+)\) - p([0-9]+(?:-p?[0-9]+)?)"#
|
||||
),
|
||||
titlePosition: 1,
|
||||
volumePosition: 3,
|
||||
chapterPosition: 2,
|
||||
pagePosition: 4
|
||||
),
|
||||
Pattern(
|
||||
pattern: NSRegularExpression(
|
||||
pattern: "^(.*) - v([0-9]+) p([0-9]+(?:-[0-9]+)?) - c([0-9]+(?:x[0-9]+)?)"
|
||||
),
|
||||
titlePosition: 1,
|
||||
volumePosition: 2,
|
||||
chapterPosition: 4,
|
||||
pagePosition: 3
|
||||
),
|
||||
] else {
|
||||
alert.message = String(format: "Regular expression is invalid")
|
||||
pendingAlert = alert
|
||||
return nil
|
||||
}
|
||||
|
||||
var matchingPattern: Pattern?
|
||||
for testPattern in patterns {
|
||||
let range = NSRange(filename.startIndex..., in: filename)
|
||||
if let match = testPattern.pattern.firstMatch(in: filename, range: range) {
|
||||
if (filename as NSString).substring(with: match.range(at: testPattern.titlePosition)) == "" {
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
if let match = testPattern.pattern.firstMatch(in: filename, range: range) {
|
||||
if (filename as NSString).substring(with: match.range(at: testPattern.pagePosition)) == "" {
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
if let match = testPattern.pattern.firstMatch(in: filename, range: range) {
|
||||
if (filename as NSString).substring(with: match.range(at: testPattern.chapterPosition)) == "" {
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
if let match = testPattern.pattern.firstMatch(in: filename, range: range) {
|
||||
if (filename as NSString).substring(with: match.range(at: testPattern.volumePosition)) == "" {
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
matchingPattern = testPattern
|
||||
break
|
||||
}
|
||||
|
||||
guard let pattern = matchingPattern else {
|
||||
alert.message = String(format: "Could not find matching pattern, likely missing regex.")
|
||||
pendingAlert = alert
|
||||
return nil
|
||||
}
|
||||
return pattern
|
||||
}
|
||||
|
||||
func getVolumeMetadata(
|
||||
builder: inout FlatBufferBuilder, pattern: Pattern,
|
||||
filenames: [(String, String)], volumeDir: URL, alert: UIAlertController
|
||||
) -> ([(Offset, MetaValue)], UInt32)? {
|
||||
var imageCount: UInt32 = 0
|
||||
var volumes: [(Offset, MetaValue)] = []
|
||||
var currentChapters: [Offset] = []
|
||||
var currentImages: [Offset] = []
|
||||
var previousVolumeURL = ""
|
||||
|
||||
var currentVolume: UInt32!
|
||||
var currentChapter: (UInt32, UInt32?)!
|
||||
|
||||
for (i, (volumeURL, filename)) in filenames.enumerated() {
|
||||
let range = NSRange(filename.startIndex..., in: filename)
|
||||
if let match = pattern.pattern.firstMatch(in: filename, range: range) {
|
||||
imageCount += 1
|
||||
let chapterStr = (filename as NSString).substring(with: match.range(at: pattern.chapterPosition))
|
||||
let chapterParts = chapterStr.split(separator: "x", maxSplits: 1)
|
||||
if chapterParts.count < 1 {
|
||||
alert.message = String(format: "Did not find chapter number in filename: \(filename)")
|
||||
pendingAlert = alert
|
||||
return nil
|
||||
}
|
||||
guard let nChapter0 = UInt32(chapterParts[0]) else {
|
||||
alert.message = String(format: "Failed to convert chapter number to an int: \(filename)")
|
||||
pendingAlert = alert
|
||||
return nil
|
||||
}
|
||||
let chapter: (UInt32, UInt32?) = (
|
||||
nChapter0, chapterParts.count > 1 ? UInt32(chapterParts[1]) : nil
|
||||
)
|
||||
|
||||
guard let volume =
|
||||
UInt32((filename as NSString)
|
||||
.substring(with: match.range(at: pattern.volumePosition)))
|
||||
else {
|
||||
alert.message = String(format: "failed to get match for volume in filename: \(filename)")
|
||||
pendingAlert = alert
|
||||
return nil
|
||||
}
|
||||
|
||||
let pageStr = (filename as NSString).substring(with: match.range(at: pattern.pagePosition))
|
||||
let pageParts = pageStr.split(separator: "-", maxSplits: 1)
|
||||
guard let nPage = UInt32(pageParts[0]) else {
|
||||
alert.message = String(format: "failed to read archive: \(filename)")
|
||||
pendingAlert = alert
|
||||
return nil
|
||||
}
|
||||
let (page, doublePage) = (nPage, pageParts.count > 1)
|
||||
|
||||
let archive: Archive!
|
||||
do {
|
||||
let a = try Archive(url: volumeDir.appendingPathComponent(volumeURL), accessMode: .read)
|
||||
archive = a
|
||||
} catch {
|
||||
alert.message = String(format: "failed to read archive: \(volumeURL)")
|
||||
pendingAlert = alert
|
||||
return nil
|
||||
}
|
||||
guard let entry = archive[filename] else {
|
||||
alert.message = String(format: "failed to archive entry: \(filename)")
|
||||
pendingAlert = alert
|
||||
return nil
|
||||
}
|
||||
var size = ImageDimensions(width: 0, height: 0)
|
||||
do {
|
||||
size = try imageDimensions(of: entry, in: archive)
|
||||
} catch {
|
||||
alert.message = String(format: "Failed to get image dimensions of filename: \(filename)")
|
||||
pendingAlert = alert
|
||||
return nil
|
||||
}
|
||||
let m_filename = builder.create(string: filename)
|
||||
let imageMetadata = ImageMetadata.createImageMetadata(
|
||||
&builder,
|
||||
doublePage: doublePage,
|
||||
filenameOffset: m_filename,
|
||||
firstPage: page,
|
||||
size: Size(width: UInt32(size.width), height: UInt32(size.height))
|
||||
)
|
||||
|
||||
if currentVolume != nil {
|
||||
if volume != currentVolume {
|
||||
assert(volume > currentVolume)
|
||||
|
||||
let chapterName = builder.create(string: "")
|
||||
let imagesOffset = builder.createVector(ofOffsets: currentImages)
|
||||
let chapterMetadata = ChapterMetadata.createChapterMetadata(
|
||||
&builder,
|
||||
chapter: MetaValue(
|
||||
main: currentChapter.0, bonus: currentChapter.1 ?? 0
|
||||
),
|
||||
nameOffset: chapterName,
|
||||
imagesVectorOffset: imagesOffset
|
||||
)
|
||||
|
||||
currentChapters.append(chapterMetadata)
|
||||
|
||||
let volumeTitle = builder.create(string: "")
|
||||
let volumeURLOffset = builder.create(string: previousVolumeURL)
|
||||
let chaptersOffset = builder.createVector(ofOffsets: currentChapters)
|
||||
let volumeMetadata = VolumeMetadata.createVolumeMetadata(
|
||||
&builder,
|
||||
volume: MetaValue(main: currentVolume, bonus: 0),
|
||||
titleOffset: volumeTitle,
|
||||
archiveOffset: volumeURLOffset,
|
||||
chaptersVectorOffset: chaptersOffset
|
||||
)
|
||||
|
||||
volumes.append((volumeMetadata, MetaValue(main: currentVolume, bonus: 0)))
|
||||
|
||||
currentImages = [imageMetadata]
|
||||
currentChapters = []
|
||||
} else if chapter != currentChapter {
|
||||
if chapter.0 == currentChapter.0 {
|
||||
if chapter.1 == nil {
|
||||
alert.message = String(format: "chapter.1 is nil")
|
||||
pendingAlert = alert
|
||||
return nil
|
||||
}
|
||||
if chapter.1! != currentChapter.1 ?? 1 {
|
||||
alert.message = String(format: "chapter != currentChapter")
|
||||
pendingAlert = alert
|
||||
return nil
|
||||
}
|
||||
assert(chapter.1! == currentChapter.1 ?? 1)
|
||||
} else {
|
||||
if chapter.0 != currentChapter.0 + 1 {
|
||||
alert.message = String(format: "chapter.0 != currentChapter.0 + 1")
|
||||
pendingAlert = alert
|
||||
return nil
|
||||
}
|
||||
assert(chapter.0 == currentChapter.0 + 1)
|
||||
}
|
||||
|
||||
let chapterName = builder.create(string: "")
|
||||
let imagesOffset = builder.createVector(ofOffsets: currentImages)
|
||||
let chapterMetadata = ChapterMetadata.createChapterMetadata(
|
||||
&builder,
|
||||
chapter: MetaValue(
|
||||
main: currentChapter.0, bonus: currentChapter.1 ?? 0
|
||||
),
|
||||
nameOffset: chapterName,
|
||||
imagesVectorOffset: imagesOffset
|
||||
)
|
||||
|
||||
currentChapters.append(chapterMetadata)
|
||||
|
||||
currentImages = [imageMetadata]
|
||||
|
||||
} else {
|
||||
currentImages.append(imageMetadata)
|
||||
}
|
||||
} else {
|
||||
currentImages.append(imageMetadata)
|
||||
}
|
||||
if i == filenames.count - 1 {
|
||||
let chapterName = builder.create(string: "")
|
||||
let imagesOffset = builder.createVector(ofOffsets: currentImages)
|
||||
let chapterMetadata = ChapterMetadata.createChapterMetadata(
|
||||
&builder,
|
||||
chapter: MetaValue(
|
||||
main: chapter.0, bonus: chapter.1 ?? 0
|
||||
),
|
||||
nameOffset: chapterName,
|
||||
imagesVectorOffset: imagesOffset
|
||||
)
|
||||
|
||||
currentChapters.append(chapterMetadata)
|
||||
|
||||
let volumeTitle = builder.create(string: "")
|
||||
let volumeURLOffset = builder.create(string: volumeURL)
|
||||
let chaptersOffset = builder.createVector(ofOffsets: currentChapters)
|
||||
let volumeMetadata = VolumeMetadata.createVolumeMetadata(
|
||||
&builder,
|
||||
volume: MetaValue(main: volume, bonus: 0),
|
||||
titleOffset: volumeTitle,
|
||||
archiveOffset: volumeURLOffset,
|
||||
chaptersVectorOffset: chaptersOffset
|
||||
)
|
||||
|
||||
volumes.append((volumeMetadata, MetaValue(main: volume, bonus: 0)))
|
||||
|
||||
currentImages = []
|
||||
currentChapters = []
|
||||
}
|
||||
currentVolume = volume
|
||||
currentChapter = chapter
|
||||
previousVolumeURL = volumeURL
|
||||
} else {
|
||||
print("no regex match on \(filename), returning")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return (volumes, imageCount)
|
||||
}
|
||||
|
||||
struct Pattern {
|
||||
var pattern: NSRegularExpression
|
||||
var title: NSRegularExpression
|
||||
var titlePosition: Int
|
||||
var volumePosition: Int
|
||||
var chapterPosition: Int
|
||||
var pagePosition: Int
|
||||
@@ -434,90 +763,15 @@ final class ViewController: UIViewController, UIGestureRecognizerDelegate {
|
||||
)
|
||||
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
|
||||
|
||||
// Beautiful, is it not?
|
||||
var nPatterns: [Pattern]?
|
||||
do {
|
||||
let fPatterns: [Pattern] = try [
|
||||
Pattern(
|
||||
pattern: NSRegularExpression(
|
||||
pattern: #"c([0-9]+(?:x[0-9]+)?) \(v([0-9]+)\) - p([0-9]+(?:-p?[0-9]+)?)"#
|
||||
),
|
||||
title: NSRegularExpression(
|
||||
pattern: #"^(.*) - c([0-9]+(?:x[0-9]+)?) \(v([0-9]+)\) - p([0-9]+(?:-p?[0-9]+)?)"#
|
||||
),
|
||||
volumePosition: 2,
|
||||
chapterPosition: 1,
|
||||
pagePosition: 3
|
||||
),
|
||||
Pattern(
|
||||
pattern: NSRegularExpression(
|
||||
pattern: "v([0-9]+) p([0-9]+(?:-[0-9]+)?) - c([0-9]+(?:x[0-9]+)?)"
|
||||
),
|
||||
title: NSRegularExpression(
|
||||
pattern: "^(.*) - v([0-9]+) p([0-9]+(?:-[0-9]+)?) - c([0-9]+(?:x[0-9]+)?)"
|
||||
),
|
||||
volumePosition: 1,
|
||||
chapterPosition: 3,
|
||||
pagePosition: 2
|
||||
),
|
||||
]
|
||||
nPatterns = fPatterns
|
||||
} catch {
|
||||
alert.message = String(format: "Regular expression is invalid")
|
||||
pendingAlert = alert
|
||||
return
|
||||
}
|
||||
guard let patterns = nPatterns else {
|
||||
alert.message = String(format: "Regular expression is invalid")
|
||||
pendingAlert = alert
|
||||
return
|
||||
}
|
||||
|
||||
if fileManager.fileExists(
|
||||
atPath: path.appendingPathComponent(metadataFilename).absoluteString
|
||||
) {
|
||||
print("skipped metadata file creation")
|
||||
return
|
||||
}
|
||||
|
||||
var builder = FlatBufferBuilder(initialSize: 1024)
|
||||
|
||||
var volumes: [Offset] = []
|
||||
var currentChapters: [Offset] = []
|
||||
var currentImages: [Offset] = []
|
||||
var previousVolumeURL = ""
|
||||
|
||||
var titleValue = ""
|
||||
|
||||
var currentVolume: UInt32!
|
||||
var currentChapter: (UInt32, UInt32?)!
|
||||
|
||||
let volumeDir = path.appendingPathComponent("volumes")
|
||||
|
||||
var isDir: ObjCBool = false
|
||||
if !fileManager.fileExists(atPath: volumeDir.path, isDirectory: &isDir) || !isDir.boolValue {
|
||||
print("Subdirectory volumes not found in \"\(path)\", returning")
|
||||
return
|
||||
}
|
||||
let volumeURLs = try? fileManager.contentsOfDirectory(
|
||||
at: volumeDir,
|
||||
includingPropertiesForKeys: [.isRegularFileKey],
|
||||
options: [.skipsHiddenFiles]
|
||||
).filter { $0.pathExtension == "cbz" }
|
||||
.sorted { $0.lastPathComponent < $1.lastPathComponent }
|
||||
if volumeURLs == nil {
|
||||
alert.message = String(format: "failed to read dir: \(volumeDir)")
|
||||
pendingAlert = alert
|
||||
return
|
||||
}
|
||||
|
||||
if volumeURLs!.isEmpty {
|
||||
print("found no volumes in volume dir: \(volumeDir)")
|
||||
guard let volumeURLs = getArchivePaths(volumeDir: volumeDir, alert: alert) else {
|
||||
return
|
||||
}
|
||||
|
||||
var filenames: [(String, String)] = []
|
||||
for volumeURL in volumeURLs! {
|
||||
for volumeURL in volumeURLs {
|
||||
do {
|
||||
let volumeArchive = try Archive(url: volumeURL, accessMode: .read)
|
||||
volumeArchive.map { $0.path }.sorted().forEach { filenames.append((volumeURL.lastPathComponent, $0)) }
|
||||
@@ -533,237 +787,23 @@ final class ViewController: UIViewController, UIGestureRecognizerDelegate {
|
||||
return
|
||||
}
|
||||
|
||||
var matchingPattern: Pattern?
|
||||
var imageCount: UInt32 = 0
|
||||
guard let pattern = getMatchingPattern(filename: filenames[0].1, alert: alert) else {
|
||||
return
|
||||
}
|
||||
|
||||
do {
|
||||
for testPattern in patterns {
|
||||
let filename = filenames[0].1
|
||||
let range = NSRange(filename.startIndex..., in: filename)
|
||||
if let match = testPattern.title.firstMatch(in: filename, range: range) {
|
||||
if (filename as NSString).substring(with: match.range(at: 1)) == "" {
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
if let match = testPattern.pattern.firstMatch(in: filename, range: range) {
|
||||
if (filename as NSString).substring(with: match.range(at: testPattern.pagePosition)) == "" {
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
if let match = testPattern.pattern.firstMatch(in: filename, range: range) {
|
||||
if (filename as NSString).substring(with: match.range(at: testPattern.chapterPosition)) == "" {
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
if let match = testPattern.pattern.firstMatch(in: filename, range: range) {
|
||||
if (filename as NSString).substring(with: match.range(at: testPattern.volumePosition)) == "" {
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
matchingPattern = testPattern
|
||||
break
|
||||
}
|
||||
let titleValue: String!
|
||||
let range = NSRange(filenames[0].1.startIndex..., in: filenames[0].1)
|
||||
if let match = pattern.pattern.firstMatch(in: filenames[0].1, range: range) {
|
||||
titleValue = (filenames[0].1 as NSString).substring(with: match.range(at: pattern.titlePosition))
|
||||
} else {
|
||||
print("Did not find match for title, regex did not handle this case.")
|
||||
return
|
||||
}
|
||||
|
||||
guard let pattern = matchingPattern else {
|
||||
alert.message = String(format: "Could not find matching pattern, likely missing regex.")
|
||||
pendingAlert = alert
|
||||
return
|
||||
}
|
||||
|
||||
for (i, (volumeURL, filename)) in filenames.enumerated() {
|
||||
let range = NSRange(filename.startIndex..., in: filename)
|
||||
if i == 0 {
|
||||
if let match = pattern.title.firstMatch(in: filename, range: range) {
|
||||
titleValue = (filename as NSString).substring(with: match.range(at: 1))
|
||||
} else {
|
||||
print("Did not find match for title, regex did not handle this case.")
|
||||
return
|
||||
}
|
||||
}
|
||||
if let match = pattern.pattern.firstMatch(in: filename, range: range) {
|
||||
imageCount += 1
|
||||
let chapterStr = (filename as NSString).substring(with: match.range(at: pattern.chapterPosition))
|
||||
let chapterParts = chapterStr.split(separator: "x", maxSplits: 1)
|
||||
if chapterParts.count < 1 {
|
||||
alert.message = String(format: "Did not find chapter number in filename: \(filename)")
|
||||
pendingAlert = alert
|
||||
return
|
||||
}
|
||||
guard let nChapter0 = UInt32(chapterParts[0]) else {
|
||||
alert.message = String(format: "Failed to convert chapter number to an int: \(filename)")
|
||||
pendingAlert = alert
|
||||
return
|
||||
}
|
||||
let chapter: (UInt32, UInt32?) = (
|
||||
nChapter0, chapterParts.count > 1 ? UInt32(chapterParts[1]) : nil
|
||||
)
|
||||
|
||||
guard let volume =
|
||||
UInt32((filename as NSString)
|
||||
.substring(with: match.range(at: pattern.volumePosition)))
|
||||
else {
|
||||
alert.message = String(format: "failed to get match for volume in filename: \(filename)")
|
||||
pendingAlert = alert
|
||||
return
|
||||
}
|
||||
|
||||
let pageStr = (filename as NSString).substring(with: match.range(at: pattern.pagePosition))
|
||||
let pageParts = pageStr.split(separator: "-", maxSplits: 1)
|
||||
guard let nPage = UInt32(pageParts[0]) else {
|
||||
alert.message = String(format: "failed to read archive: \(filename)")
|
||||
pendingAlert = alert
|
||||
return
|
||||
}
|
||||
let (page, doublePage) = (
|
||||
nPage, pageParts.count > 1
|
||||
)
|
||||
|
||||
let archive = try Archive(url: volumeDir.appendingPathComponent(volumeURL), accessMode: .read)
|
||||
guard let entry = archive[filename] else {
|
||||
alert.message = String(format: "failed to read archive: \(filename)")
|
||||
pendingAlert = alert
|
||||
return
|
||||
}
|
||||
var size = ImageDimensions(width: 0, height: 0)
|
||||
do {
|
||||
size = try imageDimensions(of: entry, in: archive)
|
||||
} catch {
|
||||
alert.message = String(format: "Failed to get image dimensions of filename: \(filename)")
|
||||
pendingAlert = alert
|
||||
return
|
||||
}
|
||||
let m_filename = builder.create(string: filename)
|
||||
let imageMetadata = ImageMetadata.createImageMetadata(
|
||||
&builder,
|
||||
doublePage: doublePage,
|
||||
filenameOffset: m_filename,
|
||||
firstPage: page,
|
||||
size: Size(width: UInt32(size.width), height: UInt32(size.height))
|
||||
)
|
||||
|
||||
if currentVolume != nil {
|
||||
if volume != currentVolume {
|
||||
assert(volume > currentVolume)
|
||||
|
||||
let chapterName = builder.create(string: "")
|
||||
let imagesOffset = builder.createVector(ofOffsets: currentImages)
|
||||
let chapterMetadata = ChapterMetadata.createChapterMetadata(
|
||||
&builder,
|
||||
chapter: MetaValue(
|
||||
main: currentChapter.0, bonus: currentChapter.1 ?? 0
|
||||
),
|
||||
nameOffset: chapterName,
|
||||
imagesVectorOffset: imagesOffset
|
||||
)
|
||||
|
||||
currentChapters.append(chapterMetadata)
|
||||
|
||||
let volumeTitle = builder.create(string: "")
|
||||
let volumeURLOffset = builder.create(string: previousVolumeURL)
|
||||
let chaptersOffset = builder.createVector(ofOffsets: currentChapters)
|
||||
let volumeMetadata = VolumeMetadata.createVolumeMetadata(
|
||||
&builder,
|
||||
volume: MetaValue(main: currentVolume, bonus: 0),
|
||||
titleOffset: volumeTitle,
|
||||
archiveOffset: volumeURLOffset,
|
||||
chaptersVectorOffset: chaptersOffset
|
||||
)
|
||||
|
||||
volumes.append(volumeMetadata)
|
||||
|
||||
currentImages = [imageMetadata]
|
||||
currentChapters = []
|
||||
} else if chapter != currentChapter {
|
||||
if chapter.0 == currentChapter.0 {
|
||||
if chapter.1 == nil {
|
||||
alert.message = String(format: "chapter.1 is nil")
|
||||
pendingAlert = alert
|
||||
return
|
||||
}
|
||||
if chapter.1! != currentChapter.1 ?? 1 {
|
||||
alert.message = String(format: "chapter != currentChapter")
|
||||
pendingAlert = alert
|
||||
return
|
||||
}
|
||||
assert(chapter.1! == currentChapter.1 ?? 1)
|
||||
} else {
|
||||
if chapter.0 != currentChapter.0 + 1 {
|
||||
alert.message = String(format: "chapter.0 != currentChapter.0 + 1")
|
||||
pendingAlert = alert
|
||||
return
|
||||
}
|
||||
assert(chapter.0 == currentChapter.0 + 1)
|
||||
}
|
||||
|
||||
let chapterName = builder.create(string: "")
|
||||
let imagesOffset = builder.createVector(ofOffsets: currentImages)
|
||||
let chapterMetadata = ChapterMetadata.createChapterMetadata(
|
||||
&builder,
|
||||
chapter: MetaValue(
|
||||
main: currentChapter.0, bonus: currentChapter.1 ?? 0
|
||||
),
|
||||
nameOffset: chapterName,
|
||||
imagesVectorOffset: imagesOffset
|
||||
)
|
||||
|
||||
currentChapters.append(chapterMetadata)
|
||||
|
||||
currentImages = [imageMetadata]
|
||||
|
||||
} else {
|
||||
currentImages.append(imageMetadata)
|
||||
}
|
||||
} else {
|
||||
currentImages.append(imageMetadata)
|
||||
}
|
||||
if i == filenames.count - 1 {
|
||||
let chapterName = builder.create(string: "")
|
||||
let imagesOffset = builder.createVector(ofOffsets: currentImages)
|
||||
let chapterMetadata = ChapterMetadata.createChapterMetadata(
|
||||
&builder,
|
||||
chapter: MetaValue(
|
||||
main: chapter.0, bonus: chapter.1 ?? 0
|
||||
),
|
||||
nameOffset: chapterName,
|
||||
imagesVectorOffset: imagesOffset
|
||||
)
|
||||
|
||||
currentChapters.append(chapterMetadata)
|
||||
|
||||
let volumeTitle = builder.create(string: "")
|
||||
let volumeURLOffset = builder.create(string: volumeURL)
|
||||
let chaptersOffset = builder.createVector(ofOffsets: currentChapters)
|
||||
let volumeMetadata = VolumeMetadata.createVolumeMetadata(
|
||||
&builder,
|
||||
volume: MetaValue(main: volume, bonus: 0),
|
||||
titleOffset: volumeTitle,
|
||||
archiveOffset: volumeURLOffset,
|
||||
chaptersVectorOffset: chaptersOffset
|
||||
)
|
||||
|
||||
volumes.append(volumeMetadata)
|
||||
|
||||
currentImages = []
|
||||
currentChapters = []
|
||||
}
|
||||
currentVolume = volume
|
||||
currentChapter = chapter
|
||||
previousVolumeURL = volumeURL
|
||||
} else {
|
||||
print("no regex match on \(filename), returning")
|
||||
return
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
print("failed reading image file names")
|
||||
guard let (volumes, imageCount) = getVolumeMetadata(
|
||||
builder: &builder, pattern: pattern, filenames: filenames, volumeDir: volumeDir, alert: alert
|
||||
) else {
|
||||
return
|
||||
}
|
||||
|
||||
if volumes.count == 0 {
|
||||
@@ -776,7 +816,7 @@ final class ViewController: UIViewController, UIGestureRecognizerDelegate {
|
||||
let countryOfOrigin = builder.create(string: nil)
|
||||
let description = builder.create(string: nil)
|
||||
let tags = builder.createVector(ofOffsets: [])
|
||||
let volumeOffsets = builder.createVector(ofOffsets: volumes)
|
||||
let volumeOffsets = builder.createVector(ofOffsets: volumes.map { $0.0 })
|
||||
let metadata = Metadata.createMetadata(
|
||||
&builder,
|
||||
titleOffset: title,
|
||||
@@ -2632,6 +2672,135 @@ extension ViewController {
|
||||
}
|
||||
comics[indexPath.item].metadata = newMetadata
|
||||
}
|
||||
|
||||
private func addNewVolumesToMetadata(pM: Metadata, volumeURLs: [URL], volumeDir: URL) -> Metadata? {
|
||||
let alert = UIAlertController(
|
||||
title: "Failed to rebuild metadata",
|
||||
message: "This is an alert.",
|
||||
preferredStyle: .alert
|
||||
)
|
||||
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
|
||||
|
||||
var volumes: [(Offset, MetaValue)] = []
|
||||
var currentChapters: [Offset] = []
|
||||
var currentImages: [Offset] = []
|
||||
var builder = FlatBufferBuilder(initialSize: 1024)
|
||||
for volume in pM.volumes {
|
||||
for chapter in volume.chapters {
|
||||
for image in chapter.images {
|
||||
let m_filename = builder.create(string: image.filename)
|
||||
let imageMetadata = ImageMetadata.createImageMetadata(
|
||||
&builder,
|
||||
doublePage: image.doublePage,
|
||||
filenameOffset: m_filename,
|
||||
firstPage: image.firstPage,
|
||||
size: image.size
|
||||
)
|
||||
currentImages.append(imageMetadata)
|
||||
}
|
||||
let chapterName = builder.create(string: chapter.name)
|
||||
let imagesOffset = builder.createVector(ofOffsets: currentImages)
|
||||
let chapterMetadata = ChapterMetadata.createChapterMetadata(
|
||||
&builder,
|
||||
chapter: chapter.chapter,
|
||||
nameOffset: chapterName,
|
||||
imagesVectorOffset: imagesOffset
|
||||
)
|
||||
currentChapters.append(chapterMetadata)
|
||||
currentImages = []
|
||||
}
|
||||
let volumeTitle = builder.create(string: volume.title)
|
||||
let volumeURLOffset = builder.create(string: volume.archive)
|
||||
let chaptersOffset = builder.createVector(ofOffsets: currentChapters)
|
||||
let volumeMetadata = VolumeMetadata.createVolumeMetadata(
|
||||
&builder,
|
||||
volume: volume.volume,
|
||||
titleOffset: volumeTitle,
|
||||
archiveOffset: volumeURLOffset,
|
||||
chaptersVectorOffset: chaptersOffset
|
||||
)
|
||||
|
||||
volumes.append((volumeMetadata, volume.volume))
|
||||
currentChapters = []
|
||||
}
|
||||
|
||||
var filenames: [(String, String)] = []
|
||||
for volumeURL in volumeURLs {
|
||||
do {
|
||||
let volumeArchive = try Archive(url: volumeURL, accessMode: .read)
|
||||
volumeArchive.map { $0.path }.sorted().forEach { filenames.append((volumeURL.lastPathComponent, $0)) }
|
||||
} catch {
|
||||
alert.message = String(format: "failed to read archive: \(volumeURL)")
|
||||
pendingAlert = alert
|
||||
continue
|
||||
}
|
||||
}
|
||||
guard let pattern = getMatchingPattern(filename: filenames[0].1, alert: alert) else {
|
||||
return nil
|
||||
}
|
||||
guard let (newVolumeOffsets, newImageCount) = getVolumeMetadata(
|
||||
builder: &builder, pattern: pattern,
|
||||
filenames: filenames, volumeDir: volumeDir, alert: alert
|
||||
) else {
|
||||
return nil
|
||||
}
|
||||
volumes += newVolumeOffsets
|
||||
|
||||
let title = builder.create(string: pM.title)
|
||||
let originalLanguage = builder.create(string: pM.originalLanguage)
|
||||
let countryOfOrigin = builder.create(string: pM.countryOfOrigin)
|
||||
let description = builder.create(string: pM.description)
|
||||
let tags = builder.createVector(ofOffsets: [])
|
||||
let volumeOffsets = builder.createVector(ofOffsets: volumes.sorted {
|
||||
($0.1.main < $1.1.main) || ($0.1.main == $1.1.main && $0.1.bonus < $1.1.bonus)
|
||||
}.map { $0.0 })
|
||||
|
||||
let metadata = Metadata.createMetadata(
|
||||
&builder,
|
||||
titleOffset: title,
|
||||
format: pM.format,
|
||||
originalLanguageOffset: originalLanguage,
|
||||
countryOfOriginOffset: countryOfOrigin,
|
||||
publicationDemographic: pM.publicationDemographic,
|
||||
status: pM.status,
|
||||
contentRating: pM.contentRating,
|
||||
source: pM.source,
|
||||
startReleaseDate: pM.startReleaseDate,
|
||||
endReleaseDate: pM.endReleaseDate,
|
||||
tagsVectorOffset: tags,
|
||||
descriptionOffset: description,
|
||||
anilistId: pM.anilistId,
|
||||
volumesVectorOffset: volumeOffsets,
|
||||
imageCount: pM.imageCount + newImageCount
|
||||
)
|
||||
|
||||
builder.finish(offset: metadata)
|
||||
do {
|
||||
try builder.data.write(to: currentPath.appendingPathComponent(metadataFilename))
|
||||
} catch {
|
||||
alert.message = String(format: "Failed to write metadata file at: \(metadataFilename)")
|
||||
DispatchQueue.main.async {
|
||||
self.present(alert, animated: false)
|
||||
}
|
||||
}
|
||||
let metadataPath = currentPath.appendingPathComponent(metadataFilename)
|
||||
guard let data = try? Data(contentsOf: metadataPath) else {
|
||||
alert.message = String(format: "Failed to read metadata file at: \(metadataPath)")
|
||||
DispatchQueue.main.async {
|
||||
self.present(alert, animated: false)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
var byteBuffer = ByteBuffer(data: data)
|
||||
guard let newMetadata: Metadata = try? getCheckedRoot(byteBuffer: &byteBuffer) else {
|
||||
alert.message = String(format: "Failed to load flatbuffer file at: \(metadataPath)")
|
||||
DispatchQueue.main.async {
|
||||
self.present(alert, animated: false)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return newMetadata
|
||||
}
|
||||
}
|
||||
|
||||
extension ViewController: UIPopoverPresentationControllerDelegate {
|
||||
|
||||
Reference in New Issue
Block a user