mirror of
https://github.com/ankitects/anki.git
synced 2025-09-18 14:02:21 -04:00
macOS launcher improvements
- do mpv initial run in parallel - improve messages, show dots regularly
This commit is contained in:
parent
eb6c977e08
commit
d2f818fad2
4 changed files with 81 additions and 44 deletions
|
@ -23,47 +23,45 @@ def first_run_setup() -> None:
|
|||
if not is_mac:
|
||||
return
|
||||
|
||||
def _dot():
|
||||
print(".", flush=True, end="")
|
||||
|
||||
_dot()
|
||||
import anki.collection
|
||||
|
||||
_dot()
|
||||
import PyQt6.sip
|
||||
|
||||
_dot()
|
||||
import PyQt6.QtCore
|
||||
|
||||
_dot()
|
||||
import PyQt6.QtGui
|
||||
|
||||
_dot()
|
||||
import PyQt6.QtNetwork
|
||||
|
||||
_dot()
|
||||
import PyQt6.QtQuick
|
||||
|
||||
_dot()
|
||||
import PyQt6.QtWebChannel
|
||||
|
||||
_dot()
|
||||
import PyQt6.QtWebEngineCore
|
||||
|
||||
_dot()
|
||||
import PyQt6.QtWebEngineWidgets
|
||||
|
||||
_dot()
|
||||
# Import anki_audio first and spawn commands
|
||||
import anki_audio
|
||||
import PyQt6.QtWidgets
|
||||
|
||||
audio_pkg_path = Path(anki_audio.__file__).parent
|
||||
|
||||
# Invoke mpv and lame
|
||||
cmd = [Path(""), "--version"]
|
||||
# Start mpv and lame commands concurrently
|
||||
processes = []
|
||||
for cmd_name in ["mpv", "lame"]:
|
||||
_dot()
|
||||
cmd[0] = audio_pkg_path / cmd_name
|
||||
subprocess.run([str(cmd[0]), str(cmd[1])], check=True, capture_output=True)
|
||||
cmd_path = audio_pkg_path / cmd_name
|
||||
proc = subprocess.Popen(
|
||||
[str(cmd_path), "--version"],
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL,
|
||||
)
|
||||
processes.append(proc)
|
||||
|
||||
print()
|
||||
# Continue with other imports while commands run
|
||||
import concurrent.futures
|
||||
|
||||
import bs4
|
||||
import flask
|
||||
import flask_cors
|
||||
import markdown
|
||||
import PyQt6.QtCore
|
||||
import PyQt6.QtGui
|
||||
import PyQt6.QtNetwork
|
||||
import PyQt6.QtQuick
|
||||
import PyQt6.QtWebChannel
|
||||
import PyQt6.QtWebEngineCore
|
||||
import PyQt6.QtWebEngineWidgets
|
||||
import PyQt6.QtWidgets
|
||||
import PyQt6.sip
|
||||
import requests
|
||||
import waitress
|
||||
|
||||
import anki.collection
|
||||
|
||||
from . import _macos_helper
|
||||
|
||||
# Wait for both commands to complete
|
||||
for proc in processes:
|
||||
proc.wait()
|
||||
|
|
|
@ -47,8 +47,8 @@ done
|
|||
codesign -vvv "$APP_LAUNCHER"
|
||||
spctl -a "$APP_LAUNCHER"
|
||||
|
||||
# Notarize
|
||||
./notarize.sh "$OUTPUT_DIR"
|
||||
|
||||
# Bundle
|
||||
./dmg/build.sh "$OUTPUT_DIR"
|
||||
# Notarize and bundle (skip if NODMG is set)
|
||||
if [ -z "$NODMG" ]; then
|
||||
./notarize.sh "$OUTPUT_DIR"
|
||||
./dmg/build.sh "$OUTPUT_DIR"
|
||||
fi
|
|
@ -172,6 +172,8 @@ fn run() -> Result<()> {
|
|||
command.env("UV_PRERELEASE", "allow");
|
||||
}
|
||||
|
||||
println!("\x1B[1mUpdating Anki...\x1B[0m\n");
|
||||
|
||||
match command.ensure_success() {
|
||||
Ok(_) => {
|
||||
// Sync succeeded, break out of loop
|
||||
|
|
|
@ -3,6 +3,11 @@
|
|||
|
||||
use std::os::unix::process::CommandExt;
|
||||
use std::process::Command;
|
||||
use std::sync::atomic::AtomicBool;
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::sync::Arc;
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
use anki_process::CommandExt as AnkiCommandExt;
|
||||
use anyhow::Context;
|
||||
|
@ -25,6 +30,9 @@ pub fn launch_anki_detached(anki_bin: &std::path::Path, _config: &crate::Config)
|
|||
.process_group(0)
|
||||
.ensure_spawn()?;
|
||||
std::mem::forget(child);
|
||||
|
||||
println!("Anki will start shortly.");
|
||||
println!("\x1B[1mYou can close this window.\x1B[0m\n");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -34,6 +42,10 @@ pub fn ensure_terminal_shown() -> Result<()> {
|
|||
// If launched from GUI, relaunch in Terminal.app
|
||||
relaunch_in_terminal()?;
|
||||
}
|
||||
|
||||
// Set terminal title to "Anki Launcher"
|
||||
print!("\x1b]0;Anki Launcher\x07");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -47,12 +59,37 @@ fn relaunch_in_terminal() -> Result<()> {
|
|||
}
|
||||
|
||||
pub fn handle_first_launch(anki_bin: &std::path::Path) -> Result<()> {
|
||||
use std::io::Write;
|
||||
use std::io::{
|
||||
self,
|
||||
};
|
||||
|
||||
// Pre-validate by running --version to trigger any Gatekeeper checks
|
||||
println!("\n\x1B[1mThis may take a few minutes. Please wait...\x1B[0m");
|
||||
print!("\n\x1B[1mThis may take a few minutes. Please wait\x1B[0m");
|
||||
io::stdout().flush().unwrap();
|
||||
|
||||
// Start progress indicator
|
||||
let running = Arc::new(AtomicBool::new(true));
|
||||
let running_clone = running.clone();
|
||||
let progress_thread = thread::spawn(move || {
|
||||
while running_clone.load(Ordering::Relaxed) {
|
||||
print!(".");
|
||||
io::stdout().flush().unwrap();
|
||||
thread::sleep(Duration::from_secs(1));
|
||||
}
|
||||
});
|
||||
|
||||
let _ = Command::new(anki_bin)
|
||||
.env("ANKI_FIRST_RUN", "1")
|
||||
.arg("--version")
|
||||
.stdout(std::process::Stdio::null())
|
||||
.stderr(std::process::Stdio::null())
|
||||
.ensure_success();
|
||||
|
||||
// Stop progress indicator
|
||||
running.store(false, Ordering::Relaxed);
|
||||
progress_thread.join().unwrap();
|
||||
println!(); // New line after dots
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue