mirror of
https://github.com/truewhile/MeBox.git
synced 2026-10-02 04:16:38 +08:00
Rebrand MMTL to MeBox (name, logo, Docker image) (#17)
* Rebrand MMTL to MeBox across codebase and assets Rename the project display name, Go module path, environment variable prefix (MEBOX_*), Docker image references, and UI branding from MMTL/mmtl to MeBox/mebox. Replace logo assets with the new MeBox icon and keep legacy SQLite migration support for existing mmtl.db deployments. Co-authored-by: truewhile <truewhile@users.noreply.github.com> * Fix logo icons: use cube-only crop without truncated text Previous icon generation cropped too much of the source image, including partial MeBox wordmark text that was cut off in square icon containers. Regenerate logo-64/192/512, favicon, and SVG from cube-only region. Co-authored-by: truewhile <truewhile@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: truewhile <truewhile@users.noreply.github.com>
This commit is contained in:
+1
-1
@@ -16,7 +16,7 @@ class AppErrorBoundary extends Component<{ children: ReactNode }, { hasError: bo
|
||||
}
|
||||
|
||||
componentDidCatch(error: Error, info: ErrorInfo) {
|
||||
console.error('MMTL UI crashed', error, info)
|
||||
console.error('MeBox UI crashed', error, info)
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
@@ -29,7 +29,7 @@ export interface ExternalPlayer {
|
||||
|
||||
function publicOriginHeader() {
|
||||
if (typeof window === 'undefined' || !window.location?.origin) return undefined
|
||||
return { 'X-MMTL-Public-Origin': window.location.origin }
|
||||
return { 'X-MeBox-Public-Origin': window.location.origin }
|
||||
}
|
||||
|
||||
export const playbackAPI = {
|
||||
|
||||
@@ -73,11 +73,11 @@ export function LayoutHeader({
|
||||
<Link to="/" className={`flex items-center gap-2.5 transition-transform hover:scale-105 ${showSidebar ? 'lg:hidden' : 'hidden sm:flex'}`}>
|
||||
<img
|
||||
src="/brand/logo-192.png"
|
||||
alt="MMTL"
|
||||
alt="MeBox"
|
||||
className="h-9 w-9 rounded-xl object-contain shadow-sm"
|
||||
/>
|
||||
<span className="hidden font-display text-lg font-black tracking-tight text-[var(--app-text)] sm:inline-block">
|
||||
MMTL
|
||||
MeBox
|
||||
</span>
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
@@ -73,7 +73,7 @@ function LayoutSidebarHeader({
|
||||
<Link to="/" className="flex items-center gap-3">
|
||||
<img
|
||||
src="/brand/logo-192.png"
|
||||
alt="MMTL"
|
||||
alt="MeBox"
|
||||
className="h-10 w-10 shrink-0 rounded-xl object-contain shadow-sm"
|
||||
/>
|
||||
{sidebarExpanded && (
|
||||
@@ -82,7 +82,7 @@ function LayoutSidebarHeader({
|
||||
animate={{ opacity: 1, x: 0 }}
|
||||
className="font-display text-lg font-extrabold tracking-tight text-[var(--app-text)]"
|
||||
>
|
||||
MMTL
|
||||
MeBox
|
||||
</motion.span>
|
||||
)}
|
||||
</Link>
|
||||
|
||||
@@ -43,7 +43,7 @@ export class RouteErrorBoundary extends Component<{ children: ReactNode }, { has
|
||||
}
|
||||
|
||||
componentDidCatch(error: Error, info: ErrorInfo) {
|
||||
console.error('MMTL route crashed', error, info)
|
||||
console.error('MeBox route crashed', error, info)
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
@@ -3,7 +3,7 @@ import { useCallback, useEffect, useState } from 'react'
|
||||
export type ThemeMode = 'light' | 'dark' | 'system'
|
||||
export type ResolvedTheme = 'light' | 'dark'
|
||||
|
||||
const THEME_STORAGE_KEY = 'mmtl.theme'
|
||||
const THEME_STORAGE_KEY = 'mebox.theme'
|
||||
const THEME_LEGACY_STORAGE_KEY = 'mediastationgo.theme'
|
||||
const DARK_QUERY = '(prefers-color-scheme: dark)'
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ export function DatabaseSettingsPanel() {
|
||||
port: 5432,
|
||||
user: 'postgres',
|
||||
password: '',
|
||||
dbname: 'mmtl',
|
||||
dbname: 'mebox',
|
||||
sslmode: 'disable',
|
||||
dsn: '',
|
||||
})
|
||||
@@ -70,7 +70,7 @@ export function DatabaseSettingsPanel() {
|
||||
port: Number(formData.port) || 5432,
|
||||
user: formData.user?.trim() || '',
|
||||
password: formData.password || '',
|
||||
dbname: formData.dbname?.trim() || 'mmtl',
|
||||
dbname: formData.dbname?.trim() || 'mebox',
|
||||
sslmode: formData.sslmode || 'disable',
|
||||
}
|
||||
}
|
||||
@@ -144,7 +144,7 @@ export function DatabaseSettingsPanel() {
|
||||
const payload = getPayload()
|
||||
const ok = await confirmAction({
|
||||
title: '切换数据库',
|
||||
message: '保存后系统配置将更新为使用 PostgreSQL。需要重启 MMTL 服务使新数据库生效。确定保存吗?',
|
||||
message: '保存后系统配置将更新为使用 PostgreSQL。需要重启 MeBox 服务使新数据库生效。确定保存吗?',
|
||||
})
|
||||
if (!ok) return
|
||||
|
||||
@@ -211,7 +211,7 @@ export function DatabaseSettingsPanel() {
|
||||
<p className="font-mono text-ink-600 break-all">
|
||||
{status?.type === 'postgres'
|
||||
? status.dsn || '配置的 PostgreSQL 实例'
|
||||
: status?.db_path || './data/mmtl.db'}
|
||||
: status?.db_path || './data/mebox.db'}
|
||||
</p>
|
||||
</div>
|
||||
<div className="space-y-1 rounded-lg bg-sand-200/30 p-3">
|
||||
@@ -292,7 +292,7 @@ export function DatabaseSettingsPanel() {
|
||||
type="text"
|
||||
value={formData.dbname || ''}
|
||||
onChange={(e) => setFormData({ ...formData, dbname: e.target.value })}
|
||||
placeholder="mmtl"
|
||||
placeholder="mebox"
|
||||
className="w-full rounded-lg border border-gray-200 bg-sand-200/40 px-3 py-2 text-ink-600 placeholder:text-gray-400 focus:border-brand-500 focus:outline-none"
|
||||
/>
|
||||
</div>
|
||||
@@ -339,7 +339,7 @@ export function DatabaseSettingsPanel() {
|
||||
type="text"
|
||||
value={formData.dsn || ''}
|
||||
onChange={(e) => setFormData({ ...formData, dsn: e.target.value })}
|
||||
placeholder="postgres://user:password@127.0.0.1:5432/mmtl?sslmode=disable"
|
||||
placeholder="postgres://user:password@127.0.0.1:5432/mebox?sslmode=disable"
|
||||
className="w-full font-mono text-xs rounded-lg border border-gray-200 bg-sand-200/40 px-3 py-2 text-ink-600 placeholder:text-gray-400 focus:border-brand-500 focus:outline-none"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -41,11 +41,11 @@ export function LibraryPage() {
|
||||
|
||||
// 排序状态(支持按库记忆)
|
||||
const [sortField, setSortField] = useState<SortField>(() => {
|
||||
const saved = localStorage.getItem(`mmtl_lib_sort_field_${id}`) || localStorage.getItem('mmtl_lib_sort_field')
|
||||
const saved = localStorage.getItem(`mebox_lib_sort_field_${id}`) || localStorage.getItem('mebox_lib_sort_field')
|
||||
return (saved as SortField) || 'title'
|
||||
})
|
||||
const [sortOrder, setSortOrder] = useState<SortOrder>(() => {
|
||||
const saved = localStorage.getItem(`mmtl_lib_sort_order_${id}`) || localStorage.getItem('mmtl_lib_sort_order')
|
||||
const saved = localStorage.getItem(`mebox_lib_sort_order_${id}`) || localStorage.getItem('mebox_lib_sort_order')
|
||||
return (saved as SortOrder) || 'asc'
|
||||
})
|
||||
const [randomSeed, setRandomSeed] = useState(() => Date.now())
|
||||
@@ -78,11 +78,11 @@ export function LibraryPage() {
|
||||
setSortField(field)
|
||||
setSortOrder(order)
|
||||
if (id) {
|
||||
localStorage.setItem(`mmtl_lib_sort_field_${id}`, field)
|
||||
localStorage.setItem(`mmtl_lib_sort_order_${id}`, order)
|
||||
localStorage.setItem(`mebox_lib_sort_field_${id}`, field)
|
||||
localStorage.setItem(`mebox_lib_sort_order_${id}`, order)
|
||||
}
|
||||
localStorage.setItem('mmtl_lib_sort_field', field)
|
||||
localStorage.setItem('mmtl_lib_sort_order', order)
|
||||
localStorage.setItem('mebox_lib_sort_field', field)
|
||||
localStorage.setItem('mebox_lib_sort_order', order)
|
||||
if (field === 'random') {
|
||||
setRandomSeed(Date.now())
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ function LoginBrandHeader() {
|
||||
animate={{ scale: 1, opacity: 1 }}
|
||||
transition={{ delay: 0.15, type: 'spring', stiffness: 200 }}
|
||||
src="/brand/logo-192.png"
|
||||
alt="MMTL"
|
||||
alt="MeBox"
|
||||
className="mb-4 h-14 w-14 rounded-2xl object-contain shadow-sm"
|
||||
/>
|
||||
|
||||
@@ -83,7 +83,7 @@ function LoginBrandHeader() {
|
||||
transition={{ delay: 0.25 }}
|
||||
className="font-display text-2xl font-extrabold tracking-tight text-gray-900"
|
||||
>
|
||||
MMTL
|
||||
MeBox
|
||||
</motion.h1>
|
||||
|
||||
<motion.p
|
||||
|
||||
@@ -29,7 +29,7 @@ import { PlayerPlaylistPanel } from '../components/PlayerPlaylistPanel'
|
||||
//
|
||||
// External subtitles next to the source file are auto-discovered and
|
||||
// attached as <track> elements.
|
||||
const SUBTITLE_STORAGE_KEY = 'mmtl.subtitle'
|
||||
const SUBTITLE_STORAGE_KEY = 'mebox.subtitle'
|
||||
|
||||
// 初始字幕偏好:localStorage 记录上次选择的轨道(-1=关闭);没有偏好时
|
||||
// 默认 0(自动加载第一条字幕)。
|
||||
|
||||
@@ -133,14 +133,14 @@ export const generalSettingsGroup: SettingGroup = {
|
||||
label: 'SSL 证书路径',
|
||||
type: 'text',
|
||||
hint: '可选。填写证书文件的绝对路径则优先从文件读取(无需粘贴内容);留空则使用上方粘贴的证书内容。文件被替换后无需改设置,最长 30 秒内自动热加载新证书。',
|
||||
placeholder: '/etc/ssl/mmtl-cert.pem',
|
||||
placeholder: '/etc/ssl/mebox-cert.pem',
|
||||
},
|
||||
{
|
||||
key: 'https.key_path',
|
||||
label: 'SSL 私钥路径',
|
||||
type: 'text',
|
||||
hint: '可选。填写私钥文件的绝对路径则优先从文件读取;留空则使用上方粘贴的私钥内容。',
|
||||
placeholder: '/etc/ssl/mmtl-key.pem',
|
||||
placeholder: '/etc/ssl/mebox-key.pem',
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ export const useAuthStore = create<AuthState>()(
|
||||
},
|
||||
}),
|
||||
{
|
||||
name: 'mmtl-auth',
|
||||
name: 'mebox-auth',
|
||||
partialize: (state) => ({
|
||||
token: state.token,
|
||||
refreshToken: state.refreshToken,
|
||||
|
||||
@@ -22,7 +22,7 @@ export const usePlayProfileStore = create<PlayProfileState>()(
|
||||
})),
|
||||
}),
|
||||
{
|
||||
name: 'mmtl-play-profile',
|
||||
name: 'mebox-play-profile',
|
||||
storage: createJSONStorage(() => sessionStorage),
|
||||
},
|
||||
),
|
||||
|
||||
@@ -27,7 +27,7 @@ export interface StrmAccount {
|
||||
has_credential: boolean
|
||||
provider_label: string
|
||||
config_preview?: StrmAccountConfigPreview
|
||||
/** 仅远程 Emby 挂载账号返回:播放流量是否经过 MMTL 代理 */
|
||||
/** 仅远程 Emby 挂载账号返回:播放流量是否经过 MeBox 代理 */
|
||||
proxy_play?: boolean
|
||||
/** 仅远程 Emby 挂载账号返回:多线路配置 */
|
||||
emby_lines?: EmbyRemoteLine[]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const STORAGE_KEY = 'mmtl_pinned_libraries'
|
||||
const STORAGE_KEY = 'mebox_pinned_libraries'
|
||||
|
||||
function parsePinnedIds(raw: string | null): string[] {
|
||||
if (!raw) return []
|
||||
|
||||
Reference in New Issue
Block a user