Skip to content

Commit

Permalink
add Italian localization; add MP3 support; fixed system sound; fixed …
Browse files Browse the repository at this point in the history
…video trimmer
  • Loading branch information
lihaoyun6 committed May 20, 2024
1 parent bee346a commit 613bba7
Show file tree
Hide file tree
Showing 9 changed files with 106 additions and 21 deletions.
32 changes: 28 additions & 4 deletions QuickRecorder.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
18D3BE012BCEB1BF006CFFC0 /* AppSelector.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18D3BE002BCEB1BF006CFFC0 /* AppSelector.swift */; };
18D3BE042BCEC847006CFFC0 /* SCContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18D3BE032BCEC847006CFFC0 /* SCContext.swift */; };
18F1A0E22BD3E4C000DB102C /* AreaSelector.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18F1A0E12BD3E4C000DB102C /* AreaSelector.swift */; };
18F40B492BFB988A00F0AC70 /* SwiftLAME in Frameworks */ = {isa = PBXBuildFile; productRef = 18F40B482BFB988A00F0AC70 /* SwiftLAME */; };
18FDFC8E2BDA435F0020E685 /* ScreenMagnifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18FDFC8D2BDA435F0020E685 /* ScreenMagnifier.swift */; };
18FDFC912BDA4DB30020E685 /* KeyboardShortcuts in Frameworks */ = {isa = PBXBuildFile; productRef = 18FDFC902BDA4DB30020E685 /* KeyboardShortcuts */; };
18FEBDAA2BCF8200003F09BC /* RecordEngine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18FEBDA92BCF8200003F09BC /* RecordEngine.swift */; };
Expand All @@ -46,6 +47,9 @@
189BD5EC2BDE971B0056D06C /* VideoEditor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoEditor.swift; sourceTree = "<group>"; };
189BD5F42BDF8A800056D06C /* CameraOverlayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraOverlayer.swift; sourceTree = "<group>"; };
189BD5F62BDFDF200056D06C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
18A735972BFBA12F002314AF /* it */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; name = it; path = it.lproj/Credits.rtf; sourceTree = "<group>"; };
18A735982BFBA132002314AF /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/Localizable.strings; sourceTree = "<group>"; };
18A735992BFBA138002314AF /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/InfoPlist.strings; sourceTree = "<group>"; };
18D3BDE72BCE5DC1006CFFC0 /* QuickRecorder.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = QuickRecorder.app; sourceTree = BUILT_PRODUCTS_DIR; };
18D3BDEA2BCE5DC1006CFFC0 /* QuickRecorderApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickRecorderApp.swift; sourceTree = "<group>"; };
18D3BDEC2BCE5DC1006CFFC0 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
Expand All @@ -71,6 +75,7 @@
files = (
18FDFC912BDA4DB30020E685 /* KeyboardShortcuts in Frameworks */,
181724052BE3BEA600F5F539 /* Sparkle in Frameworks */,
18F40B492BFB988A00F0AC70 /* SwiftLAME in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -168,6 +173,7 @@
packageProductDependencies = (
18FDFC902BDA4DB30020E685 /* KeyboardShortcuts */,
181724042BE3BEA600F5F539 /* Sparkle */,
18F40B482BFB988A00F0AC70 /* SwiftLAME */,
);
productName = QuickRecorder;
productReference = 18D3BDE72BCE5DC1006CFFC0 /* QuickRecorder.app */;
Expand Down Expand Up @@ -196,11 +202,13 @@
en,
Base,
"zh-Hans",
it,
);
mainGroup = 18D3BDDE2BCE5DC1006CFFC0;
packageReferences = (
18FDFC8F2BDA4DB30020E685 /* XCRemoteSwiftPackageReference "KeyboardShortcuts" */,
181724032BE3BEA600F5F539 /* XCRemoteSwiftPackageReference "Sparkle" */,
18F40B472BFB988A00F0AC70 /* XCRemoteSwiftPackageReference "SwiftLAME" */,
);
productRefGroup = 18D3BDE82BCE5DC1006CFFC0 /* Products */;
projectDirPath = "";
Expand Down Expand Up @@ -260,6 +268,7 @@
children = (
1862BF902BD5494F003ED522 /* zh-Hans */,
1862BF912BD5495D003ED522 /* Base */,
18A735972BFBA12F002314AF /* it */,
);
name = Credits.rtf;
sourceTree = "<group>";
Expand All @@ -268,6 +277,7 @@
isa = PBXVariantGroup;
children = (
189BD5E72BDE34B80056D06C /* zh-Hans */,
18A735992BFBA138002314AF /* it */,
);
name = InfoPlist.strings;
sourceTree = "<group>";
Expand All @@ -276,6 +286,7 @@
isa = PBXVariantGroup;
children = (
18D3BDFC2BCE5DF5006CFFC0 /* zh-Hans */,
18A735982BFBA132002314AF /* it */,
);
name = Localizable.strings;
sourceTree = "<group>";
Expand Down Expand Up @@ -409,7 +420,7 @@
CODE_SIGN_ENTITLEMENTS = QuickRecorder/QuickRecorder.entitlements;
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 124;
CURRENT_PROJECT_VERSION = 125;
DEVELOPMENT_ASSET_PATHS = "\"QuickRecorder/Preview Content\"";
DEVELOPMENT_TEAM = L4T783637F;
ENABLE_HARDENED_RUNTIME = YES;
Expand All @@ -425,7 +436,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 12.3;
MARKETING_VERSION = 1.2.4;
MARKETING_VERSION = 1.2.5;
PRODUCT_BUNDLE_IDENTIFIER = com.lihaoyun6.QuickRecorder;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = YES;
Expand All @@ -441,7 +452,7 @@
CODE_SIGN_ENTITLEMENTS = QuickRecorder/QuickRecorder.entitlements;
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 124;
CURRENT_PROJECT_VERSION = 125;
DEVELOPMENT_ASSET_PATHS = "\"QuickRecorder/Preview Content\"";
DEVELOPMENT_TEAM = L4T783637F;
ENABLE_HARDENED_RUNTIME = YES;
Expand All @@ -457,7 +468,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 12.3;
MARKETING_VERSION = 1.2.4;
MARKETING_VERSION = 1.2.5;
PRODUCT_BUNDLE_IDENTIFIER = com.lihaoyun6.QuickRecorder;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = YES;
Expand Down Expand Up @@ -497,6 +508,14 @@
minimumVersion = 2.6.0;
};
};
18F40B472BFB988A00F0AC70 /* XCRemoteSwiftPackageReference "SwiftLAME" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/hidden-spectrum/SwiftLAME.git";
requirement = {
kind = revision;
revision = e8256a8151594f47f103c742f684253c6c44871d;
};
};
18FDFC8F2BDA4DB30020E685 /* XCRemoteSwiftPackageReference "KeyboardShortcuts" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/sindresorhus/KeyboardShortcuts.git";
Expand All @@ -513,6 +532,11 @@
package = 181724032BE3BEA600F5F539 /* XCRemoteSwiftPackageReference "Sparkle" */;
productName = Sparkle;
};
18F40B482BFB988A00F0AC70 /* SwiftLAME */ = {
isa = XCSwiftPackageProductDependency;
package = 18F40B472BFB988A00F0AC70 /* XCRemoteSwiftPackageReference "SwiftLAME" */;
productName = SwiftLAME;
};
18FDFC902BDA4DB30020E685 /* KeyboardShortcuts */ = {
isa = XCSwiftPackageProductDependency;
package = 18FDFC8F2BDA4DB30020E685 /* XCRemoteSwiftPackageReference "KeyboardShortcuts" */;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@
"revision" : "0a4caaf7a81eea2cece651ef4b17331fa0634dff",
"version" : "2.6.0"
}
},
{
"identity" : "swiftlame",
"kind" : "remoteSourceControl",
"location" : "https://github.com/hidden-spectrum/SwiftLAME.git",
"state" : {
"revision" : "e8256a8151594f47f103c742f684253c6c44871d"
}
}
],
"version" : 2
Expand Down
2 changes: 1 addition & 1 deletion QuickRecorder/QuickRecorderApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -403,7 +403,7 @@ extension NSImage {

enum AudioQuality: Int { case normal = 128, good = 192, high = 256, extreme = 320 }

enum AudioFormat: String { case aac, alac, flac, opus }
enum AudioFormat: String { case aac, alac, flac, opus, mp3 }

enum VideoFormat: String { case mov, mp4 }

Expand Down
14 changes: 8 additions & 6 deletions QuickRecorder/RecordEngine.swift
Original file line number Diff line number Diff line change
Expand Up @@ -139,11 +139,12 @@ extension AppDelegate {
if ud.string(forKey: "background") != BackgroundType.wallpaper.rawValue { conf.backgroundColor = SCContext.getBackgroundColor() }
if let colorSpace = SCContext.getColorSpace() { conf.colorSpaceName = colorSpace }
if ud.bool(forKey: "withAlpha") { conf.pixelFormat = kCVPixelFormatType_32BGRA }
if #available(macOS 13, *) {
conf.capturesAudio = ud.bool(forKey: "recordWinSound") || fastStart
conf.sampleRate = SCContext.audioSettings["AVSampleRateKey"] as! Int
conf.channelCount = SCContext.audioSettings["AVNumberOfChannelsKey"] as! Int
}
}

if #available(macOS 13, *) {
conf.capturesAudio = ud.bool(forKey: "recordWinSound") || fastStart
conf.sampleRate = SCContext.audioSettings["AVSampleRateKey"] as! Int
conf.channelCount = SCContext.audioSettings["AVNumberOfChannelsKey"] as! Int
}

conf.minimumFrameInterval = CMTime(value: 1, timescale: audioOnly ? CMTimeScale.max : CMTimeScale(ud.integer(forKey: "frameRate")))
Expand Down Expand Up @@ -177,13 +178,14 @@ extension AppDelegate {
assertionFailure("capture failed".local)
return
}
registerGlobalMouseMonitor()
if !audioOnly { registerGlobalMouseMonitor() }
DispatchQueue.main.async { [self] in updateStatusBar() }
}

func prepareAudioRecording() {
var fileEnding = ud.string(forKey: "audioFormat") ?? "wat"
switch fileEnding { // todo: I'd like to store format info differently
case AudioFormat.mp3.rawValue: fallthrough
case AudioFormat.aac.rawValue: fallthrough
case AudioFormat.alac.rawValue: fileEnding = "m4a"
case AudioFormat.flac.rawValue: fileEnding = "flac"
Expand Down
68 changes: 59 additions & 9 deletions QuickRecorder/SCContext.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import AVFoundation
import Foundation
import ScreenCaptureKit
import UserNotifications
import SwiftLAME

class SCContext {
static var autoStop = 0
Expand Down Expand Up @@ -165,6 +166,7 @@ class SCContext {
static func updateAudioSettings() {
audioSettings = [AVSampleRateKey : 48000, AVNumberOfChannelsKey : 2] // reset audioSettings
switch ud.string(forKey: "audioFormat") {
case AudioFormat.mp3.rawValue: fallthrough
case AudioFormat.aac.rawValue:
audioSettings[AVFormatIDKey] = kAudioFormatMPEG4AAC
audioSettings[AVEncoderBitRateKey] = ud.integer(forKey: "audioQuality") * 1000
Expand Down Expand Up @@ -343,29 +345,77 @@ class SCContext {
}
}

audioFile = nil // close audio file
if streamType == .systemaudio {
if ud.string(forKey: "audioFormat") == AudioFormat.mp3.rawValue {
Task {
let outPutUrl = URL(fileURLWithPath: String(filePath.dropLast(4)) + ".mp3")
do {
try await m4a2mp3(inputUrl: URL(fileURLWithPath: filePath), outputUrl: outPutUrl)
let title = "Recording Completed".local
let body = String(format: "File saved to: %@".local, outPutUrl.path.removingPercentEncoding!)
let id = "quickrecorder.completed.\(Date.now)"
showNotification(title: title, body: body, id: id)
} catch {
showNotification(title: "Failed to save file".local, body: "\(error.localizedDescription)", id: "quickrecorder.error.\(Date.now)")
}
}
} else {
let title = "Recording Completed".local
var body = String(format: "File saved to folder: %@".local, ud.string(forKey: "saveDirectory")!)
if let filePath = filePath { body = String(format: "File saved to: %@".local, filePath) }
let id = "quickrecorder.completed.\(Date.now)"
showNotification(title: title, body: body, id: id)
}
}

isPaused = false
hideMousePointer = false
streamType = nil
//previewType = nil
audioFile = nil // close audio file
window = nil
screen = nil
startTime = nil
AppDelegate.shared.presenterType = "OFF"
AppDelegate.shared.updateStatusBar()

if !(ud.bool(forKey: "recordMic") && ud.bool(forKey: "recordWinSound") && ud.bool(forKey: "remuxAudio")) && vW.status == .completed {
if !(ud.bool(forKey: "recordMic") && ud.bool(forKey: "recordWinSound") && ud.bool(forKey: "remuxAudio")) && streamType != .systemaudio {
let title = "Recording Completed".local
var body = String(format: "File saved to folder: %@".local, ud.string(forKey: "saveDirectory")!)
if let filePath = filePath { body = String(format: "File saved to: %@".local, filePath) }
let id = "quickrecorder.completed.\(Date.now)"
showNotification(title: title, body: body, id: id)

if ud.bool(forKey: "trimAfterRecord") {
let fileURL = URL(fileURLWithPath: filePath)
AppDelegate.shared.createNewWindow(view: VideoTrimmerView(videoURL: fileURL), title: fileURL.lastPathComponent)
if let vW = vW {
if vW.status == .completed {
showNotification(title: title, body: body, id: id)
trimVideo()
}
} else {
showNotification(title: title, body: body, id: id)
trimVideo()
}
}

streamType = nil
}

static func m4a2mp3(inputUrl: URL, outputUrl: URL) async throws {
let progress = Progress()
let lameEncoder = try SwiftLameEncoder(
sourceUrl: inputUrl,
configuration: .init(
sampleRate: .custom(48000),
bitrateMode: .constant(Int32(ud.integer(forKey: "audioQuality"))),
quality: .nearBest
),
destinationUrl: outputUrl,
progress: progress // optional
)
try await lameEncoder.encode(priority: .userInitiated)
}

static func trimVideo() {
if ud.bool(forKey: "trimAfterRecord") {
let fileURL = URL(fileURLWithPath: filePath)
AppDelegate.shared.createNewWindow(view: VideoTrimmerView(videoURL: fileURL), title: fileURL.lastPathComponent)
}
}

static func getCameras() -> [AVCaptureDevice] {
Expand Down
2 changes: 1 addition & 1 deletion QuickRecorder/ViewModel/ContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ struct ContentView: View {
if #available(macOS 13, *) {
Button(action: {
appDelegate.closeMainWindow()
appDelegate.prepRecord(type: "audio", screens: SCContext.getSCDisplayWithMouse(), windows: nil, applications: nil)
AppDelegate.shared.prepRecord(type: "audio", screens: SCContext.getSCDisplayWithMouse(), windows: nil, applications: nil)
}, label: {
SelectorView(title: "System Audio".local, symbol: "waveform")
.cornerRadius(8)
Expand Down
1 change: 1 addition & 0 deletions QuickRecorder/ViewModel/SettingsView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ struct SettingsView: View {
.padding([.leading, .trailing], 10).padding(.bottom, 5.5)
.disabled(audioFormat == .alac || audioFormat == .flac)
Picker("Format", selection: $audioFormat) {
Text("MP3").tag(AudioFormat.mp3)
Text("AAC").tag(AudioFormat.aac)
Text("ALAC (Lossless)").tag(AudioFormat.alac)
Text("FLAC (Lossless)").tag(AudioFormat.flac)
Expand Down
Binary file modified QuickRecorder/it.lproj/Localizable.strings
Binary file not shown.
Binary file modified img/donate.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 613bba7

Please sign in to comment.