mirror of
https://github.com/truewhile/MeBox.git
synced 2026-10-07 05:46:38 +08:00
优化
优化
This commit is contained in:
@@ -13,7 +13,7 @@ import (
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/repository"
|
||||
"github.com/ShukeBta/MMTL/internal/repository"
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
@@ -11,8 +11,8 @@ import (
|
||||
"go.uber.org/zap"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MediaStationGo/internal/repository"
|
||||
"github.com/ShukeBta/MMTL/internal/model"
|
||||
"github.com/ShukeBta/MMTL/internal/repository"
|
||||
)
|
||||
|
||||
func TestAdultProviderRouting(t *testing.T) {
|
||||
|
||||
@@ -8,8 +8,8 @@ import (
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MediaStationGo/internal/repository"
|
||||
"github.com/ShukeBta/MMTL/internal/model"
|
||||
"github.com/ShukeBta/MMTL/internal/repository"
|
||||
)
|
||||
|
||||
func TestNormalizeAdultCode(t *testing.T) {
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
// read so values stored on disk are useless without the JWT secret.
|
||||
//
|
||||
// On first read it seeds the table with the providers supported by
|
||||
// MediaStationGo today (TMDb / Bangumi / TheTVDB / Fanart / OpenAI / Douban).
|
||||
// MMTL today (TMDb / Bangumi / TheTVDB / Fanart / OpenAI / Douban).
|
||||
package service
|
||||
|
||||
import (
|
||||
@@ -17,8 +17,8 @@ import (
|
||||
"go.uber.org/zap"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MediaStationGo/internal/repository"
|
||||
"github.com/ShukeBta/MMTL/internal/model"
|
||||
"github.com/ShukeBta/MMTL/internal/repository"
|
||||
)
|
||||
|
||||
// APIConfigService coordinates third-party API key storage.
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MMTL/internal/model"
|
||||
)
|
||||
|
||||
// TestConnection 测试 API 连接。
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MMTL/internal/model"
|
||||
)
|
||||
|
||||
// GetEffectiveConfig 获取生效的 API 配置(数据库配置优先于配置文件)。
|
||||
|
||||
@@ -7,9 +7,9 @@ import (
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/config"
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MediaStationGo/internal/repository"
|
||||
"github.com/ShukeBta/MMTL/internal/config"
|
||||
"github.com/ShukeBta/MMTL/internal/model"
|
||||
"github.com/ShukeBta/MMTL/internal/repository"
|
||||
)
|
||||
|
||||
// ApiConfigService 负责第三方 API 配置的 CRUD 和加密管理。
|
||||
|
||||
@@ -12,8 +12,8 @@ import (
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MediaStationGo/internal/repository"
|
||||
"github.com/ShukeBta/MMTL/internal/model"
|
||||
"github.com/ShukeBta/MMTL/internal/repository"
|
||||
)
|
||||
|
||||
// AuditService is the only sanctioned writer for the access_logs table.
|
||||
|
||||
@@ -12,9 +12,9 @@ import (
|
||||
"go.uber.org/zap"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/config"
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MediaStationGo/internal/repository"
|
||||
"github.com/ShukeBta/MMTL/internal/config"
|
||||
"github.com/ShukeBta/MMTL/internal/model"
|
||||
"github.com/ShukeBta/MMTL/internal/repository"
|
||||
)
|
||||
|
||||
// AuthService handles registration, login, and JWT issuance.
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MMTL/internal/model"
|
||||
)
|
||||
|
||||
// IssueToken signs a JWT for the given user (60min validity, includes tier).
|
||||
@@ -21,7 +21,7 @@ func (s *AuthService) IssueToken(u *model.User) (string, error) {
|
||||
RegisteredClaims: jwt.RegisteredClaims{
|
||||
IssuedAt: jwt.NewNumericDate(time.Now()),
|
||||
ExpiresAt: jwt.NewNumericDate(time.Now().Add(60 * time.Minute)),
|
||||
Issuer: "mediastationgo",
|
||||
Issuer: "mmtl",
|
||||
Subject: u.ID,
|
||||
},
|
||||
}
|
||||
@@ -68,7 +68,7 @@ func (s *AuthService) IssueExternalPlaybackToken(u *model.User, mediaID string,
|
||||
RegisteredClaims: jwt.RegisteredClaims{
|
||||
IssuedAt: jwt.NewNumericDate(time.Now()),
|
||||
ExpiresAt: jwt.NewNumericDate(time.Now().Add(ExternalPlaybackTokenDurationForMedia(durationSec))),
|
||||
Issuer: "mediastationgo",
|
||||
Issuer: "mmtl",
|
||||
Subject: u.ID,
|
||||
},
|
||||
}
|
||||
@@ -95,7 +95,7 @@ func (s *AuthService) IssueEmbyToken(u *model.User) (string, error) {
|
||||
RegisteredClaims: jwt.RegisteredClaims{
|
||||
IssuedAt: jwt.NewNumericDate(time.Now()),
|
||||
ExpiresAt: jwt.NewNumericDate(time.Now().Add(EmbyTokenDuration)),
|
||||
Issuer: "mediastationgo",
|
||||
Issuer: "mmtl",
|
||||
Subject: u.ID,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -12,10 +12,10 @@ import (
|
||||
"go.uber.org/zap"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/config"
|
||||
"github.com/ShukeBta/MediaStationGo/internal/database"
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MediaStationGo/internal/repository"
|
||||
"github.com/ShukeBta/MMTL/internal/config"
|
||||
"github.com/ShukeBta/MMTL/internal/database"
|
||||
"github.com/ShukeBta/MMTL/internal/model"
|
||||
"github.com/ShukeBta/MMTL/internal/repository"
|
||||
)
|
||||
|
||||
func newAuthTestServices(t *testing.T) (*repository.Container, *AuthService, *ProfileService, *PermissionService) {
|
||||
|
||||
@@ -19,7 +19,7 @@ import (
|
||||
"go.uber.org/zap"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/config"
|
||||
"github.com/ShukeBta/MMTL/internal/config"
|
||||
)
|
||||
|
||||
// BackupService manages database backups.
|
||||
@@ -72,7 +72,7 @@ func (b *BackupService) Create(ctx context.Context) (*BackupInfo, error) {
|
||||
return nil, err
|
||||
}
|
||||
ts := time.Now().Format("20060102_150405")
|
||||
dst := filepath.Join(dir, fmt.Sprintf("mediastation_%s.db", ts))
|
||||
dst := filepath.Join(dir, fmt.Sprintf("mmtl_%s.db", ts))
|
||||
|
||||
// VACUUM INTO creates a clean, non-WAL copy atomically.
|
||||
if err := b.db.WithContext(ctx).Exec("VACUUM INTO ?", dst).Error; err != nil {
|
||||
|
||||
@@ -23,7 +23,7 @@ import (
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/config"
|
||||
"github.com/ShukeBta/MMTL/internal/config"
|
||||
)
|
||||
|
||||
// BangumiProvider talks to https://api.bgm.tv.
|
||||
@@ -181,7 +181,7 @@ func (b *BangumiProvider) getJSON(ctx context.Context, u string, out any) error
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req.Header.Set("User-Agent", "MediaStationGo/0.1 (https://github.com/ShukeBta/MediaStationGo)")
|
||||
req.Header.Set("User-Agent", "MMTL/0.1 (https://github.com/ShukeBta/MMTL)")
|
||||
if t := strings.TrimSpace(b.cfg.Secrets.BangumiToken); t != "" {
|
||||
req.Header.Set("Authorization", "Bearer "+t)
|
||||
}
|
||||
|
||||
@@ -7,8 +7,8 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MediaStationGo/internal/repository"
|
||||
"github.com/ShukeBta/MMTL/internal/model"
|
||||
"github.com/ShukeBta/MMTL/internal/repository"
|
||||
)
|
||||
|
||||
// Bot / 设备管控相关的设置键。全部存储在 settings 表,由管理员通过
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/service/cloud115"
|
||||
"github.com/ShukeBta/MMTL/internal/service/cloud115"
|
||||
)
|
||||
|
||||
// 115 开放平台(openapi)驱动测试:mock proapi 的列目录/直链接口。
|
||||
|
||||
@@ -13,7 +13,7 @@ import (
|
||||
// cloudDrive2Provider bridges CloudDrive2 through its WebDAV endpoint.
|
||||
//
|
||||
// CloudDrive2 integrates many cloud disks (115 / 123 / Aliyun and more).
|
||||
// Treating it as a WebDAV-backed cloud provider lets MediaStationGo
|
||||
// Treating it as a WebDAV-backed cloud provider lets MMTL
|
||||
// browse, mount and upload to those disks without carrying every provider's
|
||||
// private chunk-upload protocol in this project.
|
||||
type cloudDrive2Provider struct {
|
||||
|
||||
@@ -19,7 +19,7 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/service/cloud115"
|
||||
"github.com/ShukeBta/MMTL/internal/service/cloud115"
|
||||
)
|
||||
|
||||
// openAPI115Provider 实现 Provider 接口:List 列目录、Resolve 用 pickcode
|
||||
|
||||
@@ -6,8 +6,8 @@ import (
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MediaStationGo/internal/repository"
|
||||
"github.com/ShukeBta/MMTL/internal/model"
|
||||
"github.com/ShukeBta/MMTL/internal/repository"
|
||||
)
|
||||
|
||||
// CloudMountInfo 是云盘挂载库的规范标识(因网盘后端已移除,仅保留类型以兼容
|
||||
|
||||
@@ -15,7 +15,7 @@ import (
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/repository"
|
||||
"github.com/ShukeBta/MMTL/internal/repository"
|
||||
)
|
||||
|
||||
// Danmaku setting keys, managed through the admin settings UI (PUT
|
||||
@@ -296,7 +296,7 @@ func (s *DanmakuService) fetchBody(ctx context.Context, sourceURL string, follow
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
req.Header.Set("User-Agent", "MediaStationGo/danmaku (+https://github.com/ShukeBta/MediaStationGo)")
|
||||
req.Header.Set("User-Agent", "MMTL/danmaku (+https://github.com/ShukeBta/MMTL)")
|
||||
req.Header.Set("Accept", "application/json, application/xml, */*")
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
|
||||
@@ -13,8 +13,8 @@ import (
|
||||
"go.uber.org/zap"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MediaStationGo/internal/repository"
|
||||
"github.com/ShukeBta/MMTL/internal/model"
|
||||
"github.com/ShukeBta/MMTL/internal/repository"
|
||||
)
|
||||
|
||||
func newDanmakuTestService(t *testing.T) *DanmakuService {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package service
|
||||
|
||||
import "github.com/ShukeBta/MediaStationGo/internal/repository"
|
||||
import "github.com/ShukeBta/MMTL/internal/repository"
|
||||
|
||||
func IsTransientDatabaseLock(err error) bool {
|
||||
return repository.IsSQLiteBusyError(err)
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MMTL/internal/model"
|
||||
)
|
||||
|
||||
// SweepInactiveUsers is kept for compatibility with the existing scheduler; it
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MMTL/internal/model"
|
||||
)
|
||||
|
||||
// KickDevice marks a device as kicked so the next request from it is rejected
|
||||
|
||||
@@ -10,8 +10,8 @@ import (
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MediaStationGo/internal/repository"
|
||||
"github.com/ShukeBta/MMTL/internal/model"
|
||||
"github.com/ShukeBta/MMTL/internal/repository"
|
||||
)
|
||||
|
||||
// DeviceService implements device/session tracking and the two decoupled
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
// service to start playback of an HTTP URL.
|
||||
//
|
||||
// We do NOT mediate the renderer ↔ client traffic; the renderer pulls
|
||||
// the bytes directly from MediaStationGo's /api/stream endpoint, so
|
||||
// the bytes directly from MMTL's /api/stream endpoint, so
|
||||
// the cast call only ever transports a URL string.
|
||||
package service
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ import (
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/config"
|
||||
"github.com/ShukeBta/MMTL/internal/config"
|
||||
)
|
||||
|
||||
// DoubanProvider talks to the unofficial Douban movie API.
|
||||
|
||||
@@ -5,8 +5,8 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MediaStationGo/internal/repository"
|
||||
"github.com/ShukeBta/MMTL/internal/model"
|
||||
"github.com/ShukeBta/MMTL/internal/repository"
|
||||
)
|
||||
|
||||
// ImageURL returns artwork for a media/series/season item id.
|
||||
|
||||
@@ -3,7 +3,7 @@ package service
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MMTL/internal/model"
|
||||
)
|
||||
|
||||
func TestImageURLFallsBackToLibraryCoverURL(t *testing.T) {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// EmbyService produces JSON envelopes shaped like the most-consumed
|
||||
// Emby-API endpoints so existing players (Infuse / Yamby / Hills /
|
||||
// Senplayer / Kodi NextPVR extension / iOS native clients) can talk to
|
||||
// MediaStationGo without a custom plugin.
|
||||
// MMTL without a custom plugin.
|
||||
//
|
||||
// The shim is read-mostly: items, images, playback are fully covered;
|
||||
// 播放进度上报 / 收藏切换 是写路径但走我们自己的 PlaybackHistory /
|
||||
@@ -17,14 +17,14 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/config"
|
||||
"github.com/ShukeBta/MediaStationGo/internal/repository"
|
||||
"github.com/ShukeBta/MMTL/internal/config"
|
||||
"github.com/ShukeBta/MMTL/internal/repository"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
// 用一个固定的 ServerId 字符串。Emby 客户端会缓存这个 id,第一次见到
|
||||
// 该 id 后会把所有派生数据(cookie/收藏/历史)和它绑定。
|
||||
const embyServerID = "mediastation-go-001"
|
||||
const embyServerID = "mmtl-001"
|
||||
|
||||
// embyCompatVersion deliberately reports an Emby 4.x server. Official Emby
|
||||
// clients reject Jellyfin-style 10.x identities as unsupported/too old during
|
||||
|
||||
@@ -6,9 +6,9 @@ import (
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/config"
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MediaStationGo/internal/repository"
|
||||
"github.com/ShukeBta/MMTL/internal/config"
|
||||
"github.com/ShukeBta/MMTL/internal/model"
|
||||
"github.com/ShukeBta/MMTL/internal/repository"
|
||||
)
|
||||
|
||||
func newTestEmbyService(t *testing.T) *EmbyService {
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MMTL/internal/model"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MMTL/internal/model"
|
||||
)
|
||||
|
||||
// Item 单条目详情。
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MMTL/internal/model"
|
||||
)
|
||||
|
||||
func (e *EmbyService) mediaItems(ctx context.Context, p ItemsParams) (map[string]any, error) {
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MMTL/internal/model"
|
||||
)
|
||||
|
||||
func (e *EmbyService) mediaSourcesForItem(ctx context.Context, m *model.Media, asEmbedded, directOnly bool) []map[string]any {
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
|
||||
"gorm.io/gorm"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MMTL/internal/model"
|
||||
)
|
||||
|
||||
// movieLibraryHasEpisodicContent 报告电影类型库里是否混入了「剧集结构」内容
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MMTL/internal/model"
|
||||
)
|
||||
|
||||
func TestEmbyMovieLibrarySeasonNumbersStayMovies(t *testing.T) {
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MMTL/internal/model"
|
||||
)
|
||||
|
||||
// PlaybackInfo returns a PlaybackInfoResponse usable by Emby clients.
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MMTL/internal/model"
|
||||
)
|
||||
|
||||
func TestEmbyRootItemsExposeLibraries(t *testing.T) {
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MMTL/internal/model"
|
||||
)
|
||||
|
||||
type embySeriesGroup struct {
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MMTL/internal/model"
|
||||
)
|
||||
|
||||
func TestEmbyItemsExposeSeriesSeasonEpisodeHierarchy(t *testing.T) {
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MMTL/internal/model"
|
||||
)
|
||||
|
||||
func (e *EmbyService) seriesIDForMedia(m *model.Media) string {
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MMTL/internal/model"
|
||||
)
|
||||
|
||||
// writeTempVideoWithSubtitle creates a temp directory with a fake video and a
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MMTL/internal/model"
|
||||
)
|
||||
|
||||
// SystemInfo returns the full Emby identity payload.
|
||||
@@ -13,7 +13,7 @@ func (e *EmbyService) SystemInfo() map[string]any {
|
||||
return map[string]any{
|
||||
"Id": embyServerID,
|
||||
"ServerId": embyServerID,
|
||||
"ServerName": "MediaStationGo",
|
||||
"ServerName": "MMTL",
|
||||
"Version": embyCompatVersion,
|
||||
"ServerVersion": embyCompatVersion,
|
||||
"ProductName": "Emby Server",
|
||||
@@ -42,7 +42,7 @@ func (e *EmbyService) SystemInfoPublic() map[string]any {
|
||||
return map[string]any{
|
||||
"Id": embyServerID,
|
||||
"ServerId": embyServerID,
|
||||
"ServerName": "MediaStationGo",
|
||||
"ServerName": "MMTL",
|
||||
"Version": embyCompatVersion,
|
||||
"ServerVersion": embyCompatVersion,
|
||||
"ProductName": "Emby Server",
|
||||
@@ -85,7 +85,7 @@ func (e *EmbyService) userPayload(u *model.User) map[string]any {
|
||||
"Id": u.ID,
|
||||
"Name": u.Username,
|
||||
"ServerId": embyServerID,
|
||||
"ServerName": "MediaStationGo",
|
||||
"ServerName": "MMTL",
|
||||
"HasPassword": true,
|
||||
"HasConfiguredPassword": true,
|
||||
"HasConfiguredEasyPassword": false,
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
|
||||
"gorm.io/gorm"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MMTL/internal/model"
|
||||
)
|
||||
|
||||
// SetFavorite 把 mediaID 标为 userID 的收藏。
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MMTL/internal/model"
|
||||
)
|
||||
|
||||
func TestEmbyLatestItemsCollapsesMovieVersions(t *testing.T) {
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
|
||||
"gorm.io/gorm"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MMTL/internal/model"
|
||||
)
|
||||
|
||||
func (e *EmbyService) applyUserMediaVisibility(ctx context.Context, q *gorm.DB, userID string) *gorm.DB {
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
"go.uber.org/zap"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MMTL/internal/model"
|
||||
)
|
||||
|
||||
// pollutedEpisodeCleanupSettingKey marks that the one-time normalization has run.
|
||||
|
||||
@@ -6,8 +6,8 @@ import (
|
||||
"go.uber.org/zap"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MediaStationGo/internal/repository"
|
||||
"github.com/ShukeBta/MMTL/internal/model"
|
||||
"github.com/ShukeBta/MMTL/internal/repository"
|
||||
)
|
||||
|
||||
func newCleanupTestContainer(t *testing.T) (*Container, *gorm.DB) {
|
||||
|
||||
@@ -21,7 +21,7 @@ import (
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/config"
|
||||
"github.com/ShukeBta/MMTL/internal/config"
|
||||
)
|
||||
|
||||
// FanartProvider talks to https://webservice.fanart.tv.
|
||||
@@ -133,7 +133,7 @@ func (f *FanartProvider) getJSON(ctx context.Context, u string, out any) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req.Header.Set("User-Agent", "MediaStationGo/0.1")
|
||||
req.Header.Set("User-Agent", "MMTL/0.1")
|
||||
resp, err := f.client.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/config"
|
||||
"github.com/ShukeBta/MMTL/internal/config"
|
||||
)
|
||||
|
||||
// AutoInstallFFmpeg is only called by the admin tool-install endpoint. The
|
||||
@@ -91,7 +91,7 @@ func downloadFFmpegWindows(log *zap.Logger, installDir string) (bool, error) {
|
||||
return false, fmt.Errorf("创建安装目录失败: %w", err)
|
||||
}
|
||||
|
||||
tempDir, err := os.MkdirTemp("", "mediastationgo-ffmpeg-*")
|
||||
tempDir, err := os.MkdirTemp("", "mmtl-ffmpeg-*")
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("创建临时目录失败: %w", err)
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ import (
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/config"
|
||||
"github.com/ShukeBta/MMTL/internal/config"
|
||||
)
|
||||
|
||||
// FFprobeService wraps the external ffprobe binary.
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/config"
|
||||
"github.com/ShukeBta/MMTL/internal/config"
|
||||
)
|
||||
|
||||
func TestFFprobeServiceDefaultsToSingleConcurrentProbe(t *testing.T) {
|
||||
|
||||
@@ -16,8 +16,8 @@ import (
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/config"
|
||||
"github.com/ShukeBta/MediaStationGo/internal/repository"
|
||||
"github.com/ShukeBta/MMTL/internal/config"
|
||||
"github.com/ShukeBta/MMTL/internal/repository"
|
||||
)
|
||||
|
||||
// FileManagerService browses and mutates the server-side filesystem.
|
||||
|
||||
@@ -67,8 +67,8 @@ func (s *FileManagerService) allowedRoots() (map[string]string, error) {
|
||||
add("movies", s.cfg.Media.MoviesDir)
|
||||
add("tv", s.cfg.Media.TVDir)
|
||||
add("anime", s.cfg.Media.AnimeDir)
|
||||
add("downloads", envOrDefault("MEDIASTATION_DOWNLOAD_CONTAINER_DIR", "/downloads"))
|
||||
add("media", envOrDefault("MEDIASTATION_MEDIA_CONTAINER_DIR", "/media"))
|
||||
add("downloads", envOrDefault("MMTL_DOWNLOAD_CONTAINER_DIR", "/downloads"))
|
||||
add("media", envOrDefault("MMTL_MEDIA_CONTAINER_DIR", "/media"))
|
||||
if s.repo != nil && s.repo.Setting != nil {
|
||||
addSetting := func(label, key string) {
|
||||
if value, err := s.repo.Setting.Get(context.Background(), key); err == nil {
|
||||
|
||||
@@ -8,9 +8,9 @@ import (
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/config"
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MediaStationGo/internal/repository"
|
||||
"github.com/ShukeBta/MMTL/internal/config"
|
||||
"github.com/ShukeBta/MMTL/internal/model"
|
||||
"github.com/ShukeBta/MMTL/internal/repository"
|
||||
)
|
||||
|
||||
func newFileManagerTestServiceWithRepo(t *testing.T, root string) (*FileManagerService, *repository.Container) {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
//
|
||||
// Some deployments cannot reach image.tmdb.org directly (GFW, internal-only
|
||||
// networks). ImageProxy fronts a remote image URL so the browser only ever
|
||||
// talks to the MediaStationGo origin. The proxy:
|
||||
// talks to the MMTL origin. The proxy:
|
||||
//
|
||||
// - validates the URL scheme is http/https,
|
||||
// - streams bytes through with a small disk cache under cache/images,
|
||||
@@ -20,7 +20,7 @@ import (
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/config"
|
||||
"github.com/ShukeBta/MMTL/internal/config"
|
||||
)
|
||||
|
||||
// ImageProxy fetches and caches remote images on behalf of the browser.
|
||||
|
||||
@@ -14,7 +14,7 @@ import (
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/config"
|
||||
"github.com/ShukeBta/MMTL/internal/config"
|
||||
)
|
||||
|
||||
func TestImageProxyDoesNotNegativeCacheFailedRemoteImageFetch(t *testing.T) {
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/config"
|
||||
"github.com/ShukeBta/MMTL/internal/config"
|
||||
)
|
||||
|
||||
var testJPEG = []byte{
|
||||
|
||||
@@ -6,8 +6,8 @@ import (
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MediaStationGo/internal/repository"
|
||||
"github.com/ShukeBta/MMTL/internal/model"
|
||||
"github.com/ShukeBta/MMTL/internal/repository"
|
||||
)
|
||||
|
||||
var availabilityNoiseRE = regexp.MustCompile(`(?i)(自动订阅|订阅|全集|合集|complete|batch|s\d{1,2}e\d{1,3}|season\s*\d+|s\d{1,2}|第\s*\d+\s*季|第\s*\d+\s*[集话話期]|\(\d{4}\)|\b\d{4}\b|2160p|1080p|720p|4k|uhd|bluray|blu-ray|web-?dl|hdtv|remux|x26[45]|h\.?26[45]|hevc|avc|hdr10?\+?|dovi|dv|atmos|aac|ddp?5\.1|truehd|flac)`)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package service
|
||||
|
||||
import "github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
import "github.com/ShukeBta/MMTL/internal/model"
|
||||
|
||||
func applyLocalMetadata(m *model.Media, local *LocalMetadata) {
|
||||
applyLocalIdentityMetadata(m, local)
|
||||
|
||||
@@ -3,7 +3,7 @@ package service
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MMTL/internal/model"
|
||||
)
|
||||
|
||||
func TestApplyLocalMetadataPreservesPathHintAsPending(t *testing.T) {
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MMTL/internal/model"
|
||||
)
|
||||
|
||||
type ManualScrapeRequest struct {
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MMTL/internal/model"
|
||||
)
|
||||
|
||||
type manualTMDbCandidate struct {
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MMTL/internal/model"
|
||||
)
|
||||
|
||||
func (s *ScraperService) ManualSearch(ctx context.Context, media *model.Media, query, provider, mediaType string) ([]ExternalMediaResult, error) {
|
||||
|
||||
@@ -13,9 +13,9 @@ import (
|
||||
"go.uber.org/zap"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/config"
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MediaStationGo/internal/repository"
|
||||
"github.com/ShukeBta/MMTL/internal/config"
|
||||
"github.com/ShukeBta/MMTL/internal/model"
|
||||
"github.com/ShukeBta/MMTL/internal/repository"
|
||||
)
|
||||
|
||||
func TestManualRequestMatchFallsBackToCandidatePayload(t *testing.T) {
|
||||
|
||||
@@ -4,9 +4,9 @@ package service
|
||||
import (
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/config"
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MediaStationGo/internal/repository"
|
||||
"github.com/ShukeBta/MMTL/internal/config"
|
||||
"github.com/ShukeBta/MMTL/internal/model"
|
||||
"github.com/ShukeBta/MMTL/internal/repository"
|
||||
)
|
||||
|
||||
// MediaService offers high-level CRUD over libraries and media items.
|
||||
|
||||
@@ -8,8 +8,8 @@ import (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MediaStationGo/internal/repository"
|
||||
"github.com/ShukeBta/MMTL/internal/model"
|
||||
"github.com/ShukeBta/MMTL/internal/repository"
|
||||
)
|
||||
|
||||
type mediaListCacheValue struct {
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MMTL/internal/model"
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
@@ -4,8 +4,8 @@ import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MediaStationGo/internal/repository"
|
||||
"github.com/ShukeBta/MMTL/internal/model"
|
||||
"github.com/ShukeBta/MMTL/internal/repository"
|
||||
)
|
||||
|
||||
func (s *MediaService) attachLibraryMetadata(ctx context.Context, items []model.Media) {
|
||||
|
||||
@@ -3,7 +3,7 @@ package service
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MMTL/internal/model"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MMTL/internal/model"
|
||||
)
|
||||
|
||||
type LibraryRootInput struct {
|
||||
|
||||
@@ -6,9 +6,9 @@ import (
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/config"
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MediaStationGo/internal/repository"
|
||||
"github.com/ShukeBta/MMTL/internal/config"
|
||||
"github.com/ShukeBta/MMTL/internal/model"
|
||||
"github.com/ShukeBta/MMTL/internal/repository"
|
||||
)
|
||||
|
||||
func TestCreateLibraryWithRootsAppendsToExistingLogicalLibrary(t *testing.T) {
|
||||
|
||||
@@ -6,8 +6,8 @@ import (
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MediaStationGo/internal/repository"
|
||||
"github.com/ShukeBta/MMTL/internal/model"
|
||||
"github.com/ShukeBta/MMTL/internal/repository"
|
||||
)
|
||||
|
||||
// ListMedia paginates media items inside a library.
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MMTL/internal/model"
|
||||
)
|
||||
|
||||
type MediaMetadataUpdate struct {
|
||||
|
||||
@@ -5,9 +5,9 @@ import (
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/config"
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MediaStationGo/internal/repository"
|
||||
"github.com/ShukeBta/MMTL/internal/config"
|
||||
"github.com/ShukeBta/MMTL/internal/model"
|
||||
"github.com/ShukeBta/MMTL/internal/repository"
|
||||
)
|
||||
|
||||
func TestUpdateMediaMetadataMarksManualMatch(t *testing.T) {
|
||||
|
||||
@@ -69,8 +69,8 @@ func embeddedContainerMarkerCandidates(input string) []string {
|
||||
part string
|
||||
container string
|
||||
}{
|
||||
{part: "/media", container: envOrDefault("MEDIASTATION_MEDIA_CONTAINER_DIR", "/media")},
|
||||
{part: "/downloads", container: envOrDefault("MEDIASTATION_DOWNLOAD_CONTAINER_DIR", "/downloads")},
|
||||
{part: "/media", container: envOrDefault("MMTL_MEDIA_CONTAINER_DIR", "/media")},
|
||||
{part: "/downloads", container: envOrDefault("MMTL_DOWNLOAD_CONTAINER_DIR", "/downloads")},
|
||||
} {
|
||||
part := strings.TrimRight(marker.part, "/")
|
||||
container := strings.TrimRight(filepath.ToSlash(marker.container), "/")
|
||||
@@ -83,17 +83,17 @@ func embeddedContainerMarkerCandidates(input string) []string {
|
||||
|
||||
// describeUnresolvedLibraryPath 把「路径解析失败」变成可操作的诊断信息:列出尝试过的
|
||||
// 候选路径与当前的宿主机→容器映射状态。旧库存的是宿主机路径,在新版/容器内常因为缺少
|
||||
// MEDIASTATION_MEDIA_DIR 映射而扫不出媒体——这条诊断帮助用户直接定位到底哪一步断了。
|
||||
// MMTL_MEDIA_DIR 映射而扫不出媒体——这条诊断帮助用户直接定位到底哪一步断了。
|
||||
// 仅用于日志与扫描错误提示,不改变解析逻辑本身。
|
||||
func describeUnresolvedLibraryPath(rawPath string) string {
|
||||
rawPath = strings.TrimSpace(rawPath)
|
||||
candidates := mappedPathCandidates(rawPath)
|
||||
mediaHost := strings.TrimSpace(os.Getenv("MEDIASTATION_MEDIA_DIR"))
|
||||
mediaContainer := envOrDefault("MEDIASTATION_MEDIA_CONTAINER_DIR", "/media")
|
||||
mediaHost := strings.TrimSpace(os.Getenv("MMTL_MEDIA_DIR"))
|
||||
mediaContainer := envOrDefault("MMTL_MEDIA_CONTAINER_DIR", "/media")
|
||||
var b strings.Builder
|
||||
fmt.Fprintf(&b, "媒体库路径无法解析为可访问目录:%s(已尝试候选:%s)", rawPath, strings.Join(candidates, " | "))
|
||||
if mediaHost == "" {
|
||||
b.WriteString(";未配置 MEDIASTATION_MEDIA_DIR / MEDIASTATION_MEDIA_CONTAINER_DIR。若为 Docker 部署且此库为旧宿主机路径,请设置这两个变量把宿主机路径映射到容器内路径,并确认对应 volume 已挂载。")
|
||||
b.WriteString(";未配置 MMTL_MEDIA_DIR / MMTL_MEDIA_CONTAINER_DIR。若为 Docker 部署且此库为旧宿主机路径,请设置这两个变量把宿主机路径映射到容器内路径,并确认对应 volume 已挂载。")
|
||||
} else {
|
||||
fmt.Fprintf(&b, ";当前映射 %s → %s。请确认该库路径位于此宿主机目录下,或补充对应的 volume 与路径映射。", mediaHost, mediaContainer)
|
||||
}
|
||||
@@ -204,8 +204,8 @@ func dockerVolumePathCandidates(path string) []string {
|
||||
env string
|
||||
container string
|
||||
}{
|
||||
{env: "MEDIASTATION_MEDIA_DIR", container: envOrDefault("MEDIASTATION_MEDIA_CONTAINER_DIR", "/media")},
|
||||
{env: "MEDIASTATION_DOWNLOAD_DIR", container: envOrDefault("MEDIASTATION_DOWNLOAD_CONTAINER_DIR", "/downloads")},
|
||||
{env: "MMTL_MEDIA_DIR", container: envOrDefault("MMTL_MEDIA_CONTAINER_DIR", "/media")},
|
||||
{env: "MMTL_DOWNLOAD_DIR", container: envOrDefault("MMTL_DOWNLOAD_CONTAINER_DIR", "/downloads")},
|
||||
} {
|
||||
container := cleanPathForVolumeMapping(mapping.container)
|
||||
if container == "." || container == "" || strings.HasPrefix(container, ".") {
|
||||
@@ -247,8 +247,8 @@ func dockerVolumePathCandidates(path string) []string {
|
||||
part string
|
||||
container string
|
||||
}{
|
||||
{part: "/media", container: envOrDefault("MEDIASTATION_MEDIA_CONTAINER_DIR", "/media")},
|
||||
{part: "/downloads", container: envOrDefault("MEDIASTATION_DOWNLOAD_CONTAINER_DIR", "/downloads")},
|
||||
{part: "/media", container: envOrDefault("MMTL_MEDIA_CONTAINER_DIR", "/media")},
|
||||
{part: "/downloads", container: envOrDefault("MMTL_DOWNLOAD_CONTAINER_DIR", "/downloads")},
|
||||
} {
|
||||
part := strings.TrimRight(marker.part, "/")
|
||||
container := strings.TrimRight(filepath.ToSlash(marker.container), "/")
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
|
||||
"gorm.io/gorm"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MMTL/internal/model"
|
||||
)
|
||||
|
||||
const maxRecycleBinRecords = 200
|
||||
|
||||
@@ -9,9 +9,9 @@ import (
|
||||
"go.uber.org/zap"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/config"
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MediaStationGo/internal/repository"
|
||||
"github.com/ShukeBta/MMTL/internal/config"
|
||||
"github.com/ShukeBta/MMTL/internal/model"
|
||||
"github.com/ShukeBta/MMTL/internal/repository"
|
||||
)
|
||||
|
||||
func TestListRecycleBinPrunesOldRowsOverLimit(t *testing.T) {
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MMTL/internal/model"
|
||||
)
|
||||
|
||||
func mediaReleaseSortTime(media model.Media) time.Time {
|
||||
|
||||
@@ -3,8 +3,8 @@ package service
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MediaStationGo/internal/repository"
|
||||
"github.com/ShukeBta/MMTL/internal/model"
|
||||
"github.com/ShukeBta/MMTL/internal/repository"
|
||||
)
|
||||
|
||||
// SearchMedia performs a simple LIKE search across titles.
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MMTL/internal/model"
|
||||
)
|
||||
|
||||
type SeriesCard struct {
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MMTL/internal/model"
|
||||
)
|
||||
|
||||
var episodicPathRE = regexp.MustCompile(`(?i)[\\/](?:电视剧|剧集|连续剧|短剧|国产剧|国剧|大陆剧|华语剧|国产电视剧|大陆电视剧|华语电视剧|欧美剧|欧美电视剧|美剧|英剧|日韩剧|日韩电视剧|日剧|韩剧|港剧|台剧|港台剧|泰剧|综艺|纪录片|儿童|动漫|番剧|国漫|日番|韩漫|美漫|欧美动漫|欧美动画|其他动漫|tv|series|shows?|season[\s._-]*\d|s\d{1,2}(?:[\s._-]|[\\/])|special[\s._-]*episodes?|specials?|sp|ovas?|oads?|extras?|bonus(?:es)?|omake|特别篇|特別篇|番外篇?|特典|外传|外傳|总集篇|總集篇)[\\/]`)
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MMTL/internal/model"
|
||||
)
|
||||
|
||||
type mediaSeriesKeyResolver struct {
|
||||
|
||||
@@ -7,9 +7,9 @@ import (
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/config"
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MediaStationGo/internal/repository"
|
||||
"github.com/ShukeBta/MMTL/internal/config"
|
||||
"github.com/ShukeBta/MMTL/internal/model"
|
||||
"github.com/ShukeBta/MMTL/internal/repository"
|
||||
)
|
||||
|
||||
func TestListRecentSeriesCardsCountsAllEpisodesInSeries(t *testing.T) {
|
||||
|
||||
@@ -14,8 +14,8 @@ func TestResolveAccessibleLibraryPathMapsConfiguredHostMediaDir(t *testing.T) {
|
||||
if err := os.MkdirAll(containerLibrary, 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Setenv("MEDIASTATION_MEDIA_DIR", hostRoot)
|
||||
t.Setenv("MEDIASTATION_MEDIA_CONTAINER_DIR", containerRoot)
|
||||
t.Setenv("MMTL_MEDIA_DIR", hostRoot)
|
||||
t.Setenv("MMTL_MEDIA_CONTAINER_DIR", containerRoot)
|
||||
|
||||
got, err := resolveAccessibleLibraryPath(filepath.Join(hostRoot, "电视剧", "国产剧"))
|
||||
if err != nil {
|
||||
@@ -33,8 +33,8 @@ func TestResolveAccessibleLibraryPathMapsWindowsDriveBeforeLinuxAbs(t *testing.T
|
||||
if err := os.MkdirAll(containerLibrary, 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Setenv("MEDIASTATION_MEDIA_DIR", `Q:\media`)
|
||||
t.Setenv("MEDIASTATION_MEDIA_CONTAINER_DIR", containerRoot)
|
||||
t.Setenv("MMTL_MEDIA_DIR", `Q:\media`)
|
||||
t.Setenv("MMTL_MEDIA_CONTAINER_DIR", containerRoot)
|
||||
|
||||
for _, input := range []string{
|
||||
`Q:\media\电视剧\国产剧`,
|
||||
@@ -61,8 +61,8 @@ func TestResolveAccessibleLibraryPathRecoversDockerPollutedWindowsDrive(t *testi
|
||||
if err := os.MkdirAll(containerLibrary, 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Setenv("MEDIASTATION_MEDIA_DIR", `F:\media`)
|
||||
t.Setenv("MEDIASTATION_MEDIA_CONTAINER_DIR", containerRoot)
|
||||
t.Setenv("MMTL_MEDIA_DIR", `F:\media`)
|
||||
t.Setenv("MMTL_MEDIA_CONTAINER_DIR", containerRoot)
|
||||
|
||||
got, err := resolveAccessibleLibraryPath(`/app/F:\media\电视剧\国产剧`)
|
||||
if err != nil {
|
||||
@@ -95,7 +95,7 @@ func TestResolveAccessibleLibraryPathMapsRelativeDockerMediaMarker(t *testing.T)
|
||||
if err := os.MkdirAll(containerLibrary, 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Setenv("MEDIASTATION_MEDIA_CONTAINER_DIR", containerRoot)
|
||||
t.Setenv("MMTL_MEDIA_CONTAINER_DIR", containerRoot)
|
||||
|
||||
got, err := resolveAccessibleLibraryPath(filepath.Join("media", "电视剧", "国产剧"))
|
||||
if err != nil {
|
||||
@@ -116,7 +116,7 @@ func TestResolveAccessibleLibraryPathMapsEmbeddedHostMediaMarker(t *testing.T) {
|
||||
if err := os.MkdirAll(containerLibrary, 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Setenv("MEDIASTATION_MEDIA_CONTAINER_DIR", containerRoot)
|
||||
t.Setenv("MMTL_MEDIA_CONTAINER_DIR", containerRoot)
|
||||
|
||||
got, err := resolveAccessibleLibraryPath("/vol1/1000/Docker/moviepilot-v2/media/电视剧/国产剧")
|
||||
if err != nil {
|
||||
@@ -134,7 +134,7 @@ func TestResolveAccessibleMappedPathMapsEmbeddedHostDownloadMarker(t *testing.T)
|
||||
if err := os.MkdirAll(containerItem, 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Setenv("MEDIASTATION_DOWNLOAD_CONTAINER_DIR", containerDownloads)
|
||||
t.Setenv("MMTL_DOWNLOAD_CONTAINER_DIR", containerDownloads)
|
||||
|
||||
got, _, err := resolveAccessibleMappedPath("/vol1/1000/Docker/qbittorrent/downloads/国产剧")
|
||||
if err != nil {
|
||||
@@ -180,7 +180,7 @@ func TestMappedPathCandidatesMapWindowsDriveDownloadMarker(t *testing.T) {
|
||||
root := t.TempDir()
|
||||
containerDownloads := filepath.Join(root, "container", "downloads")
|
||||
containerLibrary := filepath.Join(containerDownloads, "国产剧")
|
||||
t.Setenv("MEDIASTATION_DOWNLOAD_CONTAINER_DIR", containerDownloads)
|
||||
t.Setenv("MMTL_DOWNLOAD_CONTAINER_DIR", containerDownloads)
|
||||
|
||||
want := filepath.Clean(containerLibrary)
|
||||
for _, got := range mappedPathCandidates(`F:\downloads\国产剧`) {
|
||||
@@ -197,8 +197,8 @@ func TestResolveMappedDestinationPathPrefersConfiguredContainerMapping(t *testin
|
||||
if err := os.MkdirAll(containerMedia, 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Setenv("MEDIASTATION_MEDIA_DIR", `Q:\media`)
|
||||
t.Setenv("MEDIASTATION_MEDIA_CONTAINER_DIR", containerMedia)
|
||||
t.Setenv("MMTL_MEDIA_DIR", `Q:\media`)
|
||||
t.Setenv("MMTL_MEDIA_CONTAINER_DIR", containerMedia)
|
||||
|
||||
for _, input := range []string{`Q:\media`, `Q:/media`, `/app/Q:\media`} {
|
||||
t.Run(input, func(t *testing.T) {
|
||||
@@ -221,7 +221,7 @@ func TestResolveMappedDestinationPathPrefersContainerForRelativeMediaMarker(t *t
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Chdir(workDir)
|
||||
t.Setenv("MEDIASTATION_MEDIA_CONTAINER_DIR", containerMedia)
|
||||
t.Setenv("MMTL_MEDIA_CONTAINER_DIR", containerMedia)
|
||||
|
||||
got := resolveMappedDestinationPath(filepath.Join("media", "电视剧", "国产剧"))
|
||||
want := filepath.Join(containerMedia, "电视剧", "国产剧")
|
||||
@@ -237,8 +237,8 @@ func TestResolveAccessibleMappedPathMapsWindowsDownloadVariants(t *testing.T) {
|
||||
if err := os.MkdirAll(containerSource, 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Setenv("MEDIASTATION_DOWNLOAD_DIR", `Q:\downloads`)
|
||||
t.Setenv("MEDIASTATION_DOWNLOAD_CONTAINER_DIR", containerDownloads)
|
||||
t.Setenv("MMTL_DOWNLOAD_DIR", `Q:\downloads`)
|
||||
t.Setenv("MMTL_DOWNLOAD_CONTAINER_DIR", containerDownloads)
|
||||
|
||||
for _, input := range []string{`Q:\downloads\国产剧`, `Q:/downloads/国产剧`, `/app/Q:\downloads\国产剧`} {
|
||||
t.Run(input, func(t *testing.T) {
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MMTL/internal/model"
|
||||
)
|
||||
|
||||
type MediaItem struct {
|
||||
|
||||
@@ -6,9 +6,9 @@ import (
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/config"
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MediaStationGo/internal/repository"
|
||||
"github.com/ShukeBta/MMTL/internal/config"
|
||||
"github.com/ShukeBta/MMTL/internal/model"
|
||||
"github.com/ShukeBta/MMTL/internal/repository"
|
||||
)
|
||||
|
||||
func TestGroupMediaVersionsMergesEpisodeByExternalIDAcrossLibraries(t *testing.T) {
|
||||
|
||||
@@ -5,9 +5,9 @@ import (
|
||||
"slices"
|
||||
"testing"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/config"
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MediaStationGo/internal/repository"
|
||||
"github.com/ShukeBta/MMTL/internal/config"
|
||||
"github.com/ShukeBta/MMTL/internal/model"
|
||||
"github.com/ShukeBta/MMTL/internal/repository"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
|
||||
@@ -273,7 +273,7 @@ func (p *MetaTubeProvider) applyAuthHeader(req *http.Request, token string) {
|
||||
req.Header.Set("X-Token", token)
|
||||
}
|
||||
req.Header.Set("Accept", "application/json")
|
||||
req.Header.Set("User-Agent", "MediaStationGo/1.0 (MetaTube Client)")
|
||||
req.Header.Set("User-Agent", "MMTL/1.0 (MetaTube Client)")
|
||||
}
|
||||
|
||||
func (p *MetaTubeProvider) convertSearchResultToMatch(query string, res *MetaTubeSearchResult) *Match {
|
||||
|
||||
@@ -22,8 +22,8 @@ import (
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MediaStationGo/internal/repository"
|
||||
"github.com/ShukeBta/MMTL/internal/model"
|
||||
"github.com/ShukeBta/MMTL/internal/repository"
|
||||
)
|
||||
|
||||
// NFOService is the entry point used by the admin "导出 NFO" action.
|
||||
|
||||
@@ -6,13 +6,13 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MMTL/internal/model"
|
||||
)
|
||||
|
||||
func TestWriteMediaNFOUsesMappedDestinationPath(t *testing.T) {
|
||||
root := t.TempDir()
|
||||
t.Setenv("MEDIASTATION_MEDIA_DIR", root)
|
||||
t.Setenv("MEDIASTATION_MEDIA_CONTAINER_DIR", "/media")
|
||||
t.Setenv("MMTL_MEDIA_DIR", root)
|
||||
t.Setenv("MMTL_MEDIA_CONTAINER_DIR", "/media")
|
||||
mediaPath := filepath.Join(root, "电影", "测试电影.mkv")
|
||||
if err := os.MkdirAll(filepath.Dir(mediaPath), 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
|
||||
@@ -8,8 +8,8 @@ import (
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/config"
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MMTL/internal/config"
|
||||
"github.com/ShukeBta/MMTL/internal/model"
|
||||
)
|
||||
|
||||
// TestOrganizeNaming locks in the rename pipeline used by OrganizeDirectory:
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/repository"
|
||||
"github.com/ShukeBta/MMTL/internal/repository"
|
||||
)
|
||||
|
||||
type OrganizeScope string
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MMTL/internal/model"
|
||||
)
|
||||
|
||||
func organizeFatalResultError(res *OrganizeResult) error {
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MMTL/internal/model"
|
||||
)
|
||||
|
||||
func (p *OrganizePipelineService) syncScrapedOrganizedNames(ctx context.Context, opts OrganizeOptions, res *OrganizeResult, path string) {
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MMTL/internal/model"
|
||||
)
|
||||
|
||||
func TestOrganizeScanRootUsesActualOrganizedTarget(t *testing.T) {
|
||||
|
||||
@@ -20,9 +20,9 @@ import (
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/config"
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MediaStationGo/internal/repository"
|
||||
"github.com/ShukeBta/MMTL/internal/config"
|
||||
"github.com/ShukeBta/MMTL/internal/model"
|
||||
"github.com/ShukeBta/MMTL/internal/repository"
|
||||
)
|
||||
|
||||
// OrganizerService moves/renames files into library structures.
|
||||
|
||||
@@ -11,8 +11,8 @@ import (
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/config"
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MMTL/internal/config"
|
||||
"github.com/ShukeBta/MMTL/internal/model"
|
||||
)
|
||||
|
||||
func TestOrganizeDirectoryClassifiesScraperMatchBeforeRename(t *testing.T) {
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MMTL/internal/model"
|
||||
)
|
||||
|
||||
// isSmartClassifyEnabled checks database settings first, then config.yaml.
|
||||
|
||||
@@ -7,8 +7,8 @@ import (
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/config"
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
"github.com/ShukeBta/MMTL/internal/config"
|
||||
"github.com/ShukeBta/MMTL/internal/model"
|
||||
)
|
||||
|
||||
func TestOrganizeDirectoryUsesDownloadCategoryLayout(t *testing.T) {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user