From 5a251bfe88519b77dc5484172d6fa610cfd72610 Mon Sep 17 00:00:00 2001 From: Jackson Harper Date: Sat, 11 Jun 2022 09:45:06 -0700 Subject: [PATCH 1/3] WIP: local PDF saving --- apple/OmnivoreKit/Sources/App/PDFSupport/PDFViewer.swift | 1 + .../Sources/App/PDFSupport/PDFViewerViewModel.swift | 7 +++++++ .../CoreDataModel.xcdatamodel/contents | 3 ++- apple/OmnivoreKit/Sources/Models/DataModels/FeedItem.swift | 2 +- apple/OmnivoreKit/Sources/Models/DataModels/PDFItem.swift | 2 ++ .../Sources/Services/DataService/DataService.swift | 3 +-- apple/OmnivoreKit/Sources/Utils/PDFUtils.swift | 7 +++++++ 7 files changed, 21 insertions(+), 4 deletions(-) diff --git a/apple/OmnivoreKit/Sources/App/PDFSupport/PDFViewer.swift b/apple/OmnivoreKit/Sources/App/PDFSupport/PDFViewer.swift index d6217081c..fa89eeb4e 100644 --- a/apple/OmnivoreKit/Sources/App/PDFSupport/PDFViewer.swift +++ b/apple/OmnivoreKit/Sources/App/PDFSupport/PDFViewer.swift @@ -142,6 +142,7 @@ import Utils // NOTE: the issue here is the PDF is downloaded, but saved to a URL we don't know about // because it is changed. let pdfURL = await viewModel.downloadPDF(dataService: dataService) + print("PDF URL", pdfURL) if let pdfURL = pdfURL { let document = HighlightedDocument(url: pdfURL, viewModel: viewModel) pdfStateObject.document = document diff --git a/apple/OmnivoreKit/Sources/App/PDFSupport/PDFViewerViewModel.swift b/apple/OmnivoreKit/Sources/App/PDFSupport/PDFViewerViewModel.swift index 5b25456cb..2f78cef45 100644 --- a/apple/OmnivoreKit/Sources/App/PDFSupport/PDFViewerViewModel.swift +++ b/apple/OmnivoreKit/Sources/App/PDFSupport/PDFViewerViewModel.swift @@ -3,6 +3,7 @@ import CoreData import Foundation import Models import Services +import Utils public final class PDFViewerViewModel: ObservableObject { @Published public var errorMessage: String? @@ -93,6 +94,12 @@ public final class PDFViewerViewModel: ObservableObject { if itemDownloaded { return pdfItem.localPdfURL } + if let tempURL = pdfItem.tempPDFURL { + if let localURL = try? PDFUtils.copyToLocal(url: tempURL) { + return tempURL + // return URL(string: localURL) + } + } if let localURL = try await dataService.fetchPDFData(slug: pdfItem.slug, pageURLString: pdfItem.originalArticleURL) { return localURL } diff --git a/apple/OmnivoreKit/Sources/Models/CoreData/CoreDataModel.xcdatamodeld/CoreDataModel.xcdatamodel/contents b/apple/OmnivoreKit/Sources/Models/CoreData/CoreDataModel.xcdatamodeld/CoreDataModel.xcdatamodel/contents index fec76121b..9c4257c46 100644 --- a/apple/OmnivoreKit/Sources/Models/CoreData/CoreDataModel.xcdatamodeld/CoreDataModel.xcdatamodel/contents +++ b/apple/OmnivoreKit/Sources/Models/CoreData/CoreDataModel.xcdatamodeld/CoreDataModel.xcdatamodel/contents @@ -44,6 +44,7 @@ + @@ -91,7 +92,7 @@ - + diff --git a/apple/OmnivoreKit/Sources/Models/DataModels/FeedItem.swift b/apple/OmnivoreKit/Sources/Models/DataModels/FeedItem.swift index 4147401d9..d74f21aeb 100644 --- a/apple/OmnivoreKit/Sources/Models/DataModels/FeedItem.swift +++ b/apple/OmnivoreKit/Sources/Models/DataModels/FeedItem.swift @@ -47,7 +47,7 @@ public extension LinkedItem { var isReadyToRead: Bool { if isPDF { // If its a PDF we verify the local file is available - return PDFUtils.exists(filename: localPDF) + return PDFUtils.exists(filename: localPDF) || PDFUtils.tempExists(tempPDFURL: tempPDFURL) } // Check the state and whether we have HTML return state == "SUCCEEDED" diff --git a/apple/OmnivoreKit/Sources/Models/DataModels/PDFItem.swift b/apple/OmnivoreKit/Sources/Models/DataModels/PDFItem.swift index 475f8dfb9..43c2eb672 100644 --- a/apple/OmnivoreKit/Sources/Models/DataModels/PDFItem.swift +++ b/apple/OmnivoreKit/Sources/Models/DataModels/PDFItem.swift @@ -7,6 +7,7 @@ public struct PDFItem { public let itemID: String public let pdfURL: URL? public let localPDF: String? + public let tempPDFURL: URL? public let title: String public let slug: String public let readingProgress: Double @@ -24,6 +25,7 @@ public struct PDFItem { itemID: item.unwrappedID, pdfURL: URL(string: item.unwrappedPageURLString), localPDF: item.localPDF, + tempPDFURL: item.tempPDFURL, title: item.unwrappedID, slug: item.unwrappedSlug, readingProgress: item.readingProgress, diff --git a/apple/OmnivoreKit/Sources/Services/DataService/DataService.swift b/apple/OmnivoreKit/Sources/Services/DataService/DataService.swift index eb464759c..f14ac5b6a 100644 --- a/apple/OmnivoreKit/Sources/Services/DataService/DataService.swift +++ b/apple/OmnivoreKit/Sources/Services/DataService/DataService.swift @@ -148,9 +148,8 @@ public final class DataService: ObservableObject { switch pageScrape.contentType { case let .pdf(localUrl): linkedItem.contentReader = "PDF" + linkedItem.tempPDFURL = localUrl linkedItem.title = PDFUtils.titleFromPdfFile(pageScrape.url) - print("PERSISTING PDF", localUrl) - linkedItem.localPDF = try PDFUtils.copyToLocal(url: localUrl) case let .html(html: html, title: title, iconURL: iconURL): linkedItem.contentReader = "WEB" linkedItem.originalHtml = html diff --git a/apple/OmnivoreKit/Sources/Utils/PDFUtils.swift b/apple/OmnivoreKit/Sources/Utils/PDFUtils.swift index 0d4a4c19c..d7c89cd68 100644 --- a/apple/OmnivoreKit/Sources/Utils/PDFUtils.swift +++ b/apple/OmnivoreKit/Sources/Utils/PDFUtils.swift @@ -45,6 +45,13 @@ public enum PDFUtils { return false } + public static func tempExists(tempPDFURL: URL?) -> Bool { + if let tempPDFURL = tempPDFURL { + return FileManager.default.fileExists(atPath: tempPDFURL.path) + } + return false + } + public static func titleFromPdfFile(_ urlStr: String) -> String { let url = URL(string: urlStr) if let url = url { From 7084f18932409e197c8754c04d6ae9b653f9ef33 Mon Sep 17 00:00:00 2001 From: Jackson Harper Date: Sun, 12 Jun 2022 14:36:35 -0700 Subject: [PATCH 2/3] Handle changing IDs when local PDFs are saved --- .../DataService/Mutations/SavePDF.swift | 2 + .../Services/DataService/OfflineSync.swift | 10 ++--- .../Queries/ArticleContentQuery.swift | 43 +++++++++++++++++-- .../OmnivoreKit/Sources/Utils/PDFUtils.swift | 4 +- 4 files changed, 48 insertions(+), 11 deletions(-) diff --git a/apple/OmnivoreKit/Sources/Services/DataService/Mutations/SavePDF.swift b/apple/OmnivoreKit/Sources/Services/DataService/Mutations/SavePDF.swift index c0e9e186e..c5b53b58e 100644 --- a/apple/OmnivoreKit/Sources/Services/DataService/Mutations/SavePDF.swift +++ b/apple/OmnivoreKit/Sources/Services/DataService/Mutations/SavePDF.swift @@ -4,6 +4,7 @@ import Models import SwiftGraphQL public struct UploadFileRequestPayload { + public let pageId: String public let uploadID: String? public let uploadFileID: String? public let urlString: String? @@ -29,6 +30,7 @@ public extension DataService { uploadFileRequestSuccess: .init { .success( payload: UploadFileRequestPayload( + pageId: (try $0.createdPageId()) ?? id, uploadID: try $0.id(), uploadFileID: try $0.uploadFileId(), urlString: try $0.uploadSignedUrl() diff --git a/apple/OmnivoreKit/Sources/Services/DataService/OfflineSync.swift b/apple/OmnivoreKit/Sources/Services/DataService/OfflineSync.swift index c5c5e2777..73dce5a04 100644 --- a/apple/OmnivoreKit/Sources/Services/DataService/OfflineSync.swift +++ b/apple/OmnivoreKit/Sources/Services/DataService/OfflineSync.swift @@ -54,18 +54,14 @@ public extension DataService { try await updateLinkedItemStatus(id: id, newId: nil, status: .isSyncing) let uploadRequest = try await uploadFileRequest(id: id, url: url) + print("UPLOAD REQUEST, ORIGINAL ID, NEW ID", id, uploadRequest.pageId) if let urlString = uploadRequest.urlString, let uploadUrl = URL(string: urlString) { - let attr = try? FileManager.default.attributesOfItem(atPath: localPdfURL.path) - if let attr = attr { - print("ATTR", attr[.size]) - } - - try await uploadFile(id: id, localPdfURL: localPdfURL, url: uploadUrl) + try await uploadFile(id: uploadRequest.pageId, localPdfURL: localPdfURL, url: uploadUrl) } else { throw SaveArticleError.badData } - try await updateLinkedItemStatus(id: id, newId: nil, status: .isNSync) + try await updateLinkedItemStatus(id: id, newId: uploadRequest.pageId, status: .isNSync) try backgroundContext.performAndWait { try backgroundContext.save() } diff --git a/apple/OmnivoreKit/Sources/Services/DataService/Queries/ArticleContentQuery.swift b/apple/OmnivoreKit/Sources/Services/DataService/Queries/ArticleContentQuery.swift index 8c3b98c57..843239a1f 100644 --- a/apple/OmnivoreKit/Sources/Services/DataService/Queries/ArticleContentQuery.swift +++ b/apple/OmnivoreKit/Sources/Services/DataService/Queries/ArticleContentQuery.swift @@ -195,6 +195,8 @@ public extension DataService { } internal func persistArticleContent(item: InternalLinkedItem, htmlContent: String, highlights: [InternalHighlight]) async throws { + var needsPDFDownload = false + try await backgroundContext.perform { [weak self] in guard let self = self else { return } let fetchRequest: NSFetchRequest = LinkedItem.fetchRequest() @@ -226,19 +228,53 @@ public extension DataService { linkedItem.isArchived = item.isArchived linkedItem.contentReader = item.contentReader linkedItem.serverSyncStatus = Int64(ServerSyncStatus.isNSync.rawValue) + + if item.isPDF { + needsPDFDownload = true + + // Check if we already have the PDF item locally. Either in temporary + // space, or in the documents directory + if let localPDF = existingItem?.localPDF { + if PDFUtils.exists(filename: localPDF) { + linkedItem.localPDF = localPDF + needsPDFDownload = false + } + } + + if let tempPDFURL = existingItem?.tempPDFURL { + linkedItem.localPDF = try? PDFUtils.moveToLocal(url: tempPDFURL) + PDFUtils.exists(filename: linkedItem.localPDF) + if linkedItem.localPDF != nil { + needsPDFDownload = false + } + } + } } if item.isPDF { - try await fetchPDFData(slug: item.slug, pageURLString: item.pageURLString) + if needsPDFDownload { + print("PDF does not exist, downloading", item.id, item.title) + try await backgroundContext.perform { + let fetchRequest: NSFetchRequest = LinkedItem.fetchRequest() + fetchRequest.predicate = NSPredicate(format: "id == %@", item.id) + + let existingItem = try? self.backgroundContext.fetch(fetchRequest).first + print("EXISTING ITEM", existingItem) + } + + try await fetchPDFData(slug: item.slug, pageURLString: item.pageURLString) + } else { + print("PDF already exists, not downloading", item.id) + } } try await backgroundContext.perform { [weak self] in do { try self?.backgroundContext.save() - logger.debug("ArticleContent saved succesfully") + // logger.debug("ArticleContent saved succesfully") } catch { self?.backgroundContext.rollback() - logger.debug("Failed to save ArticleContent") + // logger.debug("Failed to save ArticleContent") throw error } } @@ -275,6 +311,7 @@ public extension DataService { try data.write(to: tempPath) let localPDF = try PDFUtils.moveToLocal(url: tempPath) localPdfURL = PDFUtils.localPdfURL(filename: localPDF) + linkedItem.tempPDFURL = nil linkedItem.localPDF = localPDF try self?.backgroundContext.save() } catch { diff --git a/apple/OmnivoreKit/Sources/Utils/PDFUtils.swift b/apple/OmnivoreKit/Sources/Utils/PDFUtils.swift index d7c89cd68..1919377fc 100644 --- a/apple/OmnivoreKit/Sources/Utils/PDFUtils.swift +++ b/apple/OmnivoreKit/Sources/Utils/PDFUtils.swift @@ -35,12 +35,14 @@ public enum PDFUtils { let url = FileManager.default .urls(for: .documentDirectory, in: .userDomainMask)[0] .appendingPathComponent(filename) + return url } public static func exists(filename: String?) -> Bool { if let filename = filename, let localPdfURL = localPdfURL(filename: filename) { - return FileManager.default.fileExists(atPath: localPdfURL.absoluteString) + let result = FileManager.default.fileExists(atPath: localPdfURL.path) + return result } return false } From 2a7a87de09f22fbe2344ed0d5e3be92038141562 Mon Sep 17 00:00:00 2001 From: Jackson Harper Date: Mon, 13 Jun 2022 09:42:59 -0700 Subject: [PATCH 3/3] Remove debug lines --- .../Sources/App/PDFSupport/PDFViewer.swift | 1 - .../App/PDFSupport/PDFViewerViewModel.swift | 1 - .../Queries/ArticleContentQuery.swift | 21 ++++--------------- 3 files changed, 4 insertions(+), 19 deletions(-) diff --git a/apple/OmnivoreKit/Sources/App/PDFSupport/PDFViewer.swift b/apple/OmnivoreKit/Sources/App/PDFSupport/PDFViewer.swift index fa89eeb4e..d6217081c 100644 --- a/apple/OmnivoreKit/Sources/App/PDFSupport/PDFViewer.swift +++ b/apple/OmnivoreKit/Sources/App/PDFSupport/PDFViewer.swift @@ -142,7 +142,6 @@ import Utils // NOTE: the issue here is the PDF is downloaded, but saved to a URL we don't know about // because it is changed. let pdfURL = await viewModel.downloadPDF(dataService: dataService) - print("PDF URL", pdfURL) if let pdfURL = pdfURL { let document = HighlightedDocument(url: pdfURL, viewModel: viewModel) pdfStateObject.document = document diff --git a/apple/OmnivoreKit/Sources/App/PDFSupport/PDFViewerViewModel.swift b/apple/OmnivoreKit/Sources/App/PDFSupport/PDFViewerViewModel.swift index 2f78cef45..14bcb6ed2 100644 --- a/apple/OmnivoreKit/Sources/App/PDFSupport/PDFViewerViewModel.swift +++ b/apple/OmnivoreKit/Sources/App/PDFSupport/PDFViewerViewModel.swift @@ -97,7 +97,6 @@ public final class PDFViewerViewModel: ObservableObject { if let tempURL = pdfItem.tempPDFURL { if let localURL = try? PDFUtils.copyToLocal(url: tempURL) { return tempURL - // return URL(string: localURL) } } if let localURL = try await dataService.fetchPDFData(slug: pdfItem.slug, pageURLString: pdfItem.originalArticleURL) { diff --git a/apple/OmnivoreKit/Sources/Services/DataService/Queries/ArticleContentQuery.swift b/apple/OmnivoreKit/Sources/Services/DataService/Queries/ArticleContentQuery.swift index 843239a1f..e1851149b 100644 --- a/apple/OmnivoreKit/Sources/Services/DataService/Queries/ArticleContentQuery.swift +++ b/apple/OmnivoreKit/Sources/Services/DataService/Queries/ArticleContentQuery.swift @@ -251,30 +251,17 @@ public extension DataService { } } - if item.isPDF { - if needsPDFDownload { - print("PDF does not exist, downloading", item.id, item.title) - try await backgroundContext.perform { - let fetchRequest: NSFetchRequest = LinkedItem.fetchRequest() - fetchRequest.predicate = NSPredicate(format: "id == %@", item.id) - - let existingItem = try? self.backgroundContext.fetch(fetchRequest).first - print("EXISTING ITEM", existingItem) - } - - try await fetchPDFData(slug: item.slug, pageURLString: item.pageURLString) - } else { - print("PDF already exists, not downloading", item.id) - } + if item.isPDF && needsPDFDownload { + try await fetchPDFData(slug: item.slug, pageURLString: item.pageURLString) } try await backgroundContext.perform { [weak self] in do { try self?.backgroundContext.save() - // logger.debug("ArticleContent saved succesfully") + logger.debug("ArticleContent saved succesfully") } catch { self?.backgroundContext.rollback() - // logger.debug("Failed to save ArticleContent") + logger.debug("Failed to save ArticleContent") throw error } }