- Add shell option for Windows in player's runCommand to fix
"spawn pnpm ENOENT" error (Windows needs shell:true to find .cmd)
- Add deps:download step to CI workflow so third-party tools
(ffmpeg, BBDown, etc.) are available during packaging
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1. events.ts: progress polling was using /api/downloads/active which
returns DB records without percent/speed fields. Changed to /api/tasks
which returns TaskInfo with real-time progress data.
2. download-item.tsx: lint fix had renamed callback params from `task`
to `taskItem` but missed updating all references in the function body,
causing ReferenceError. Reverted param names back to `task`.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace hardcoded "mediago" protocol scheme with dynamic `appName`
from environment, so community/dev builds use their own scheme
(e.g. "mediago-community://"). Applies to:
- constants: defaultScheme = appName
- main.window.ts: production URL uses defaultScheme
- browser.window.ts: same
- build.ts: CFBundleURLSchemes uses dynamic scheme
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Previously the frontend hashed passwords with MD5 + a hardcoded salt
before sending to the backend. This exposed the salt in client-side JS
and used an insecure hash algorithm.
Backend changes:
- Setup: accepts plain password, bcrypt hashes it, generates UUID apiKey
- Signin: accepts plain password, bcrypt verifies, returns stored apiKey
- Status: checks passwordHash instead of apiKey
- AppStore: new passwordHash field
- Middleware: add X-API-Key header support (was only reading Authorization)
- CORS: allow X-API-Key header
Frontend changes:
- Signin page: send plain password, receive apiKey from response
- Remove md5/crypto-js dependency and APIKEY_SALT_KEY constant
- api/download-task: auto-inject localPath/deleteSegments from store
(was lost during go-adapter migration, caused EOF errors)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Instead of manually calling setHttpApiKey() after signin, use an axios
request interceptor that reads apiKey from useAppStore.getState() on
every request. This ensures the header is always in sync with the
stored apiKey, regardless of when or how it was set.
Removed: setHttpApiKey() function (no longer needed).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
After login, the apiKey was saved to Zustand/localStorage but never
set on the http axios instance header, causing subsequent API calls
to return 401.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add proper TypeScript return types to every api/ function, using
existing shared types (Favorite, Video, Conversion, AppStore, etc.)
from @mediago/shared-common.
New types added:
- GoEnvPath (api/config.ts) for /api/env response
- AuthStatus (api/auth.ts) for /api/auth/status response
Updated SWR hooks to use typed data instead of Record<string, unknown>
casts: useFavorites, useConfig, useEnvPath, useAuthApi, useConversions.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Two issues:
1. http.ts 401 handler used window.location.hash (HashRouter syntax)
but the app uses BrowserRouter — changed to window.location.pathname
2. useAuth() blindly checked localStorage apiKey, which is always empty
on first visit. Now queries Go Core auth status first: only redirects
to /signin when auth is enabled and configured (or needs setup)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The UI sends X-API-Key for authentication, but the CORS AllowHeaders
config only listed Authorization. This caused preflight failures in
server mode where UI (localhost:8555) and Go Core (127.0.0.1:9900)
are on different origins.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Sidebar: toggle between embedded and external browser window mode,
show extract page in sidebar even when opened externally
- Home page: remove redundant material extraction button
- Converter: temporarily disable video format options, keep audio only
- Electron: remove node-machine-id dependency from package.json
- Tool bar: fix combineToHomePage argument structure
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
PageContainer was missing flex-col, causing pagination to render inline
with the list. Add flex-col + gap-3 to PageContainer and remove
duplicate padding/bg from the inner list container.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace hardcoded { current: 1, pageSize: 500 } with dynamic pagination
state. Default pageSize is 50 with an Ant Design Pagination component
at the bottom of the list.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
machineId is now generated by Go Core on first startup (uuid),
so the Electron IPC handler using node-machine-id is no longer needed.
Removes: getMachineId handler, node-machine-id import, nanoid import.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move machineId generation from Electron (node-machine-id) to Go Core.
On first startup, if machineId is empty in appStore config, Go Core
generates a UUID and persists it. This makes machineId available in
both Electron and Web modes via the config API.
UI now reads machineId from getConfig() instead of getMachineId() IPC.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
PlatformApi methods via Electron IPC return { code, data, msg } objects.
After migrating from useAPI() to usePlatform(), the auto-unwrap logic was
lost, causing consumers to receive raw objects instead of extracted data
(e.g. onSelectDownloadDir() returned [object Object] instead of a path).
Fix: wrap all PlatformApi function calls in the Proxy get trap to
auto-unwrap { code, data } responses, matching the old useAPI() behavior.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- core: move defer logger.Sync() after logger re-init to avoid nil panic
on early startup
- electron: replace console.log with ElectronLogger in DownloaderServer
and ElectronApp for consistent log output
- ui: add 1s delay before fetching coreUrl in Electron mode to wait for
Go core to finish starting
- ui: guard data?.list access in converter-page to prevent crash when
data is undefined
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Previously, init() was not awaited in index.ts, so any failure in the async
chain (e.g. getConfig() timing out) was silently swallowed and the window
was never created.
Fix:
1. Await mediago.init() in index.ts so errors surface properly
2. Move serviceInit() (window creation) before Go core startup so the UI
always appears, even if the backend fails to start
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1. Use Go build tag `dev` to conditionally compile swagger docs and routes.
Production binaries no longer include swaggo/files (swagger UI assets):
- mediago-core: 34 MB → 24 MB (-10 MB, -29%)
- mediago-player: 29 MB → 13 MB (-16 MB, -55%)
Dev builds (-tags dev) retain full swagger at /swagger and /docs.
2. Set executable permission (0o755) on built binaries (non-Windows).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The packaged app failed to launch because mediago-core was missing from
Resources/bin/. The asarUnpack approach relied on platform-specific npm
optional deps that pnpm workspace hoisting never installed in app/node_modules/.
Fix: copy locally-built binaries (core, player, deps) into app/build/bin
and app/build/deps during the pack step, then expose them via extraResources
so electron-builder places them at the expected Resources/bin/ and
Resources/deps/ paths at runtime.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Redesign the "Add File" flow as a modal dialog containing:
- File path field with "Browse" button (opens native file picker)
- Output format selector (Video: MP4/MKV/WebM, Audio: MP3/AAC/FLAC/WAV)
- Quality selector (High/Medium/Low)
- Two action buttons: "Add to List" (saves for later) and
"Convert Now" (saves and starts conversion immediately)
Also fix silent failure when adding files — getFileName() used
new URL() which throws on local file paths. Replaced with simple
path.split() extraction and added try-catch error handling.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move ffmpeg execution from Electron to Go Core so conversion works in
both Electron and web server modes.
Go Core backend:
- Add -ffmpeg-bin CLI flag to pass ffmpeg binary path
- Enhance Conversion DB model with status, outputPath, outputFormat,
quality, progress, and error fields
- Create converter executor (service/converter.go) that spawns ffmpeg,
builds args per format/quality, and parses stderr for progress
- Add StartConversion/StopConversion to service with SSE events for
real-time progress (conversion-start/progress/success/failed/stop)
- Add POST /api/conversions/:id/start and /:id/stop endpoints
Supported formats:
- Video: MP4 (H.264), MKV (H.264), WebM (VP9) with CRF quality
- Audio: MP3, AAC, FLAC, WAV with bitrate quality presets
- Quality presets: high/medium/low mapping to CRF and bitrate values
Frontend (converter-page):
- Add format selector (Video/Audio groups) and quality dropdown
- Show per-item status badge, progress bar during conversion
- Action buttons: Start/Stop/Open Folder/Delete based on status
- "Convert All" batch button for pending items
- SWR auto-refresh during active conversions
Integration:
- Pass -ffmpeg-bin from Electron and core:dev to Go Core
- Remove old broken Electron-only convertToAudio code
- Add startConversion/stopConversion to core-sdk and GoApi
- Add i18n keys for new UI elements (en/zh)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Vite 8's rollup types no longer accept the object shorthand for
manualChunks. Switch to the function form which is compatible with
all Vite versions.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
UI app:
- Add Vite manual chunks (vendor, antd, zustand) for better caching
- Wrap DownloadTaskItem with React.memo() to prevent list re-renders
- Wrap IconButton with React.memo() to prevent re-renders in lists
- Add missing Suspense fallback to SigninPage route
Player app:
- Add Vite manual chunks (videojs, vendor) to isolate video.js bundle
- Remove duplicate resize calculation in usePlayerSize hook
(ResizeObserver already handles container size changes)
- Disable SWR revalidateOnFocus/revalidateOnReconnect for video list
(list only changes when user adds/removes videos)
- Extract PlaylistItem into memoized component to prevent re-renders
when sibling items change, and eliminate duplicated rendering logic
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Previously the app polled GET /api/tasks every second unconditionally
from startup, even with no downloads running. Now polling is driven
by SSE events: started on download-start, stopped when no tasks have
Downloading status (checked after success/failed/stop events).
Applied to both Electron main process (downloader.server.ts) and
web/UI mode (go-event-bridge.ts).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Converted all Chinese-language comments across 47 source files to
English, covering Go backend (apps/core, apps/player), TypeScript
scripts, Electron main process, UI components, and shared packages.
Only comment text was modified — code, string literals, log messages,
and i18n translation values were left untouched.
Also fix pre-existing lint errors in scripts/release.ts and
scripts/utils.ts (node: protocol prefix, unused imports, bare catch).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Three root causes fixed:
1. ElectronStore migration deleted Go Core's config.json on every startup.
The old migration code unconditionally ran unlinkSync() on config.json
in the workspace directory — the same file Go Core uses for persistence.
Removed the migration entirely since it has already run for all users
(window-state.json now holds the bounds data).
2. core:dev mode saved config to the wrong directory (log dir instead of
data dir) because -config-dir was not passed. Added config_dir to
devConfig and the dev() command args, pointing to ~/.mediago/data to
avoid collision with the old v2.0 ~/.mediago/config.json format.
3. syncCLIToAppStore() overwrote user settings with CLI default values
on every Go Core startup in core:dev mode. Removed the function; CLI
args now only set initial cfg defaults, while appStore (user config)
takes precedence via the existing syncAppStoreToCfg().
Also aligns blockAds default (true) between Go Core and frontend Zustand store.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
getGoApi() was called eagerly inside useMemo during component mount,
before initGoAdapter() had run. Now GoApi methods resolve getGoApi()
at invocation time, so useAPI() can safely be called in App.tsx before
the adapter is initialized.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Major cleanup of the frontend adapter layer:
1. Type split: MediaGoApi (55 methods) → GoApi (22 data/CRUD methods via
Go Core HTTP) + PlatformApi (~30 Electron-native methods via IPC)
2. Remove Proxy-based routing: replace the fragile apiAdapter Proxy +
GO_METHODS set + ALL_API_METHODS array with direct object composition.
GoApi methods never fall through to Electron IPC.
3. Clean dead code: remove 18 preload methods that called IPC channels
with no handler (getFavorites, getAppStore, createDownloadTasks, etc.)
Remove unused event constants (SOCKET_TEST, SETUP_AUTH, SIGNIN, etc.)
4. New platform-stubs.ts: explicit no-op stubs for web/server mode
instead of a catch-all Proxy that returns empty responses.
5. Simplified useAPI: direct spread of wrapped GoApi + PlatformApi
instead of dynamic Object.keys().reduce() enumeration.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add adapterReady state to App.tsx: show Loading until initGoAdapter
completes, preventing API calls before goHandle is set (fixes
"No handler registered" errors for get-favorites, get-app-store, etc.)
- Add error handling and debug logging for player server startup
- Prepend core:build && player:build to dev:electron, dev:server,
pack:electron, and release:electron scripts
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1. Sync Go Core config to Zustand on app startup so settings persist
across restarts (Go Core is the single source of truth).
2. Go Core Create handler now respects startDownload param — downloads
start immediately when "Download Now" is clicked.
3. Player integration fixes:
- Electron: graceful skip when player binary is not built
- Server: start player service alongside Go Core, expose playerUrl
- Web adapter: derive playerUrl from current host instead of empty string
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Rename APP_NAME to mediago-community in .env
- Update APP_ID to mediago.caorushizi.cn
- Set mac identity: null to skip code signing
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Bump knip to v6.1.1, turbo to v2.9.1
- Remove oxlint-tsgolint devDependency
- Remove hidden={isWeb} from showTerminal setting item
- Format .vscode/settings.json and setting-page/index.tsx
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@electron/rebuild and prebuild-install are no longer needed as the
Electron app has no native runtime dependencies.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Fix PTYRunner.readPTYOutput to use raw chunk reads instead of a
broken bufio.Scanner split that called onStdLine with the entire
remaining buffer on every invocation, causing log lines to be
written multiple times
- Remove unused flushInterval field and NewPTYRunnerWithInterval
- Add convertEol: true to XTerm so bare \n in stored logs is treated
as \r\n, preventing misaligned output when replaying log files
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Update apps/server/src/binaryResolver.ts to use monorepo paths
instead of npm platform packages
- Remove @mediago/core and @mediago/deps from server package.json
- Add .gitkeep placeholder in apps/player/assets/ui/ for go:embed
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Phase 4-6 of monorepo merge:
- Create scripts/download-deps.ts for downloading third-party tools
from GitHub Releases (ffmpeg, N_m3u8DL-RE, BBDown, gopeed)
- Add scripts/deps-versions.json for version-locked tool definitions
- Update pnpm-workspace.yaml for new monorepo structure
- Change @mediago/core-sdk references from file:// to workspace:*
- Remove @mediago/core, @mediago/deps, @mediago/player npm deps
from electron package.json
- Rewrite binaryResolver.ts to use monorepo paths (dev) and
extraResources (production) instead of npm platform packages
- Simplify apps/core/scripts/config.ts (remove npm config, use .deps/)
- Add Go project scripts to root package.json
- Update turbo.json build outputs
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>