๐ต A local-first desktop app for searching and playing Niconico VOCALOID videos with a modern Spotify-like interface.
Windows native โข Tauri + Rust backend โข Vue 3 frontend โข SQLite FTS5 search
Inspired by ใใณใใณ่ถ ๆค็ดข โ a popular Niconico video search service.
This project is a desktop port of the web-based VOCALOID Search, rebuilt as a local-first application using Tauri.
Tip
Best fit for: people who want a native Windows app with local search, integrated PiP playback, Watch Later, and a Rust-authoritative playback model instead of a self-hosted web stack.
- โก Quick Start
- โจ Why this desktop edition exists
- ๐ธ Screenshots
- ๐ Core Features
- ๐งญ Architecture Highlights
- ๐งฉ Web vs Desktop Edition
- ๐ ๏ธ Technical Specifications
- ๐ป System Requirements
- ๐๏ธ Data Storage
- ๐ User Guide
- โ FAQ / Troubleshooting
- ๐๏ธ Build from Source
โ ๏ธ Known Limitations- ๐บ๏ธ Future Plans
- ๐ License
If you just want to try the app locally:
- Clone the repository
- Go into
vocaloid-search-desktop/ - Install dependencies with
npm install - Run
npm run tauri devfor general UI work - Use
npm run tauri build -- --debugwhen you need to validate embedded-player behavior
Important
Niconico rejects localhost-origin embedded playback, so tauri dev is not enough for final playback validation. Use a debug or release Tauri build when checking real embedded-player behavior.
Note
The desktop app now includes Watch Later, authoritative Rust-managed playback state, PiP/main shared player behavior, and preflight sync storage checks out of the box.
VOCALOID Search Desktop is designed for people who want a native local app instead of a self-hosted web service:
- ๐ง Spotify-like playback workflow with an embedded Niconico player
- ๐ฅ๏ธ Native PiP window that stays on top and shares the same playback state as the main window
- ๐ Fast local search powered by SQLite FTS5
- ๐ Watch history + Watch Later built into the desktop app
- ๐ง Custom formula sorting and filtering for ranking videos your way
- ๐พ Local-first storage so browsing and search stay fast after sync
- ๐จ Modern Interface: Spotify-inspired UI with playlist-style layout
- ๐ Light / Dark Mode: Theme switching for different viewing environments
- ๐ Multi-language Support: English, Japanese, and Traditional Chinese
- ๐ช PiP Window: Native always-on-top picture-in-picture playback window
- ๐ Watch History: Track what you have watched and jump back into playback
- โฐ Watch Later: Save videos for future playback in a dedicated list
- ๐ Exclude Watched: Filter watched videos out of search results
- ๐พ Window State Persistence: Restore window size, position, and maximize state between sessions
- ๐๏ธ Local Database: Scrape and store video metadata locally for fast search
- ๐งฎ Custom Formula Sorting & Filtering: Weight views, likes, mylists, and comments using your own formula
- โญ๏ธ Auto-Skip: Automatically skip video endings when desired
โถ๏ธ Embedded Player: Continuous playback with the official Niconico embed player- ๐ท๏ธ Keyword + Tag Search: Full-text keyword search with tag filtering
- โพ๏ธ Infinite Scroll: Dynamic loading instead of fixed pagination
- ๐งช Shared Player Logic: Main window and PiP consume the same playback event flow
This project has evolved beyond a simple prototype. Several architectural decisions are now central to how it works:
All authoritative playback, browsing, and list state live in the Rust backend. The Vue frontend acts as a display and interaction layer rather than maintaining a competing copy of state.
Each list (Search, History, Watch Later) has its own context, identity, and version. This helps prevent stale pagination or overlapping search/load-more requests from corrupting visible results.
The app uses a unified player architecture so both windows respond to the same backend playback events and metadata updates. Fixes to playback behavior generally apply to both windows.
When Search playback is active with watched exclusion enabled, the app freezes the watched boundary for that session. This keeps pagination membership stable instead of letting videos disappear mid-session.
The player renders first, then richer metadata lands through authoritative backend updates. This avoids view-specific fetch divergence and keeps Search, History, Watch Later, main window, and PiP aligned.
| Feature | Web Edition | Desktop Edition |
|---|---|---|
| Deployment | Self-hosted server (NixOS/Linux) | Local application (Windows) |
| Runtime | 24/7 server operation | On-demand launch |
| Scraper | Automated via systemd timer | Manual execution with preflight confirmation |
| Multi-user | Yes, user registration supported | Single user, local data |
| Mobile Support | PWA/TWA for Android | Not applicable |
| PiP Mode | Compact window resize | Native always-on-top window |
| Data Storage | Server-side database | Local filesystem |
| Offline Search | Requires server connection | Fully local after sync |
| Platform | NixOS/Linux only | Windows (Linux planned) |
Choose Web Edition if:
- You want 24/7 automated scraping
- You need multi-user support
- You want mobile access via PWA
- You run NixOS/Linux servers
Choose Desktop Edition if:
- You prefer a native desktop experience
- You want PiP tightly integrated with the OS
- You do not want to manage a server
- You want search and playlist browsing to stay local and fast
| Layer | Technology |
|---|---|
| Frontend | TypeScript, Vue 3, Vite, Tailwind CSS |
| Backend | Rust (Tauri 2.x) |
| Database | SQLite with FTS5 full-text search |
| Data Sources | Niconico Snapshot API v2 for sync/search cache, watch/{id}?responseType=json for single-video playback metadata enrichment |
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Vue 3 Frontend โ
โ (Search UI, Player, Settings, PiP) โ
โโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโ
โ Tauri IPC
โโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโ
โ Rust Backend โ
โ (State, SQLite, HTTP Client, File I/O) โ
โโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโ
โ Local SQLite Database (FTS5) โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- ๐ Custom Protocol: Uses
tauri://localhostinstead of HTTP localhost because Niconico's embed player rejects localhost origins - ๐ FTS5 Full-text Search: Fast keyword and tag search with SQLite FTS5
- ๐งฎ Formula-based Scoring: Flexible weighting for views, likes, mylists, and comments
- ๐ Versioned List Contexts: Search / History / Watch Later each maintain stable context identity
- ๐ช Unified Player Core: Shared playback state and event handling across main window and PiP
- ๐งท Staged Metadata Rendering: Player-first UX with authoritative metadata refresh after backend enrichment
- โ Frontend logic is covered by focused Vitest suites
- โ Rust state and playback flows include backend tests
- โ Recent releases prioritized race-condition fixes, state authority, and dual-window consistency rather than cosmetic-only changes
- OS: Windows 10/11 (x64)
- RAM: 4GB minimum, 8GB recommended
- Storage: ~10MB for the application executable. Database size depends on sync scope (for example,
VOCALOIDkeyword, 20 days, music category โ 40MB) - Network: Internet connection required for video playback and data sync
- Runtime: WebView2 Runtime is usually pre-installed on Windows 10/11
Database and settings are stored at:
Windows: %APPDATA%\com.vocaloid-search.desktop
To use portable mode (store data in the application folder), create a data/ folder in the same directory as the executable:
<vocaloid-search-desktop.exe location>/data/
When portable mode is active, all data (database, config, thumbnails) is stored in this folder. You can copy the entire folder to another computer and the application will use the same data.
Note: Switching between portable and standard mode does not automatically migrate data.
-
Startup Check
- On startup, the app checks whether the database is empty or stale.
- Niconico Snapshot API data typically refreshes daily around 5โ6 AM JST.
-
Sync Database
- Open the Data Sync page to configure scraping.
- Before a sync runs, the app performs a preflight confirmation with estimated matched videos, estimated database size, and available disk space.
- Sync is blocked when the estimated database size exceeds free disk space.
-
Search & Browse
- Search by keyword, combine tag filters, and adjust formula-based sorting.
- Enable Exclude Watched if you want search results to ignore watched videos.
-
Watch Videos
- Click a video in Search, History, or Watch Later to start playback.
- The embedded player appears first, and metadata is refined through backend-authoritative updates.
-
Use PiP Mode
- Pop playback into a native PiP window.
- PiP shares the same authoritative playback flow as the main window.
| Option | Default | Description |
|---|---|---|
query |
VOCALOID |
Search keyword for Niconico Snapshot API |
max_age_days |
365 |
Only fetch videos newer than N days. Leave empty for unlimited |
targets |
tags |
Search targets: tags, tagsExact, title, description, or combinations |
category_filter |
MUSIC |
Niconico category filter (MUSIC, GAME, ANIME, ENTERTAINMENT, DANCE, OTHER) |
Not fully. tauri dev is fine for general UI work, but Niconico embedded playback rejects localhost-origin behavior. Use npm run tauri build -- --debug or a release build when validating real embedded-player behavior.
That is intentional. The app uses staged metadata rendering: the embedded player appears first, then richer metadata is applied after authoritative Rust-side enrichment completes.
Search playback uses a frozen watched boundary for the active playback session. This prevents result membership from shifting underneath the current session.
The scraper now estimates matched videos, estimated database size, and available disk space before a sync runs. This helps avoid destructive or misleading sync attempts when storage is insufficient.
- Node.js 18+
- Rust 1.70+ (with
cargo) - Windows 10/11 SDK
# Clone the repository
git clone https://github.com/anton1615/VOCALOID-Search-Desktop.git
cd VOCALOID-Search-Desktop/vocaloid-search-desktop
# Install dependencies
npm installnpm run tauri devThis runs the frontend dev server and Tauri in development mode.
# Build frontend and backend together
npm run tauri build
# OR build with debug flag (faster build, larger binary)
npm run tauri build -- --debugImportant: Tauri uses a custom protocol (
tauri://localhost) instead of HTTP localhost for the embed player. This is required because Niconico's embed player rejects requests fromlocalhostdomains.Development Note: Since Niconico rejects localhost connections,
tauri devcannot be used to validate embedded-player behavior. Rebuild the full application when testing playback-related frontend changes. Using--debugspeeds up iteration by skipping Rust optimizations.
The built executable will be at:
vocaloid-search-desktop/src-tauri/target/release/vocaloid-search-desktop.exe
These are the noteworthy issues that still appear relevant to the current app behavior:
- PiP Window: It may occasionally fail to close cleanly (rare / cause still unclear)
- Region-Locked Videos: They can interrupt auto-play and cannot be marked as watched if playback fails entirely
- Active Event Timing: Switching tabs while a long-running event is in progress (for example sync or playback transitions) can still expose edge cases
- Rare PiP Sync Failure: PiP and main window synchronization is much more stable now, but rare sync failures are still noted as edge cases
The following ideas still appear aligned with the current product direction:
- ๐๏ธ Keyboard Shortcuts for playback controls
- ๐ Open in Browser actions from player surfaces or PiP
- ๐ Global Volume Control independent of the embedded player
- ๐ท๏ธ Clickable Tags to push tags directly into search criteria
- ๐ Title & Author Links above the embedded player
- ๐ง Linux Support using Tauri's cross-platform model
- ๐ฆ Offline Playback through local downloads
- ๐๏ธ Custom Playlists beyond Watch Later