文件历史

提交图

22 次代码提交

作者 SHA1 备注 提交日期
caorushizi d654368290 feat(core): add cobra cli entrypoint 2026-05-17 03:37:28 +08:00
caorushizi c34812841e fix(core): sanitize filenames at task creation to prevent path-separator injection
Twitter-style page titles like "(2) 主页 / X" land a literal "/" in
the download filename. Gopeed used to strip such characters silently;
aria2 is strict and passes them through to the OS, which then reads
"/" as a path separator — the save ends up at
`.../(2) 主页 /X-....mp4` pointing at a non-existent sub-directory
and fails with `ERROR_PATH_NOT_FOUND (errNum=3)`.

Sanitize once, at the task-creation boundary, so the DB row, the
downloader command-line `-o` arg, and the post-download
`CheckFileExists(rec.Name, ...)` probe all agree on the same
filesystem-safe value.

- New exported `core.SanitizeFilename` replaces reserved path /
  wildcard characters (`\ / : * ? " < > |`) and ASCII control chars
  with `_`, and right-trims dots / spaces (Windows strips those
  silently, producing a filename that doesn't match the DB row).
  Falls back to "download" if every character was illegal.
- `service/download_task.go` `AddDownloadTask` and `AddDownloadTasks`
  run titles through `SanitizeFilename` before the
  `FindByName` de-duplication check, so both the dedup lookup and
  the persisted row see the cleaned value.
- `core/downloader.go` `buildArgs` still calls `SanitizeFilename`
  defensively on `p.Name` — cheap, and guards any future path that
  bypasses the service layer.

Applies to every downloader (aria2, yt-dlp, BBDown, N_m3u8DL-RE,
mediago) since the fix is in the shared `name` arg-building branch
used by all Schema entries. Pre-existing broken tasks in the DB will
still fail "file not found" on the UI and need to be deleted +
re-created.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 17:10:54 +08:00
caorushizi a9e3ed6a22 feat(core): switch direct downloader from gopeed to aria2
Gopeed's last release is aging and its SChannel-linked Windows build
chokes on modern CDN TLS handshakes (we hit SEC_I_MESSAGE_FRAGMENT on
twimg.com). Replace it with aria2 — same short flags (-x/-s/-k carry
over verbatim), stricter arg handling, and well-trodden cross-platform
builds.

Binaries are vendored in-tree at extra/aria2/<os>/<arch>/ rather than
pulled from a single GitHub release, because aria2 static builds for
Linux / macOS / Windows come from different upstream repos. To keep
the deps pipeline unified:

- `scripts/download-deps.ts` grows a "source": "local" branch that
  copies from `extra/<tool>/<os>/<arch>/` into `.deps/<os>-<arch>/`
  instead of fetching from GitHub. Resulting layout matches the rest
  of the tools, so binaryResolver.ts needs no changes.
- `scripts/deps-versions.json`: `gopeed` entry removed, `aria2`
  entry added with source:"local" + path:"extra/aria2".
- `apps/core/internal/core/types.go`: BinaryNames[TypeDirect]
  `"gopeed"` → `"aria2c"`.
- `apps/core/internal/core/schema/loader.go`: direct schema's Args
  map to aria2's flags (-d / -o, plus --console-log-level=notice /
  --summary-interval=1 / --allow-overwrite=true /
  --auto-file-renaming=false for parseable output and predictable
  rerun behaviour). ConsoleReg regexes updated to aria2's summary
  line format (e.g. "DL:512KiB" for speed, "(83%)" for percent).
  `--check-certificate=false` tacked on as a workaround for the
  SChannel handshake issue on the bundled 1.19.0 Windows build —
  proper fix is upgrading the vendored binary to a build that links
  against OpenSSL (e.g. 1.37.0), comment calls that out.
- `apps/core/.env`, `Dockerfile`, `apps/electron/scripts/build.ts`,
  `apps/core/README.md`: gopeed → aria2c / aria2 references.

No DB migration: existing `type: "direct"` rows keep working, the
underlying binary just swaps.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 17:09:35 +08:00
caorushizi 8783d949ba feat(favorite): optional title with auto-fetch and URL-first form
- Make favorite title optional in both the DTO (drop binding:"required")
  and the add-favorite modal (no validator). Server falls back to the
  URL when the title is empty so the list entry always has a label.
- Auto-fill the title via the existing GET /api/url/title scraper when
  the user leaves the URL field, unless they already typed their own
  title. Failures are swallowed (server fallback still applies).
- Reorder the modal so URL is on top and Title below, matching the
  actual data-flow: users paste a URL first and the title follows.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 05:28:35 +08:00
caorushizi bee6bd1cbd fix(ui,core): drive download badge via SSE and polish favorite error UX
- Go Core now broadcasts a "download-create" SSE event after
  POST /api/downloads succeeds, carrying the new task ids and count.
  The renderer's events.ts listens for it and calls useDownloadStore's
  increase() imperatively, so the sidebar badge updates regardless of
  which WebContents issued the request — the source-extract overlay
  dialog has its own Zustand instance and can no longer silently swallow
  the increment.
- Remove the now-redundant local increase() calls in download-form and
  browser-view-panel so the counter is incremented exactly once per task
  from a single source of truth.
- Favorite.Create returns 409 Conflict with a translated
  MsgURLAlreadyExists message when the URL already exists, instead of
  500 with the raw "url_already_exists" string.
- http.ts response interceptor now surfaces the server's translated
  message on 4xx/5xx instead of Axios's generic
  "Request failed with status code XXX".
- Simplify getFavIcon: drop the 1s <img> probe that dropped most URLs
  and return the canonical /favicon.ico; <Avatar> already falls back to
  a link icon when the image fails to load.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 05:28:22 +08:00
caorushizi c7dd925a34 feat(core): add yt-dlp plugin and consolidate binary paths into --deps-dir
- Add youtube download type with yt-dlp schema (CLI args, progress regex)
- Replace 6 individual --xxx-bin flags with single --deps-dir flag
- Add BinaryNames map in Go core to auto-resolve binary paths from deps dir
- Simplify Electron/Server binary resolvers to return depsDir only
- Add yt-dlp to deps-versions.json (v2026.03.17)
- Add YouTube option to UI download form with URL auto-detection
- Fix download-terminal.tsx writing [object Object] instead of log content
- Improve error messages when binary not found (include path and type)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 00:19:14 +08:00
caorushizi 90d7fe578f feat(core): upgrade mediago-core to v0.2.1 and adapt log parsing
- Bump mediago-core from v0.1.0 to v0.2.1 in deps-versions.json
- Update ConsoleReg to match new structured log format:
  speed regex for B/s units, start/isLive/error patterns
- Remove --no-log flag so structured logs are visible for parsing

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 00:19:14 +08:00
caorushizi 25d149e9ef feat(core): integrate mediago-core as new download type
Add mediago-core (caorushizi/mediago-core) as a fourth download type
alongside m3u8, bilibili, and direct. This enables HLS/DASH streaming
downloads using the custom Go-based downloader.

Changes span the full integration path: dependency download config,
Go Core backend (type, schema, CLI flag, binary map), binary resolution
for Electron/Server, shared TypeScript types, i18n labels, UI dropdown,
dev scripts, and Dockerfile.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 00:19:14 +08:00
caorushizi c2db365729 fix(core): add User-Agent and Referer for Bilibili title fetching
Bilibili returns an error page ("出错了") when requests lack a proper
User-Agent. Add browser User-Agent and Referer headers to both
GetPageTitle (service/helpers.go) and fetchTitle (handler/util.go).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 16:12:42 +08:00
caorushizi 0a36e39156 fix(core): whitelist static assets and SPA routes in auth middleware
Docker mode with --enable-auth was returning 401 for the homepage
and all static assets. Add /assets/, /favicon.ico, / and SPA
frontend routes (non-API paths without dots) to the auth whitelist.

Verified locally: homepage 200, /signin 200, /api/config 401 without key.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 12:34:16 +08:00
caorushizi 218603ff9f refactor(video): use ID-based video streaming and fix playback issues
- Change video stream route from /videos/*filepath to /videos/:id
  (lookup file path from database by task ID instead of filename)
- Add mimeType field to Video API response so video.js knows the format
- Fix getVideoURL double-slash bug (/videos/... → //videos/...)
- Handle directory downloads: scan inside for first video file when
  CheckFileExists returns a directory (e.g. multi-part bilibili downloads)
- Remove unused videoRoot field and ServeVideo function
- Update player-ui PlaylistItem to pass full VideoItem object

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 01:22:15 +08:00
caorushizi de3b805ea0 feat(core,player-ui): refactor video API to use database and fix playback
Refactor video player API from filesystem scanning to database-backed:
- Video list queries downloads with status="success" + file existence check
- Add GET /api/v1/videos/:id endpoint for playing specific video by task ID
- Add playerUrl to /api/env response (computed from request host)
- Whitelist player/video paths in auth middleware
- Fix video URL generation to preserve folder structure (relative path)
- Fix player-ui Vite base path and video URL resolution under /player/
- Add openUrl implementation to web platform stubs
- Player-UI supports ?id= query param to auto-play specific video
- Play button now passes task.id instead of filename

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 22:45:27 +08:00
caorushizi 452bbc3b7d refactor: merge player Go backend into core
Merge the standalone mediago-player binary into mediago-core. The core
now serves the player UI at /player/ via go:embed, and provides video
listing/streaming endpoints. Video root reuses the existing download
directory (local-dir) so no separate flag is needed.

Changes:
- Add internal/video package to core (handler, service, types)
- Embed player-ui assets via //go:embed in assets/embed.go
- Add SPA handler for /player/ path
- Register /api/v1/videos and /videos/* routes in core router
- core:build now builds player-ui before Go compilation
- Remove apps/player/ entirely (Go app, scripts, configs)
- Remove VideoServer from Electron, derive playerUrl from coreUrl
- Remove player binary management from server app
- Update CI workflow to remove player go.sum cache path

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 21:05:42 +08:00
caorushizi 7eb654b6a5 feat(core,ui): move password hashing to backend with bcrypt
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>
2026-04-02 16:27:09 +08:00
caorushizi f6e59e864a fix(core): allow X-API-Key header in CORS config
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>
2026-04-02 14:47:04 +08:00
caorushizi 43c11928fa feat(core,player): exclude swagger from prod builds; add chmod to binaries
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>
2026-04-01 13:22:16 +08:00
caorushizi 38cb884b77 style: apply oxfmt formatting across codebase
Also fix pre-existing lint errors exposed by staging:
- Merge duplicate 'eventsource' imports in eventEmitter.ts
- Remove unused catch parameter in eventEmitter.ts
- Merge duplicate 'react' imports in app-side-bar.tsx

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 12:12:49 +08:00
caorushizi 21e232f042 feat: implement format conversion with ffmpeg in Go Core
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>
2026-04-01 11:38:14 +08:00
caorushizi 350e02c0f0 chore: translate all Chinese comments to English
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>
2026-04-01 03:56:57 +08:00
caorushizi 38fa71b44b fix: config persistence, download-now auto-start, and player integration
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>
2026-04-01 00:27:30 +08:00
caorushizi 2425598c6a fix: fix download log display corruption in terminal
- 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>
2026-03-31 22:43:36 +08:00
caorushizi a9129f4a3c Merge commit '84ed412899931d87a526bb0e8d391a9b9f60ce18' as 'apps/core' 2026-03-31 21:08:13 +08:00