Compare commits

..
3 Commits
7 changed files with 78 additions and 32 deletions
+17 -11
View File
@@ -20,6 +20,9 @@ jobs:
runs-on: macos-15 runs-on: macos-15
env: env:
VERSION: ${{ inputs.version }} VERSION: ${{ inputs.version }}
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
APPLE_APP_PASSWORD: ${{ secrets.APPLE_APP_PASSWORD }}
SPARKLE_PRIVATE_KEY: ${{ secrets.SPARKLE_PRIVATE_KEY }} SPARKLE_PRIVATE_KEY: ${{ secrets.SPARKLE_PRIVATE_KEY }}
steps: steps:
- uses: actions/checkout@v7 - uses: actions/checkout@v7
@@ -31,7 +34,7 @@ jobs:
APPLE_CERTIFICATE_P12: ${{ secrets.APPLE_CERTIFICATE_P12 }} APPLE_CERTIFICATE_P12: ${{ secrets.APPLE_CERTIFICATE_P12 }}
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
run: | run: |
for variable in APPLE_CERTIFICATE_P12 APPLE_CERTIFICATE_PASSWORD SPARKLE_PRIVATE_KEY; do for variable in APPLE_CERTIFICATE_P12 APPLE_CERTIFICATE_PASSWORD APPLE_ID APPLE_TEAM_ID APPLE_APP_PASSWORD SPARKLE_PRIVATE_KEY; do
if [[ -z "${!variable:-}" ]]; then if [[ -z "${!variable:-}" ]]; then
echo "Missing GitHub Actions secret: $variable" >&2 echo "Missing GitHub Actions secret: $variable" >&2
exit 1 exit 1
@@ -53,7 +56,7 @@ jobs:
fi fi
echo "SIGNING_IDENTITY=$signing_identity" >> "$GITHUB_ENV" echo "SIGNING_IDENTITY=$signing_identity" >> "$GITHUB_ENV"
- name: Build and sign release - name: Build, sign, and notarize release
timeout-minutes: 30 timeout-minutes: 30
run: scripts/package_release.sh run: scripts/package_release.sh
@@ -70,13 +73,16 @@ jobs:
GH_TOKEN: ${{ github.token }} GH_TOKEN: ${{ github.token }}
run: | run: |
tag="v$VERSION" tag="v$VERSION"
if git rev-parse "$tag" >/dev/null 2>&1; then if gh release view "$tag" >/dev/null 2>&1; then
echo "Tag already exists: $tag" >&2 gh release upload "$tag" \
exit 1 "$RUNNER_TEMP/meetingnotes-release/release/Meetingnotes-$VERSION.zip" \
"$RUNNER_TEMP/meetingnotes-release/release/appcast.xml" \
--clobber
else
gh release create "$tag" \
"$RUNNER_TEMP/meetingnotes-release/release/Meetingnotes-$VERSION.zip" \
"$RUNNER_TEMP/meetingnotes-release/release/appcast.xml" \
--target "$GITHUB_SHA" \
--title "Meetingnotes $VERSION" \
--generate-notes
fi fi
gh release create "$tag" \
"$RUNNER_TEMP/meetingnotes-release/release/Meetingnotes-$VERSION.zip" \
"$RUNNER_TEMP/meetingnotes-release/release/appcast.xml" \
--target "$GITHUB_SHA" \
--title "Meetingnotes $VERSION" \
--generate-notes
+4 -4
View File
@@ -276,7 +276,7 @@
CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES; COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 31; CURRENT_PROJECT_VERSION = 33;
DEVELOPMENT_ASSET_PATHS = "\"meetingnotes/Preview Content\""; DEVELOPMENT_ASSET_PATHS = "\"meetingnotes/Preview Content\"";
DEVELOPMENT_TEAM = G9LVHZAJNX; DEVELOPMENT_TEAM = G9LVHZAJNX;
ENABLE_HARDENED_RUNTIME = YES; ENABLE_HARDENED_RUNTIME = YES;
@@ -290,7 +290,7 @@
"@executable_path/../Frameworks", "@executable_path/../Frameworks",
); );
MACOSX_DEPLOYMENT_TARGET = 15.0; MACOSX_DEPLOYMENT_TARGET = 15.0;
MARKETING_VERSION = 1.1.19; MARKETING_VERSION = 1.1.21;
ONLY_ACTIVE_ARCH = NO; ONLY_ACTIVE_ARCH = NO;
OTHER_SWIFT_FLAGS = "$(inherited) -D ENABLE_TCC_SPI"; OTHER_SWIFT_FLAGS = "$(inherited) -D ENABLE_TCC_SPI";
PRODUCT_BUNDLE_IDENTIFIER = net.jamesbone.meetingnotes; PRODUCT_BUNDLE_IDENTIFIER = net.jamesbone.meetingnotes;
@@ -312,7 +312,7 @@
CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES; COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 31; CURRENT_PROJECT_VERSION = 33;
DEVELOPMENT_ASSET_PATHS = "\"meetingnotes/Preview Content\""; DEVELOPMENT_ASSET_PATHS = "\"meetingnotes/Preview Content\"";
DEVELOPMENT_TEAM = G9LVHZAJNX; DEVELOPMENT_TEAM = G9LVHZAJNX;
ENABLE_HARDENED_RUNTIME = YES; ENABLE_HARDENED_RUNTIME = YES;
@@ -326,7 +326,7 @@
"@executable_path/../Frameworks", "@executable_path/../Frameworks",
); );
MACOSX_DEPLOYMENT_TARGET = 15.0; MACOSX_DEPLOYMENT_TARGET = 15.0;
MARKETING_VERSION = 1.1.19; MARKETING_VERSION = 1.1.21;
ONLY_ACTIVE_ARCH = YES; ONLY_ACTIVE_ARCH = YES;
OTHER_SWIFT_FLAGS = "$(inherited) -D ENABLE_TCC_SPI"; OTHER_SWIFT_FLAGS = "$(inherited) -D ENABLE_TCC_SPI";
PRODUCT_BUNDLE_IDENTIFIER = net.jamesbone.meetingnotes; PRODUCT_BUNDLE_IDENTIFIER = net.jamesbone.meetingnotes;
+7 -4
View File
@@ -209,15 +209,18 @@ final class AudioManager: NSObject, ObservableObject {
private func prepareAudioFiles() throws { private func prepareAudioFiles() throws {
let settings: [String: Any] = [ let settings: [String: Any] = [
AVFormatIDKey: kAudioFormatMPEG4AAC, AVFormatIDKey: kAudioFormatLinearPCM,
AVSampleRateKey: 16_000, AVSampleRateKey: 16_000,
AVNumberOfChannelsKey: 1, AVNumberOfChannelsKey: 1,
AVEncoderBitRateKey: 48_000 AVLinearPCMBitDepthKey: 16,
AVLinearPCMIsFloatKey: false,
AVLinearPCMIsBigEndianKey: false,
AVLinearPCMIsNonInterleaved: false
] ]
let base = FileManager.default.temporaryDirectory let base = FileManager.default.temporaryDirectory
let id = sessionID.uuidString let id = sessionID.uuidString
let micURL = base.appendingPathComponent("meetingnotes-\(id)-mic.m4a") let micURL = base.appendingPathComponent("meetingnotes-\(id)-mic.wav")
let systemURL = base.appendingPathComponent("meetingnotes-\(id)-system.m4a") let systemURL = base.appendingPathComponent("meetingnotes-\(id)-system.wav")
let newMicAudioFile = try AVAudioFile( let newMicAudioFile = try AVAudioFile(
forWriting: micURL, forWriting: micURL,
settings: settings, settings: settings,
@@ -79,13 +79,7 @@ class UserDefaultsManager {
} }
var transcriptionModel: String { var transcriptionModel: String {
get { get { userDefaults.string(forKey: Keys.transcriptionModel) ?? "local-parakeet/parakeet-tdt-0.6b-v3" }
let stored = userDefaults.string(forKey: Keys.transcriptionModel)
if stored == "local-whisper/whisper-large-v3-turbo" {
return "local-parakeet/parakeet-tdt-0.6b-v3"
}
return stored ?? "local-parakeet/parakeet-tdt-0.6b-v3"
}
set { userDefaults.set(newValue, forKey: Keys.transcriptionModel) } set { userDefaults.set(newValue, forKey: Keys.transcriptionModel) }
} }
@@ -275,6 +275,13 @@ final class CoderAPIClient {
let framesPerChunk = preserveSpeakerIdentity let framesPerChunk = preserveSpeakerIdentity
? max(1, input.length) ? max(1, input.length)
: AVAudioFramePosition(format.sampleRate * transcriptionChunkDuration) : AVAudioFramePosition(format.sampleRate * transcriptionChunkDuration)
if fileURL.pathExtension.caseInsensitiveCompare("wav") == .orderedSame,
input.fileFormat.streamDescription.pointee.mFormatID == kAudioFormatLinearPCM,
input.length <= framesPerChunk {
return [AudioChunk(url: fileURL, offset: 0, isTemporary: false)]
}
var chunks: [AudioChunk] = [] var chunks: [AudioChunk] = []
var frameOffset: AVAudioFramePosition = 0 var frameOffset: AVAudioFramePosition = 0
+10 -4
View File
@@ -59,10 +59,16 @@ struct SettingsView: View {
} }
} }
if viewModel.coderModels.first(where: { $0.id == viewModel.settings.transcriptionModel })?.supportsSpeakerDiarization == true { if let selectedModel = viewModel.coderModels.first(where: { $0.id == viewModel.settings.transcriptionModel }) {
Label("Remote participants are labeled Speaker 14; your microphone is labeled Me.", systemImage: "person.2.wave.2") if selectedModel.supportsSpeakerDiarization {
.font(.caption) Label("Remote participants are labeled Speaker 14; your microphone is labeled Me.", systemImage: "person.2.wave.2")
.foregroundColor(.secondary) .font(.caption)
.foregroundColor(.secondary)
} else {
Label("Remote participants are labeled Them; your microphone is labeled Me.", systemImage: "person.2")
.font(.caption)
.foregroundColor(.secondary)
}
} }
} }
+32 -2
View File
@@ -14,6 +14,9 @@ APP_PATH="$DERIVED_DATA/Build/Products/Release/$APP_NAME.app"
required_variables=( required_variables=(
VERSION VERSION
SIGNING_IDENTITY SIGNING_IDENTITY
APPLE_ID
APPLE_TEAM_ID
APPLE_APP_PASSWORD
SPARKLE_PRIVATE_KEY SPARKLE_PRIVATE_KEY
GITHUB_REPOSITORY GITHUB_REPOSITORY
) )
@@ -80,6 +83,33 @@ ARCHIVE_NAME="$APP_NAME-$VERSION.zip"
ARCHIVE_PATH="$RELEASE_DIR/$ARCHIVE_NAME" ARCHIVE_PATH="$RELEASE_DIR/$ARCHIVE_NAME"
ditto -c -k --sequesterRsrc --keepParent "$APP_PATH" "$ARCHIVE_PATH" ditto -c -k --sequesterRsrc --keepParent "$APP_PATH" "$ARCHIVE_PATH"
NOTARY_RESULT="$BUILD_ROOT/notary-result.json"
xcrun notarytool submit "$ARCHIVE_PATH" \
--apple-id "$APPLE_ID" \
--team-id "$APPLE_TEAM_ID" \
--password "$APPLE_APP_PASSWORD" \
--wait \
--timeout 20m \
--output-format json > "$NOTARY_RESULT"
NOTARY_STATUS=$(plutil -extract status raw -o - "$NOTARY_RESULT")
if [[ "$NOTARY_STATUS" != "Accepted" ]]; then
submission_id=$(plutil -extract id raw -o - "$NOTARY_RESULT")
xcrun notarytool log "$submission_id" \
--apple-id "$APPLE_ID" \
--team-id "$APPLE_TEAM_ID" \
--password "$APPLE_APP_PASSWORD" || true
echo "Apple notarization failed with status: $NOTARY_STATUS" >&2
exit 1
fi
xcrun stapler staple "$APP_PATH"
xcrun stapler validate "$APP_PATH"
spctl --assess --type execute --verbose=2 "$APP_PATH"
rm -f "$ARCHIVE_PATH"
ditto -c -k --sequesterRsrc --keepParent "$APP_PATH" "$ARCHIVE_PATH"
GENERATE_APPCAST=$(find "$DERIVED_DATA/SourcePackages/artifacts" -type f -name generate_appcast -print -quit) GENERATE_APPCAST=$(find "$DERIVED_DATA/SourcePackages/artifacts" -type f -name generate_appcast -print -quit)
if [[ -z "$GENERATE_APPCAST" ]]; then if [[ -z "$GENERATE_APPCAST" ]]; then
echo "Sparkle generate_appcast tool was not found" >&2 echo "Sparkle generate_appcast tool was not found" >&2
@@ -97,8 +127,8 @@ grep -q "$DOWNLOAD_URL$ARCHIVE_NAME" "$RELEASE_DIR/appcast.xml"
grep -q 'sparkle:edSignature=' "$RELEASE_DIR/appcast.xml" grep -q 'sparkle:edSignature=' "$RELEASE_DIR/appcast.xml"
if [[ -n "${GITHUB_STEP_SUMMARY:-}" ]]; then if [[ -n "${GITHUB_STEP_SUMMARY:-}" ]]; then
printf 'Built and Developer ID-signed Meetingnotes %s. The GitHub release is ready to publish.\n' \ printf 'Built, Developer ID-signed, notarized, and stapled Meetingnotes %s. The GitHub release is ready to publish.\n' \
"$VERSION" >> "$GITHUB_STEP_SUMMARY" "$VERSION" >> "$GITHUB_STEP_SUMMARY"
fi fi
echo "Signed release artifacts are ready in $RELEASE_DIR" echo "Signed and notarized release artifacts are ready in $RELEASE_DIR"