mirror of
https://github.com/truewhile/MeBox.git
synced 2026-10-06 21:36:37 +08:00
refactor: split modules and harden scraping workflows
This commit is contained in:
@@ -0,0 +1,191 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/ShukeBta/MediaStationGo/internal/model"
|
||||
)
|
||||
|
||||
// SystemInfo returns the full Emby identity payload.
|
||||
func (e *EmbyService) SystemInfo() map[string]any {
|
||||
return map[string]any{
|
||||
"Id": embyServerID,
|
||||
"ServerId": embyServerID,
|
||||
"ServerName": "MediaStationGo",
|
||||
"Version": embyCompatVersion,
|
||||
"ServerVersion": embyCompatVersion,
|
||||
"ProductName": "Emby Server",
|
||||
"OperatingSystem": "Windows",
|
||||
"Architecture": "X64",
|
||||
"LocalAddress": "",
|
||||
"WanAddress": "",
|
||||
"HasPendingRestart": false,
|
||||
"IsShuttingDown": false,
|
||||
"SupportsLibraryMonitor": true,
|
||||
"SupportsHttps": false,
|
||||
"SupportsAutoDiscovery": true,
|
||||
"HttpServerPortNumber": e.cfg.App.Port,
|
||||
"HttpsPortNumber": 0,
|
||||
"PublishedServerUrl": "",
|
||||
"WebSocketPortNumber": e.cfg.App.Port,
|
||||
"CompletedInstallations": []any{},
|
||||
"CanSelfRestart": false,
|
||||
"CanLaunchWebBrowser": false,
|
||||
"CanRestart": false,
|
||||
}
|
||||
}
|
||||
|
||||
// SystemInfoPublic 是不需要认证的精简版(Emby Web 客户端登陆前会拉)。
|
||||
func (e *EmbyService) SystemInfoPublic() map[string]any {
|
||||
return map[string]any{
|
||||
"Id": embyServerID,
|
||||
"ServerId": embyServerID,
|
||||
"ServerName": "MediaStationGo",
|
||||
"Version": embyCompatVersion,
|
||||
"ServerVersion": embyCompatVersion,
|
||||
"ProductName": "Emby Server",
|
||||
"OperatingSystem": "Windows",
|
||||
"LocalAddress": "",
|
||||
"WanAddress": "",
|
||||
"HttpServerPortNumber": e.cfg.App.Port,
|
||||
"HttpsPortNumber": 0,
|
||||
"SupportsHttps": false,
|
||||
"SupportsAutoDiscovery": true,
|
||||
"StartupWizardCompleted": true,
|
||||
}
|
||||
}
|
||||
|
||||
// ListUsers returns Emby-shaped users.
|
||||
func (e *EmbyService) ListUsers(ctx context.Context) ([]map[string]any, error) {
|
||||
users, err := e.repo.User.List(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out := make([]map[string]any, 0, len(users))
|
||||
for _, u := range users {
|
||||
out = append(out, e.userPayload(&u))
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// FindUser 用 ID 查用户,用于 /Users/Me 与 /Users/{id}。
|
||||
func (e *EmbyService) FindUser(ctx context.Context, id string) (map[string]any, error) {
|
||||
u, err := e.repo.User.FindByID(ctx, id)
|
||||
if err != nil || u == nil {
|
||||
return nil, err
|
||||
}
|
||||
return e.userPayload(u), nil
|
||||
}
|
||||
|
||||
func (e *EmbyService) userPayload(u *model.User) map[string]any {
|
||||
canDownload := u.Role == "admin"
|
||||
return map[string]any{
|
||||
"Id": u.ID,
|
||||
"Name": u.Username,
|
||||
"ServerId": embyServerID,
|
||||
"ServerName": "MediaStationGo",
|
||||
"HasPassword": true,
|
||||
"HasConfiguredPassword": true,
|
||||
"HasConfiguredEasyPassword": false,
|
||||
"EnableAutoLogin": false,
|
||||
"LastLoginDate": u.LastLoginAt,
|
||||
"LastActivityDate": u.UpdatedAt,
|
||||
"Configuration": map[string]any{
|
||||
"PlayDefaultAudioTrack": true,
|
||||
"DisplayCollectionsView": true,
|
||||
"DisplayMissingEpisodes": false,
|
||||
"SubtitleMode": "Default",
|
||||
"EnableNextEpisodeAutoPlay": true,
|
||||
"AudioLanguagePreference": "",
|
||||
"SubtitleLanguagePreference": "",
|
||||
},
|
||||
"Policy": map[string]any{
|
||||
"IsAdministrator": u.Role == "admin",
|
||||
"IsHidden": false,
|
||||
"IsDisabled": !u.IsActive,
|
||||
"EnableUserPreferenceAccess": true,
|
||||
"EnableRemoteAccess": true,
|
||||
"EnableMediaPlayback": true,
|
||||
"EnableAudioPlaybackTranscoding": true,
|
||||
"EnableVideoPlaybackTranscoding": true,
|
||||
"EnablePlaybackRemuxing": true,
|
||||
"EnableLiveTvAccess": false,
|
||||
"EnableContentDownloading": canDownload,
|
||||
"EnableSyncTranscoding": canDownload,
|
||||
"EnableMediaConversion": canDownload,
|
||||
"EnableAllChannels": true,
|
||||
"EnableAllFolders": true,
|
||||
"EnableAllDevices": true,
|
||||
"AuthenticationProviderId": embyLocalAuthenticationProviderID,
|
||||
"PasswordResetProviderId": embyLocalPasswordResetProviderID,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Views 返回 Emby 中"虚拟根目录"——每个 library 一个条目。
|
||||
func (e *EmbyService) Views(ctx context.Context, userID string) (map[string]any, error) {
|
||||
libs, err := e.repo.Library.List(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
libs = FilterDisplayCloudLibraries(ctx, e.repo, libs)
|
||||
visibility := e.mediaVisibility(ctx, userID)
|
||||
items := make([]map[string]any, 0, len(libs))
|
||||
for _, l := range libs {
|
||||
if !e.libraryVisibleFromCachedVisibility(l, visibility) {
|
||||
continue
|
||||
}
|
||||
items = append(items, e.libraryAsView(&l))
|
||||
}
|
||||
return map[string]any{"Items": items, "TotalRecordCount": len(items), "StartIndex": 0}, nil
|
||||
}
|
||||
|
||||
func (e *EmbyService) libraryAsView(l *model.Library) map[string]any {
|
||||
collectionType := "movies"
|
||||
switch l.Type {
|
||||
case "tv":
|
||||
collectionType = "tvshows"
|
||||
case "anime":
|
||||
collectionType = "tvshows" // Emby 没有专门的 anime CollectionType
|
||||
case "variety":
|
||||
collectionType = "tvshows"
|
||||
case "music":
|
||||
collectionType = "music"
|
||||
}
|
||||
return map[string]any{
|
||||
"Id": l.ID,
|
||||
"Name": l.Name,
|
||||
"CollectionType": collectionType,
|
||||
"ServerId": embyServerID,
|
||||
"Type": "CollectionFolder",
|
||||
"IsFolder": true,
|
||||
"Path": l.Path,
|
||||
"SortName": strings.ToLower(l.Name),
|
||||
"DateCreated": l.CreatedAt.UTC().Format(time.RFC3339),
|
||||
"CanDelete": false,
|
||||
"CanDownload": false,
|
||||
"DisplayPreferencesId": l.ID,
|
||||
"PrimaryImageItemId": l.ID,
|
||||
"PrimaryImageAspectRatio": 1.7777777777777777,
|
||||
"RecursiveItemCount": 0,
|
||||
"ChildCount": 0,
|
||||
"SpecialFeatureCount": 0,
|
||||
"EnableMediaSourceDisplay": true,
|
||||
"PlayAccess": "Full",
|
||||
"ExternalUrls": []any{},
|
||||
"ProviderIds": map[string]string{},
|
||||
"Genres": []string{},
|
||||
"Tags": []string{},
|
||||
"ImageTags": map[string]string{},
|
||||
"BackdropImageTags": []string{},
|
||||
"UserData": map[string]any{
|
||||
"PlaybackPositionTicks": 0,
|
||||
"PlayCount": 0,
|
||||
"IsFavorite": false,
|
||||
"Played": false,
|
||||
"UnplayedItemCount": 0,
|
||||
},
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user