// // NCAutoUpload.swift // Nextcloud // // Created by Marino Faggiana on 27/01/21. // Copyright © 2021 Marino Faggiana. All rights reserved. // // Author Marino Faggiana // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . // import UIKit import CoreLocation import NextcloudKit import Photos class NCAutoUpload: NSObject { @objc static let shared: NCAutoUpload = { let instance = NCAutoUpload() return instance }() private var endForAssetToUpload: Bool = false private let appDelegate = UIApplication.shared.delegate as? AppDelegate private var applicationState = UIApplication.shared.applicationState // MARK: - @objc func initAutoUpload(viewController: UIViewController?, completion: @escaping (_ items: Int) -> Void) { guard let account = NCManageDatabase.shared.getActiveAccount(), account.autoUpload else { completion(0) return } applicationState = UIApplication.shared.applicationState NCAskAuthorization.shared.askAuthorizationPhotoLibrary(viewController: viewController) { hasPermission in guard hasPermission else { NCManageDatabase.shared.setAccountAutoUploadProperty("autoUpload", state: false) completion(0) return } DispatchQueue.global().async { self.uploadAssetsNewAndFull(viewController: viewController, selector: NCGlobal.shared.selectorUploadAutoUpload, log: "Init Auto Upload") { items in completion(items) } } } } @objc func autoUploadFullPhotos(viewController: UIViewController?, log: String) { applicationState = UIApplication.shared.applicationState NCAskAuthorization.shared.askAuthorizationPhotoLibrary(viewController: viewController) { hasPermission in guard hasPermission else { return } let error = NKError(errorCode: NCGlobal.shared.errorInternalError, errorDescription: "_create_full_upload_") NCContentPresenter.shared.showWarning(error: error, priority: .max) NCActivityIndicator.shared.start() DispatchQueue.global().async { self.uploadAssetsNewAndFull(viewController: viewController, selector: NCGlobal.shared.selectorUploadAutoUploadAll, log: log) { _ in NCActivityIndicator.shared.stop() } } } } private func uploadAssetsNewAndFull(viewController: UIViewController?, selector: String, log: String, completion: @escaping (_ items: Int) -> Void) { guard let account = NCManageDatabase.shared.getActiveAccount() else { completion(0) return } let autoUploadPath = NCManageDatabase.shared.getAccountAutoUploadPath(urlBase: account.urlBase, userId: account.userId, account: account.account) var metadatas: [tableMetadata] = [] self.getCameraRollAssets(viewController: viewController, account: account, selector: selector, alignPhotoLibrary: false) { assets in guard let assets = assets, !assets.isEmpty else { NKCommon.shared.writeLog("[INFO] Automatic upload, no new assets found [" + log + "]") completion(0) return } NKCommon.shared.writeLog("[INFO] Automatic upload, new \(assets.count) assets found [" + log + "]") // Create the folder for auto upload & if request the subfolders if !NCNetworking.shared.createFolder(assets: assets, selector: selector, useSubFolder: account.autoUploadCreateSubfolder, account: account.account, urlBase: account.urlBase, userId: account.userId) { if selector == NCGlobal.shared.selectorUploadAutoUploadAll { let error = NKError(errorCode: NCGlobal.shared.errorInternalError, errorDescription: "_error_createsubfolders_upload_") NCContentPresenter.shared.showError(error: error, priority: .max) } return completion(0) } self.endForAssetToUpload = false for asset in assets { var livePhoto = false var session: String = "" let dateFormatter = DateFormatter() let assetDate = asset.creationDate ?? Date() dateFormatter.dateFormat = "yyyy" let year = dateFormatter.string(from: assetDate) dateFormatter.dateFormat = "MM" let month = dateFormatter.string(from: assetDate) let assetMediaType = asset.mediaType var serverUrl: String = "" let fileName = CCUtility.createFileName(asset.value(forKey: "filename") as? String, fileDate: assetDate, fileType: assetMediaType, keyFileName: NCGlobal.shared.keyFileNameAutoUploadMask, keyFileNameType: NCGlobal.shared.keyFileNameAutoUploadType, keyFileNameOriginal: NCGlobal.shared.keyFileNameOriginalAutoUpload, forcedNewFileName: false)! if asset.mediaSubtypes.contains(.photoLive) && CCUtility.getLivePhoto() { livePhoto = true } if selector == NCGlobal.shared.selectorUploadAutoUploadAll { session = NKCommon.shared.sessionIdentifierUpload } else { if assetMediaType == PHAssetMediaType.image && account.autoUploadWWAnPhoto == false { session = NCNetworking.shared.sessionIdentifierBackground } else if assetMediaType == PHAssetMediaType.video && account.autoUploadWWAnVideo == false { session = NCNetworking.shared.sessionIdentifierBackground } else if assetMediaType == PHAssetMediaType.image && account.autoUploadWWAnPhoto { session = NCNetworking.shared.sessionIdentifierBackgroundWWan } else if assetMediaType == PHAssetMediaType.video && account.autoUploadWWAnVideo { session = NCNetworking.shared.sessionIdentifierBackgroundWWan } else { session = NCNetworking.shared.sessionIdentifierBackground } } if account.autoUploadCreateSubfolder { serverUrl = autoUploadPath + "/" + year + "/" + month } else { serverUrl = autoUploadPath } // MOST COMPATIBLE SEARCH --> HEIC --> JPG var fileNameSearchMetadata = fileName let ext = (fileNameSearchMetadata as NSString).pathExtension.uppercased() if ext == "HEIC" && CCUtility.getFormatCompatibility() { fileNameSearchMetadata = (fileNameSearchMetadata as NSString).deletingPathExtension + ".jpg" } if NCManageDatabase.shared.getMetadata(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@ AND fileNameView == %@", account.account, serverUrl, fileNameSearchMetadata)) != nil { if selector == NCGlobal.shared.selectorUploadAutoUpload { NCManageDatabase.shared.addPhotoLibrary([asset], account: account.account) } } else { let metadata = NCManageDatabase.shared.createMetadata(account: account.account, user: account.user, userId: account.userId, fileName: fileName, fileNameView: fileName, ocId: NSUUID().uuidString, serverUrl: serverUrl, urlBase: account.urlBase, url: "", contentType: "", isLivePhoto: livePhoto) metadata.assetLocalIdentifier = asset.localIdentifier metadata.session = session metadata.sessionSelector = selector metadata.status = NCGlobal.shared.metadataStatusWaitUpload if assetMediaType == PHAssetMediaType.video { metadata.classFile = NKCommon.typeClassFile.video.rawValue } else if assetMediaType == PHAssetMediaType.image { metadata.classFile = NKCommon.typeClassFile.image.rawValue } if selector == NCGlobal.shared.selectorUploadAutoUpload { NKCommon.shared.writeLog("[INFO] Automatic upload added \(metadata.fileNameView) with Identifier \(metadata.assetLocalIdentifier)") NCManageDatabase.shared.addPhotoLibrary([asset], account: account.account) } metadatas.append(metadata) } } self.endForAssetToUpload = true NKCommon.shared.writeLog("[INFO] Start createProcessUploads") NCNetworkingProcessUpload.shared.createProcessUploads(metadatas: metadatas, completion: completion) } } // MARK: - @objc func alignPhotoLibrary(viewController: UIViewController?) { guard let activeAccount = NCManageDatabase.shared.getActiveAccount() else { return } getCameraRollAssets(viewController: viewController, account: activeAccount, selector: NCGlobal.shared.selectorUploadAutoUploadAll, alignPhotoLibrary: true) { assets in NCManageDatabase.shared.clearTable(tablePhotoLibrary.self, account: activeAccount.account) guard let assets = assets else { return } NCManageDatabase.shared.addPhotoLibrary(assets, account: activeAccount.account) NKCommon.shared.writeLog("[INFO] Align Photo Library \(assets.count)") } } private func getCameraRollAssets(viewController: UIViewController?, account: tableAccount, selector: String, alignPhotoLibrary: Bool, completion: @escaping (_ assets: [PHAsset]?) -> Void) { NCAskAuthorization.shared.askAuthorizationPhotoLibrary(viewController: viewController) { hasPermission in guard hasPermission else { completion(nil) return } let assetCollection = PHAssetCollection.fetchAssetCollections(with: PHAssetCollectionType.smartAlbum, subtype: PHAssetCollectionSubtype.smartAlbumUserLibrary, options: nil) if assetCollection.count == 0 { completion(nil) return } let predicateImage = NSPredicate(format: "mediaType == %i", PHAssetMediaType.image.rawValue) let predicateVideo = NSPredicate(format: "mediaType == %i", PHAssetMediaType.video.rawValue) var predicate: NSPredicate? let fetchOptions = PHFetchOptions() var newAssets: [PHAsset] = [] if alignPhotoLibrary || (account.autoUploadImage && account.autoUploadVideo) { predicate = NSCompoundPredicate(orPredicateWithSubpredicates: [predicateImage, predicateVideo]) } else if account.autoUploadImage { predicate = predicateImage } else if account.autoUploadVideo { predicate = predicateVideo } else { return completion(nil) } fetchOptions.predicate = predicate let assets: PHFetchResult = PHAsset.fetchAssets(in: assetCollection.firstObject!, options: fetchOptions) if selector == NCGlobal.shared.selectorUploadAutoUpload { let idAssets = NCManageDatabase.shared.getPhotoLibraryIdAsset(image: account.autoUploadImage, video: account.autoUploadVideo, account: account.account) assets.enumerateObjects { asset, _, _ in var creationDateString = "" if let creationDate = asset.creationDate { creationDateString = String(describing: creationDate) } let idAsset = account.account + asset.localIdentifier + creationDateString if !(idAssets?.contains(idAsset) ?? false) { newAssets.append(asset) } } } else { assets.enumerateObjects { asset, _, _ in newAssets.append(asset) } } completion(newAssets) } } }