Skip to content

Commit

Permalink
video support, close #6 also close #19
Browse files Browse the repository at this point in the history
  • Loading branch information
castdrian committed Jul 24, 2023
1 parent a27e9b7 commit 8ff171f
Show file tree
Hide file tree
Showing 7 changed files with 142 additions and 13 deletions.
12 changes: 11 additions & 1 deletion ishare/App.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ struct ishare: App {

class AppDelegate: NSObject, NSApplicationDelegate {
static private(set) var shared: AppDelegate! = nil

func application(_ application: NSApplication, open urls: [URL]) {
if urls.count == 1 {
importIscu(urls.first!)
Expand All @@ -43,6 +43,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
}()

var isIconShown = false
var recordingTask: Process?

func applicationDidFinishLaunching(_ notification: Notification) {
AppDelegate.shared = self
Expand All @@ -59,5 +60,14 @@ class AppDelegate: NSObject, NSApplicationDelegate {
} else {
statusBarItem.button?.image = nil
}

if !isIconShown {
stopRecording()
}
}

func stopRecording() {
recordingTask?.interrupt()
recordingTask = nil
}
}
6 changes: 4 additions & 2 deletions ishare/Http/Custom.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ enum CustomUploadError: Error {
}

func customUpload(fileURL: URL, specification: CustomUploader, callback: ((Error?, URL?) -> Void)? = nil, completion: @escaping () -> Void) {
@Default(.imageFileFormName) var imageFileFormName
@Default(.captureFileType) var fileType

guard specification.isValid() else {
Expand All @@ -32,6 +31,9 @@ func customUpload(fileURL: URL, specification: CustomUploader, callback: ((Error
if let requestHeaders = specification.headers {
headers = HTTPHeaders(requestHeaders)
}

let fileFormName = fileURL.pathExtension == "mov" ? "video" : "image"
let mimeType = fileURL.pathExtension == "mov" ? "video/mov" : "image/\(fileType)"

AF.upload(multipartFormData: { multipartFormData in
if let formData = specification.formData {
Expand All @@ -41,7 +43,7 @@ func customUpload(fileURL: URL, specification: CustomUploader, callback: ((Error
}

let fileData = try? Data(contentsOf: fileURL)
multipartFormData.append(fileData!, withName: specification.fileFormName ?? imageFileFormName, fileName: fileURL.lastPathComponent, mimeType: "image/\(fileType)")
multipartFormData.append(fileData!, withName: specification.fileFormName ?? fileFormName, fileName: fileURL.lastPathComponent, mimeType: mimeType)
}, to: url, method: .post, headers: headers).response { response in
if let data = response.data {
let json = JSON(data)
Expand Down
6 changes: 5 additions & 1 deletion ishare/Http/Imgur.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,12 @@ func imgurUpload(_ fileURL: URL, completion: @escaping () -> Void) {

let url = "https://api.imgur.com/3/upload"

let fileFormName = fileURL.pathExtension == "mov" ? "video" : "image"
let fileName = fileURL.pathExtension == "mov" ? "ishare.mov" : "ishare.\(fileType)"
let mimeType = fileURL.pathExtension == "mov" ? "video/mov" : "image/\(fileType)"

AF.upload(multipartFormData: { multipartFormData in
multipartFormData.append(fileURL, withName: "image", fileName: "ishare.\(fileType)", mimeType: "image/\(fileType)")
multipartFormData.append(fileURL, withName: fileFormName, fileName: fileName, mimeType: mimeType)
}, to: url, method: .post, headers: ["Authorization": "Client-ID " + imgurClientId]).response { response in
if let data = response.data {
let json = JSON(data)
Expand Down
3 changes: 2 additions & 1 deletion ishare/Util/Constants.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,15 @@ extension Defaults.Keys {
static let openInFinder = Key<Bool>("openInFinder", default: false)
static let uploadMedia = Key<Bool>("uploadMedia", default: false)
static let capturePath = Key<String>("capturePath", default: "~/Pictures/")
static let recordingPath = Key<String>("recordingPath", default: "~/Pictures/")
static let captureFileType = Key<FileType>("captureFileType", default: .PNG)
static let captureFileName = Key<String>("captureFileName", default: "ishare")
static let recordingFileName = Key<String>("recordingFileName", default: "ishare")
static let imgurClientId = Key<String>("imgurClientId", default: "867afe9433c0a53")
static let captureBinary = Key<String>("captureBinary", default: "/usr/sbin/screencapture")
static let activeCustomUploader = Key<UUID?>("activeCustomUploader", default: nil)
static let savedCustomUploaders = Key<Set<CustomUploader>?>("savedCustomUploaders")
static let uploadType = Key<UploadType>("uploadType", default: .IMGUR)
static let imageFileFormName = Key<String>("imageFileFormName", default: "image")
static let menuBarAppIcon = Key<Bool>("menuBarAppIcon", default: true)
static let uploadDestination = Key<UploadDestination>("uploadDestination", default: .builtIn(.IMGUR))
}
Expand Down
84 changes: 79 additions & 5 deletions ishare/Util/ScreenRecording.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,90 @@
//

import Foundation
import Defaults
import AppKit
import Cocoa

enum RecordingType: String {
case SCREEN = "-t"
case WINDOW = "-wt"
case REGION = "-st"
case SCREEN = "-v"
// case WINDOW = "-wt"
// case REGION = "-st"
}

func recordScreen(type: RecordingType, display: Int = 1) -> Void {
print("recording")
func recordScreen(type: RecordingType, display: Int = 1) {
@Default(.copyToClipboard) var copyToClipboard
@Default(.openInFinder) var openInFinder
@Default(.recordingPath) var recordingPath
@Default(.recordingFileName) var fileName
@Default(.uploadType) var uploadType
@Default(.uploadMedia) var uploadMedia

let timestamp = Int(Date().timeIntervalSince1970)
let uniqueFilename = "\(fileName)-\(timestamp)"

var path = "\(recordingPath)\(uniqueFilename).mov"
path = NSString(string: path).expandingTildeInPath

recordingTask(path: path, type: type, display: display) {
let fileURL = URL(fileURLWithPath: path)

if !FileManager.default.fileExists(atPath: fileURL.path) {
return
}

if copyToClipboard {
let pasteboard = NSPasteboard.general
pasteboard.clearContents()

pasteboard.setString(fileURL.absoluteString, forType: .fileURL)
}

if openInFinder {
NSWorkspace.shared.activateFileViewerSelecting([fileURL])
}

if uploadMedia {
uploadFile(fileURL: fileURL, uploadType: uploadType) {
showToast(fileURL: fileURL)
NSSound.beep()
}
} else {
showToast(fileURL: fileURL)
NSSound.beep()
}

deleteScreenRecordings()
}
}

func recordingTask(path: String, type: RecordingType, display: Int = 1, completion: @escaping () -> Void) {
AppDelegate.shared.toggleIcon(AppDelegate.shared as AnyObject)

@Default(.captureBinary) var captureBinary

let task = Process()
task.launchPath = captureBinary
task.arguments = type == RecordingType.SCREEN ? [type.rawValue, "-D", "\(display)", path] : [type.rawValue, path]

AppDelegate.shared.recordingTask = task

DispatchQueue.global(qos: .background).async {
task.launch()
task.waitUntilExit()

DispatchQueue.main.async {
AppDelegate.shared.recordingTask = nil
completion()
}
}
}

func deleteScreenRecordings() {
let screenRecordingsPath = FileManager.default.homeDirectoryForCurrentUser.appendingPathComponent("Library/ScreenRecordings")

do {
try FileManager.default.removeItem(at: screenRecordingsPath)
} catch {
print("Error deleting the ScreenRecordings folder: \(error)")
}
}
22 changes: 20 additions & 2 deletions ishare/Util/ToastPopover.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import SwiftUI
import AVFoundation

struct ToastPopoverView: View {
let thumbnailImage: NSImage
Expand All @@ -21,7 +22,24 @@ struct ToastPopoverView: View {
}

func showToast(fileURL: URL) {
guard let thumbnailImage = NSImage(contentsOf: fileURL) else {
var thumbnailImage: NSImage?

if fileURL.pathExtension == "mov" {
let asset = AVURLAsset(url: fileURL)
let imageGenerator = AVAssetImageGenerator(asset: asset)
imageGenerator.appliesPreferredTrackTransform = true
let time = CMTime(seconds: 2, preferredTimescale: 60)
do {
let cgImage = try imageGenerator.copyCGImage(at: time, actualTime: nil)
thumbnailImage = NSImage(cgImage: cgImage, size: CGSize(width: cgImage.width, height: cgImage.height))
} catch {
print("Error generating thumbnail: \(error)")
}
} else {
thumbnailImage = NSImage(contentsOf: fileURL)
}

guard let thumbnail = thumbnailImage else {
return
}

Expand All @@ -37,7 +55,7 @@ func showToast(fileURL: URL) {
toastWindow.backgroundColor = .clear
toastWindow.isMovableByWindowBackground = false
toastWindow.contentView = NSHostingView(
rootView: ToastPopoverView(thumbnailImage: thumbnailImage, fileURL: fileURL)
rootView: ToastPopoverView(thumbnailImage: thumbnail, fileURL: fileURL)
)

toastWindow.makeKeyAndOrderFront(nil)
Expand Down
22 changes: 21 additions & 1 deletion ishare/Views/SettingsMenuView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -127,10 +127,30 @@ struct CaptureSettingsView: View {
}

struct RecordingSettingsView: View {
@Default(.recordingPath) var recordingPath
@Default(.recordingFileName) var fileName

var body: some View {
VStack {
HStack {
}
Text("Capture path:")
TextField(text: $recordingPath) {}
Button("Select directory") {
selectFolder { folderURL in
if let url = folderURL {
recordingPath = url.path()
}
}
}
}.padding(10)

HStack {
Text("File name:")
TextField(String(), text: $fileName)
Button("Default") {
fileName = Defaults.Keys.recordingFileName.defaultValue
}
}.padding(20)
}
}
}
Expand Down

0 comments on commit 8ff171f

Please sign in to comment.