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:
truewhile
2026-09-02 16:26:28 +08:00
committed by GitHub
parent a50ceaf1a7
commit b0fe40142a
435 changed files with 1152 additions and 1149 deletions
+1 -1
View File
@@ -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() {
+1 -1
View File
@@ -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 = {
+2 -2
View File
@@ -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>
+2 -2
View File
@@ -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>
+1 -1
View File
@@ -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() {
+1 -1
View File
@@ -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)'
+6 -6
View File
@@ -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>
+6 -6
View File
@@ -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())
}
+2 -2
View File
@@ -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
+1 -1
View File
@@ -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(自动加载第一条字幕)。
+2 -2
View File
@@ -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',
},
],
}
+1 -1
View File
@@ -56,7 +56,7 @@ export const useAuthStore = create<AuthState>()(
},
}),
{
name: 'mmtl-auth',
name: 'mebox-auth',
partialize: (state) => ({
token: state.token,
refreshToken: state.refreshToken,
+1 -1
View File
@@ -22,7 +22,7 @@ export const usePlayProfileStore = create<PlayProfileState>()(
})),
}),
{
name: 'mmtl-play-profile',
name: 'mebox-play-profile',
storage: createJSONStorage(() => sessionStorage),
},
),
+1 -1
View File
@@ -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 -1
View File
@@ -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 []