English|简体中文
NOTE: We have set new update goals and will continue releasing updates in my spare time outside of study. Starting with V9.5.0, we have for the first time introduced a Windows version that includes built‑in PyCorsLocalProxy. If you need a reliable cross‑origin solution, you can use either the Android version with built‑in local CORS service or the new Windows version.
A meticulously designed web-based video streaming application featuring customizable video sources, elegant animations, and a robust caching mechanism
This project is essentially AI-generated. I was responsible for issue detection and optimization direction guidance. Models used: Doubao, Kimi, GLM-5.3-Flash/5/5-Turbo/4.7/4.6/4.6V/4.5, Deepseek-R1/Chat (provided assistance during project inception)
Visit Demo to try it now
Choose any of the following platforms and click the button to quickly create your own Bismuth Player instance:
|
|
|
|
☁️ Cloudflare Pages is supported out of the box: a
wrangler.tomlis provided at the repo root, and_redirects(SPA fallback) &_headers(security headers + long-term asset caching) ship inpublic/. Just click the button above to deploy — no extra configuration needed.
Material Design version created by Minimax Agent : View Here
- Dark Theme - Eye-friendly dark color scheme
- Gradient Design - Elegant purple-to-pink gradients
- Serif Font - Clear and beautiful Chinese typography
- Responsive Layout - Perfectly adapted for mobile and desktop
- Custom Video Sources - Support for multiple Apple CMS API sources (JSON format)
- Built-in Player (SimPlayer) - Integrated lightweight player supporting MP4/WebM/HLS with screenshot, PiP, speed control, and progress memory
- External Player Support - Fallback iframe-based player for custom player URLs
- Two-level Category Navigation — Dynamic categories loaded from API with top-level tabs and sub-category chips (leveraging Apple CMS
type_pidhierarchy) - Favorites System — ❤️ button on detail page to save favorites; dedicated Favorites tab with full management (view, play, remove, clear all)
- 🔞 Ethics Content Filter — Optional toggle in Video Source Settings to hide ethics categories and filter ethics videos from all lists
- Search Function - Quickly find the content you want
- Playback History - Automatically tracks viewing progress with one-click continue (accessible via homepage top-right button)
- Episode Selection - Clear episode selection interface with scrollable episode grid and current episode pulse highlight
- API Caching - Intelligent caching of API responses to reduce network requests
- Lazy Image Loading - Load images on demand to save bandwidth
- Skeleton Screen Loading - Elegant loading state display
- Page Transition Animations - Smooth transition effects
- Splash Screen - Elegant app startup animation
- Page Transitions - Slide in/out page transitions
- Image Loading - Fade-in animation for images
- Interaction Feedback - Button hover and click animations
| Technology | Version | Purpose |
|---|---|---|
| React | 19.2 | Frontend Framework |
| TypeScript | 5.9 | Type Safety |
| Vite | 7.2 | Build Tool |
| Tailwind CSS | 3.4 | Styling Framework |
| shadcn/ui | - | UI Component Library |
| hls.js | 1.6 | HLS Streaming |
| Lucide React | 0.562 | Icon Library |
- Node.js >= 20.19 (required by Vite 7; LTS 20/22/24 recommended)
- npm or bun
npm install
# or
bun installnpm run dev
# or
bun run devnpm run build
# or
bun run buildnpm run preview
# or
bun run preview- Go to the "Settings" page
- Click the "Add" button
- Fill in the video source information:
- ID: Unique identifier (e.g., mysource)
- Name: Display name (e.g., My Source)
- API URL: Apple CMS API address
Custom player addresses can be configured in the settings page, supporting any player that accepts URL parameters.
If you encounter CORS issues, you can configure a CORS proxy address in the settings. You can also disable the CORS proxy entirely to request sources directly.
- Enable/Disable API caching
- View cache statistics
- Clear cache
- Bottom navigation bar
- Compact card layout
- Gesture-friendly interactions
- Fixed left sidebar
- Widescreen grid layout
- Hover preview effects
Supports standard Apple CMS API format:
- List Endpoint:
?ac=videolist&pg=1 - Detail Endpoint:
?ac=videolist&ids=123 - Search Endpoint:
?ac=videolist&wd=keyword
Bismuth-Player/
├── src/
│ ├── components/ # Reusable components
│ │ ├── ui/ # shadcn/ui components
│ │ ├── SimPlayer.tsx
│ │ ├── BottomNav.tsx
│ │ └── VideoCard.tsx
│ ├── pages/ # Page components
│ │ ├── HomePage.tsx
│ │ ├── SearchPage.tsx
│ │ ├── DetailPage.tsx
│ │ ├── PlayerPage.tsx
│ │ ├── HistoryPage.tsx
│ │ ├── SettingsPage.tsx
│ │ └── settings/ # Settings sub-pages
│ │ ├── VideoSourcePage.tsx
│ │ ├── PlayerSettingsPage.tsx
│ │ ├── CorsProxyPage.tsx
│ │ ├── CacheSettingsPage.tsx
│ │ └── AboutPage.tsx
│ ├── services/ # Service layer
│ │ ├── api.ts # API requests
│ │ ├── cache.ts # Caching service
│ │ └── storage.ts # Local storage
│ ├── types/ # TypeScript types
│ ├── App.tsx # Main app component
│ ├── App.css # Global styles
│ └── main.tsx # Entry file
├── public/ # Static assets
├── package.json
├── vite.config.ts
└── README.md
Full changelog: CHANGELOG.md
- ✨ Standalone Filter page — homepage shows all content by default; a "筛选" button next to the search box opens a dedicated page with two-level category rows & infinite scroll
- ✨ History & Favorites source annotation — every card shows its origin source; cross-source playback fetches from the annotated source without switching the global one
- ✨ Deleted-source fallback — dedicated error notice when the annotated source is gone; entries get a 30-minute grace window (re-adding the same source ID restores them) before auto-cleanup
- 🐛 Fixed identity key for history/favorites (
vod_id + sourceId) so entries from different sources with the same numeric ID no longer collide
- 🐛 Fixed favicon 404 —
index.htmlreferenced the non-existent/vite.svg(Vite template leftover); now points to real app icons - 🐛 Corrected Node.js requirement — Vite 7 actually requires >= 20.19; updated both READMEs and added an
enginesfield topackage.json - ⚡ Code-splitting —
manualChunkssplits the 902 KB bundle into hls/react/vendor; hls.js loads on demand, cutting first-payload JS by ~59% (gzip) - 📦 Added GitHub Pages auto-publish workflow — builds and deploys on every push to main, with manual trigger support
- ☁️ Added Cloudflare Pages one-click deploy support —
wrangler.toml+_redirects(SPA fallback) +_headers(security headers & long-term caching); all three deploy buttons (Vercel/Netlify/Cloudflare) work out of the box
- 🐛 Fixed episode list not scrollable on player page — added
flex-1 max-h-[45vh]on mobile so episode grid scrolls independently with many episodes - 🐛 Fixed resume playback bug —
PlayerPageuseEffect missinginitialEpisodedependency - ✨ Added 🔞 Ethics content filter — toggle in Video Source Settings to hide ethics categories and filter ethics videos
- ✨ Added Favorites system — ❤️ button on detail page + dedicated Favorites tab with full management
- 📱 Navigation redesign — History moved to homepage top-right button; bottom nav now 4 items (Home/Search/Favorites/Settings)
- 📱 Global scrollbar styling + current episode pulse animation
- 🐛 Fixed build failure — removed 49 unused shadcn/ui zombie components and restored the missing
index.htmlVite entry file (was incorrectly gitignored) - 🐛 Fixed categories always falling back to hardcoded list —
getCategories()now requests the base URL directly (Apple CMS omitsclassfield when?ac=videolistparameter is present) - 🐛 Fixed inconsistent localStorage key naming —
video_sources/current_source_idrenamed tobismuth_prefix with automatic one-time migration of legacy data - 🐛 Fixed pagination field type inconsistency —
safeApiResponse()normalizes all pagination fields withNumber()to prevent string-comparison bugs - 🐛 Fixed sub-category "All" tab showing empty results — clicking a top-level category now auto-selects its first sub-category (Apple CMS top-level categories contain no direct videos)
- ✨ Added two-level category navigation — leverages
type_pidhierarchy: top-level categories as tabs + sub-categories as chips - 🔧 Updated
.gitignoreto track/index.html(critical fix for build reproducibility)
- 🐛 Fixed HomePage not refreshing after adding first video source or switching source
- 🐛 Fixed SimPlayer
crossOriginconflict on iOS causing HLS playback failures - 🐛 Fixed API response not validated — malformed responses caused TypeError crashes
- 🐛 Fixed
components.jsonpointing to wrong Tailwind config file - 🔧 Updated version fallback to V9.3.0
- 🐛 Fixed VideoCard referencing removed
imageErrorafter v9.2.0 cleanup - 🐛 Replaced native
loading="lazy"withIntersectionObserverto stop background image loading - 🐛 Fixed
img.srcclearing on unmount triggering console error - 🐛 Fixed
HomePagehasMorereferencing undefinedlimitvariable causing infinite fetch loop - 🧹 Removed unused
CACHE_TTL.searchdead code
- 🐛 Fixed
parsePlayUrlsnot handling multi-source$$$separator - 🐛 Fixed iOS Safari HLS event listener memory leak and error handler race condition
- 🐛 Fixed
DetailPageskeleton screen not resetting on video switch - 🐛 Fixed
PlayerPageepisode not syncing with prop - 🐛 Fixed
fetchWithRetrynon-OK response error reporting and connection pool exhaustion - 🐛 Fixed version number fallback mismatch
- ✨ Added volume slider to SimPlayer (hover to reveal)
- ✨ Improved pagination accuracy using API metadata
- 🧹 Removed unused
_viewKeyandimageErrorstates - ⚡ Optimized re-render performance in App, PlayerPage, and SimPlayer
- 📁 Added
.gitignore, removed build artifacts from repository
V9.1 and earlier
- 🐛 Fixed settings page crash —
ArrowLefticon missing from import caused "ArrowLeft is not defined" runtime error - 🐛 Fixed critical CORS proxy double-wrapping bug
- 🐛 Fixed Toast notifications invisible
- 🐛 Fixed auto-resume setting not working
- 🧹 Removed dead
carousel.tsximport dependencies
- 🏗️ Settings page redesigned — each setting category now has its own dedicated page
- ✨ Added proxy priority reordering
- ✨ Enhanced cache settings page
- 🔧 Unified storage key naming convention
- 🐛 Fixed iOS Safari HLS playback stuttering and CORS preflight overhead on iOS
- 🐛 Fixed fullscreen button not responding on iOS Safari
- 🐛 Fixed progress bar not responding to clicks and drags
- ✨ Added "Check for Updates" feature
- ✨ Integrated SimPlayer as built-in player
- ✨ Built-in player features: screenshot, PiP, speed control, progress memory
- ✨ CORS proxy toggle
- ✨ Added splash screen, page transitions, skeleton screens
- 🐛 Removed PWA functionality
- Various UI improvements and bug fixes
This project was inspired by LibreTV. I found LibreTV useful but requiring a backend, so I wanted to create a backend-free version. Thus, this project was born through my conversations with AIs... Thanks to that project for the creative inspiration.
This project is open-sourced under the Apache License 2.0.
Bismuth Player is solely a playback tool shell and does not provide any video content or resources.
- This application does not store, host, or distribute any video content
- All content comes from third-party video sources configured by users themselves
- Users must ensure that the content sources used are legal and compliant
- Users bear full legal responsibility for using illegal sources
- The developer is not responsible for any third-party content or user behavior
By using this application, you indicate that you have read and agree to the above terms.
Made with 💜 by Eq52