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, }, } }