Skip to content

Commit

Permalink
Converted file behaviour and location
Browse files Browse the repository at this point in the history
  • Loading branch information
alin23 committed Aug 21, 2023
1 parent b071c8e commit b37a719
Show file tree
Hide file tree
Showing 12 changed files with 174 additions and 74 deletions.
8 changes: 4 additions & 4 deletions Clop.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,7 @@
CODE_SIGN_ENTITLEMENTS = Clop/Clop.entitlements;
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 2.1.0;
CURRENT_PROJECT_VERSION = 2.1.1;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_ASSET_PATHS = "\"Clop/Preview Content\"";
DEVELOPMENT_TEAM = RDDXV84A73;
Expand All @@ -400,7 +400,7 @@
"$(PROJECT_DIR)/Clop/bin",
);
LLVM_LTO = YES_THIN;
MARKETING_VERSION = 2.1.0;
MARKETING_VERSION = 2.1.1;
PRODUCT_BUNDLE_IDENTIFIER = com.lowtechguys.Clop;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = YES;
Expand All @@ -416,7 +416,7 @@
CODE_SIGN_ENTITLEMENTS = Clop/Clop.entitlements;
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 2.1.0;
CURRENT_PROJECT_VERSION = 2.1.1;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_ASSET_PATHS = "\"Clop/Preview Content\"";
DEVELOPMENT_TEAM = RDDXV84A73;
Expand All @@ -436,7 +436,7 @@
"$(PROJECT_DIR)/Clop/bin",
);
LLVM_LTO = YES;
MARKETING_VERSION = 2.1.0;
MARKETING_VERSION = 2.1.1;
OTHER_LDFLAGS = "";
PRODUCT_BUNDLE_IDENTIFIER = com.lowtechguys.Clop;
PRODUCT_NAME = "$(TARGET_NAME)";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@
"location" : "https://github.com/FuzzyIdeas/Lowtech",
"state" : {
"branch" : "ventura",
"revision" : "3925084e4f2529a3149959cd5f7783b2f7f598a2"
"revision" : "d37e79b4aff10663135bc48a625656679c2d7459"
}
},
{
Expand Down
3 changes: 1 addition & 2 deletions Clop/ClopApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ class AppDelegate: LowtechProAppDelegate {

let drag = NSPasteboard(name: .drag)
guard self.lastDragChangeCount != drag.changeCount else {
// print("Drag ignored: \(self.lastDragChangeCount) \(drag.changeCount) \(DM.dropped)")
return
}
DM.dropped = false
Expand Down Expand Up @@ -561,7 +560,7 @@ extension NSFilePromiseReceiver {
guard let exc else {
return
}
print(exc)
log.error(exc.description)
// Task.init {
// await showNotice("Pasteboard error in retrieving file")
// }
Expand Down
3 changes: 2 additions & 1 deletion Clop/ClopShortcuts.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import AppIntents
import Foundation
import Lowtech

enum IntentError: Swift.Error, CustomLocalizedStringResourceConvertible {
case general
Expand Down Expand Up @@ -64,7 +65,7 @@ struct OptimiseFileIntent: AppIntent {
} catch let error as ClopError {
throw IntentError.message(error.description)
} catch {
print(error)
log.error(error.localizedDescription)
throw IntentError.message(error.localizedDescription)
}

Expand Down
20 changes: 10 additions & 10 deletions Clop/ClopUtils.swift
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ func shellProc(_ launchPath: String = "/bin/zsh", args: [String], env: [String:
do {
try task.run()
} catch {
print("Error running \(launchPath) \(args): \(error)")
log.error("Error running \(launchPath) \(args): \(error)")
return nil
}

Expand Down Expand Up @@ -222,17 +222,17 @@ extension FilePath {
shell("/usr/bin/file", args: ["-b", "--mime-type", string]).o
}

func copyExif(from source: FilePath, excludeTags: [String]? = []) {
func copyExif(from source: FilePath, excludeTags: [String]? = nil) {
var additionalArgs: [String] = []
if let excludeTags {
if let excludeTags, excludeTags.isNotEmpty {
additionalArgs += ["-x"] + excludeTags.map { [$0] }.joined(separator: ["-x"]).map { $0 }
}
let args = [EXIFTOOL, "-overwrite_original", "-XResolution=72", "-YResolution=72"] + additionalArgs + ["-TagsFromFile", source.string, string]
let args = [EXIFTOOL, "-overwrite_original", "-XResolution=72", "-YResolution=72"] + additionalArgs + ["-tagsFromFile", source.string, string]
let exifProc = shell("/usr/bin/perl5.30", args: args, wait: true)

#if DEBUG
debug(args.joined(separator: " "))
debug("\tout=\(exifProc.o ?? "") err=\(exifProc.e ?? "")")
log.debug(args.joined(separator: " "))
log.debug("\tout=\(exifProc.o ?? "") err=\(exifProc.e ?? "")")
#endif
}

Expand Down Expand Up @@ -286,7 +286,7 @@ func tryProcs(_ procs: [Proc], tries: Int, captureOutput: Bool = false, beforeWa
var outPipes = procs.dict { ($0, Pipe()) }
var errPipes = procs.dict { ($0, Pipe()) }

print("Starting\n\t\(procs.map(\.cmdline).joined(separator: "\n\t"))")
log.debug("Starting\n\t\(procs.map(\.cmdline).joined(separator: "\n\t"))")
var processes: [Proc: Process] = procs.dict { proc in
guard let p = shellProc(proc.cmd, args: proc.args, out: outPipes[proc]!, err: errPipes[proc]!)
else { return nil }
Expand All @@ -306,7 +306,7 @@ func tryProcs(_ procs: [Proc], tries: Int, captureOutput: Bool = false, beforeWa
return (p, proc)
}

print("Retry \(tryNum): \(p.cmdline)")
log.debug("Retry \(tryNum): \(p.cmdline)")
outPipes[p]!.fileHandleForReading.readabilityHandler = nil
errPipes[p]!.fileHandleForReading.readabilityHandler = nil
outPipes[p] = Pipe()
Expand All @@ -329,7 +329,7 @@ func tryProc(_ cmd: String, args: [String], tries: Int, captureOutput: Bool = fa
var errPipe = Pipe()

let cmdline = "\(cmd) \(args.joined(separator: " "))"
print("Starting \(cmdline)")
log.debug("Starting \(cmdline)")
guard var proc = shellProc(cmd, args: args, out: outPipe, err: errPipe) else {
throw ClopError.noProcess(cmd)
}
Expand All @@ -342,7 +342,7 @@ func tryProc(_ cmd: String, args: [String], tries: Int, captureOutput: Bool = fa
break
}

print("Retry \(tryNum): \(cmdline)")
log.debug("Retry \(tryNum): \(cmdline)")
outPipe.fileHandleForReading.readabilityHandler = nil
errPipe.fileHandleForReading.readabilityHandler = nil
outPipe = Pipe()
Expand Down
57 changes: 34 additions & 23 deletions Clop/Images.swift
Original file line number Diff line number Diff line change
Expand Up @@ -611,7 +611,7 @@ class Image: CustomStringConvertible {

}

print("\(event.path): \(flag)")
log.debug("\(event.path): \(flag)")

guard fm.fileExists(atPath: event.path), !event.path.contains(FilePath.backups.string),
flag.isDisjoint(with: [.historyDone, .itemRemoved]), flag.contains(.itemIsFile), flag.hasElements(from: [.itemCreated, .itemRenamed, .itemModified]),
Expand Down Expand Up @@ -646,31 +646,39 @@ class Image: CustomStringConvertible {
var pathString = path.string

guard img.type != .tiff || (allowTiff ?? Defaults[.optimiseTIFF]) else {
print("Skipping image \(pathString) because TIFF optimisation is disabled")
log.debug("Skipping image \(pathString) because TIFF optimisation is disabled")
throw ClopError.skippedType("TIFF optimisation is disabled")
}

if id == Optimiser.IDs.clipboardImage, pauseForNextClipboardEvent {
print("Skipping image \(pathString) because it was paused")
log.debug("Skipping image \(pathString) because it was paused")
pauseForNextClipboardEvent = false
throw ClopError.optimisationPaused(path)
}

var allowLarger = allowLarger
var originalPath: FilePath?
let applyConversionBehaviour: (Image, Image) throws -> Image = { img, converted in
let behaviour = Defaults[.convertedImageBehaviour]
if behaviour == .inPlace {
img.path.backup(force: true, operation: .move)
}
if behaviour != .temporary {
try converted.path.setOptimisationStatusXattr("pending")
let path = try converted.path.copy(to: img.path.dir)
originalPath = img.path
return Image(data: converted.data, path: path, nsImage: converted.image, type: converted.type, optimised: converted.optimised, retinaDownscaled: converted.retinaDownscaled)
}
return converted
}

switch img.type {
case Defaults[.formatsToConvertToJPEG]:
let converted = try img.convert(to: .jpeg)
img = converted
pathString = img.path.string
allowLarger = true
case Defaults[.formatsToConvertToPNG]:
let converted = try img.convert(to: .png)
img = converted
let conversionFormat: UTType? = Defaults[.formatsToConvertToJPEG].contains(img.type) ? .jpeg : (Defaults[.formatsToConvertToPNG].contains(img.type) ? .png : nil)
if let conversionFormat {
let converted = try img.convert(to: conversionFormat)

img = try applyConversionBehaviour(img, converted)
pathString = img.path.string
allowLarger = true
default:
break
}

let optimiser = OM.optimiser(
Expand All @@ -681,6 +689,9 @@ class Image: CustomStringConvertible {
optimiser.downscaleFactor = 1.0
optimiser.newSize = nil
optimiser.newBytes = -1
if let url = originalPath?.url {
optimiser.convertedFromURL = url
}

var done = false
var result: Image?
Expand Down Expand Up @@ -712,7 +723,7 @@ class Image: CustomStringConvertible {
let shouldDownscale = Defaults[.downscaleRetinaImages] && img.pixelScale > 1
var optimisedImage: Image?
do {
print("Optimising image \(pathString)")
log.debug("Optimising image \(pathString)")
if shouldDownscale {
img.retinaDownscaled = true
mainActor { optimiser.retinaDownscaled = true }
Expand All @@ -728,16 +739,16 @@ class Image: CustomStringConvertible {
}
} catch let ClopError.processError(proc) {
if proc.terminated {
debug("Process terminated by us: \(proc.commandLine)")
log.debug("Process terminated by us: \(proc.commandLine)")
} else {
err("Error optimising image \(pathString): \(proc.commandLine)")
log.error("Error optimising image \(pathString): \(proc.commandLine)")
optimiser.finish(error: "Optimisation failed")
}
} catch let error as ClopError {
err("Error optimising image \(pathString): \(error.description)")
log.error("Error optimising image \(pathString): \(error.description)")
optimiser.finish(error: error.humanDescription)
} catch {
err("Error optimising image \(pathString): \(error)")
log.error("Error optimising image \(pathString): \(error)")
optimiser.finish(error: "Optimisation failed")
}

Expand Down Expand Up @@ -835,16 +846,16 @@ class Image: CustomStringConvertible {
}
} catch let ClopError.processError(proc) {
if proc.terminated {
debug("Process terminated by us: \(proc.commandLine)")
log.debug("Process terminated by us: \(proc.commandLine)")
} else {
err("Error downscaling image \(img.path.string): \(proc.commandLine)")
log.error("Error downscaling image \(img.path.string): \(proc.commandLine)")
mainActor { optimiser.finish(error: "Downscaling failed") }
}
} catch let error as ClopError {
err("Error downscaling image \(img.path.string): \(error.description)")
log.error("Error downscaling image \(img.path.string): \(error.description)")
mainActor { optimiser.finish(error: error.humanDescription) }
} catch {
err("Error downscaling image \(img.path.string): \(error)")
log.error("Error downscaling image \(img.path.string): \(error)")
mainActor { optimiser.finish(error: "Optimisation failed") }
}
}
Expand Down
44 changes: 35 additions & 9 deletions Clop/OptimisationUtils.swift
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ class OptimiserProgressDelegate: NSObject, URLSessionDataDelegate {
let optimiser: Optimiser

nonisolated func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
debug("Finished downloading \(location.path)")
log.debug("Finished downloading \(location.path)")
}

func handleTask(_ task: URLSessionTask) {
Expand Down Expand Up @@ -211,6 +211,7 @@ final class Optimiser: ObservableObject, Identifiable, Hashable, Equatable, Cust
@Published var thumbnail: NSImage?
@Published var originalURL: URL?
@Published var startingURL: URL?
@Published var convertedFromURL: URL?

@Published var downscaleFactor = 1.0
@Published var aggresive = false
Expand Down Expand Up @@ -239,7 +240,7 @@ final class Optimiser: ObservableObject, Identifiable, Hashable, Equatable, Cust
}
@Published var url: URL? {
didSet {
print("URL set to \(url?.path ?? "nil") from \(oldValue?.path ?? "nil")")
log.debug("URL set to \(url?.path ?? "nil") from \(oldValue?.path ?? "nil")")
if startingURL == nil {
startingURL = url
}
Expand Down Expand Up @@ -381,18 +382,36 @@ final class Optimiser: ObservableObject, Identifiable, Hashable, Equatable, Cust
aggresive = false
resetRemover()

let restore: (FilePath) -> Void = { path in
try? path.backupPath?.setOptimisationStatusXattr("original")
path.restore()
}

let path: FilePath
if let startingURL, let startingPath = startingURL.existingFilePath, startingPath.backupPath?.exists ?? false {
if let convertedFromURL {
self.url = convertedFromURL
path = convertedFromURL.filePath

if path.backupPath?.exists ?? false {
restore(path)
}

if let startingPath = startingURL?.existingFilePath, startingPath != path, startingPath.stem == path.stem, startingPath.dir == path.dir {
try? startingPath.delete()
}
} else if let startingURL, startingURL.filePath.backupPath?.exists ?? false {
path = startingURL.filePath
self.url = startingURL
startingPath.restore(force: true)
path = startingPath

restore(path)
} else if let originalURL {
self.url = originalURL
path = originalURL.filePath
} else {
url.filePath.restore()
path = url.filePath
restore(path)
}
self.oldBytes = path.fileSize() ?? self.oldBytes
self.newBytes = -1
self.newSize = nil

Expand Down Expand Up @@ -510,8 +529,14 @@ class OptimisationManager: ObservableObject, QLPreviewPanelDataSource {

@Published var optimisers: Set<Optimiser> = [] {
didSet {
print("Removed optimisers: \(oldValue.subtracting(optimisers))")
print("Added optimisers: \(optimisers.subtracting(oldValue))")
let removed = oldValue.subtracting(optimisers)
let added = optimisers.subtracting(oldValue)
if !removed.isEmpty {
log.debug("Removed optimisers: \(removed)")
}
if !added.isEmpty {
log.debug("Added optimisers: \(added)")
}
}
}

Expand All @@ -532,6 +557,7 @@ class OptimisationManager: ObservableObject, QLPreviewPanelDataSource {
optimiser.running = true
optimiser.hidden = hidden
optimiser.progress.completedUnitCount = 0
optimiser.isOriginal = false

if !OM.optimisers.contains(optimiser) {
OM.optimisers = OM.optimisers.with(optimiser)
Expand Down Expand Up @@ -576,7 +602,7 @@ func tryAsync(_ action: @escaping () async throws -> Void) {
do {
try await action()
} catch {
print(error)
log.error(error.localizedDescription)
}
}
}
Expand Down
10 changes: 9 additions & 1 deletion Clop/Settings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,13 @@ public extension Defaults.Keys {
static let enableClipboardOptimiser = Key<Bool>("enableClipboardOptimiser", default: true)
static let optimiseVideoClipboard = Key<Bool>("optimiseVideoClipboard", default: false)
static let optimiseImagePathClipboard = Key<Bool>("optimiseImagePathClipboard", default: false)
static let convertInPlace = Key<Bool>("convertInPlace", default: false)

static let formatsToConvertToJPEG = Key<Set<UTType>>("formatsToConvertToJPEG", default: [UTType.webP, UTType.avif, UTType.heic, UTType.bmp].compactMap { $0 }.set)
static let formatsToConvertToPNG = Key<Set<UTType>>("formatsToConvertToPNG", default: [.tiff])
static let formatsToConvertToMP4 = Key<Set<UTType>>("formatsToConvertToMP4", default: [UTType.quickTimeMovie, UTType.mpeg2Video, UTType.mpeg, UTType.webm].compactMap { $0 }.set)
static let convertedImageBehaviour = Key<ConvertedFileBehaviour>("convertedImageBehaviour", default: .sameFolder)
static let convertedVideoBehaviour = Key<ConvertedFileBehaviour>("convertedVideoBehaviour", default: .sameFolder)

static let capVideoFPS = Key<Bool>("capVideoFPS", default: true)
static let targetVideoFPS = Key<Float>("targetVideoFPS", default: 60)
static let minVideoFPS = Key<Float>("minVideoFPS", default: 30)
Expand Down Expand Up @@ -88,3 +90,9 @@ public extension Defaults.Keys {
static let quickResizeKeys = Key<[SauceKey]>("quickResizeKeys", default: [.five, .three])
static let enabledKeys = Key<[SauceKey]>("enabledKeys", default: [.minus, .equal, .delete, .space, .z, .p, .c, .a])
}

public enum ConvertedFileBehaviour: String, Defaults.Serializable {
case temporary
case inPlace
case sameFolder
}
Loading

0 comments on commit b37a719

Please sign in to comment.