package subsonic import ( "database/sql" "strconv" "git.noroutes.net/NoRoutes/vibetunes/internal/database" ) // folderMap resolves between VibeSonic's opaque music-folder IDs and the // small sequential integers the Subsonic protocol expects for // musicFolderId (the official XSD types it as xs:int, and some clients // build folder-picker UIs assuming small integers). The mapping is // derived fresh per request from folder creation order, which is stable // as long as folders aren't deleted/recreated — acceptable for how // rarely music folders change. type folderMap struct { folders []*database.MusicFolder toInt map[string]int toFolder map[int]*database.MusicFolder } func loadFolderMap(db *sql.DB) (*folderMap, error) { folders, err := database.ListMusicFolders(db) if err != nil { return nil, err } fm := &folderMap{ folders: folders, toInt: make(map[string]int, len(folders)), toFolder: make(map[int]*database.MusicFolder, len(folders)), } for i, f := range folders { id := i + 1 fm.toInt[f.ID] = id fm.toFolder[id] = f } return fm, nil } func (fm *folderMap) IntID(folderID string) string { return strconv.Itoa(fm.toInt[folderID]) } func (fm *folderMap) ByIntID(s string) *database.MusicFolder { n, err := strconv.Atoi(s) if err != nil { return nil } return fm.toFolder[n] } // Allowed returns the folders a user may see: every folder, unless the // user has an explicit restriction list configured. func (fm *folderMap) Allowed(db *sql.DB, user *database.User) ([]*database.MusicFolder, error) { allowedIDs, err := database.AllowedMusicFolderIDs(db, user.ID) if err != nil { return nil, err } if len(allowedIDs) == 0 { return fm.folders, nil } set := make(map[string]bool, len(allowedIDs)) for _, id := range allowedIDs { set[id] = true } var out []*database.MusicFolder for _, f := range fm.folders { if set[f.ID] { out = append(out, f) } } return out, nil } // UserCanSeeFolder reports whether user is allowed to see folderID, // given their restriction list (empty = unrestricted). func UserCanSeeFolder(db *sql.DB, user *database.User, folderID string) (bool, error) { allowedIDs, err := database.AllowedMusicFolderIDs(db, user.ID) if err != nil { return false, err } if len(allowedIDs) == 0 { return true, nil } for _, id := range allowedIDs { if id == folderID { return true, nil } } return false, nil } // UserCanSeeMediaFile reports whether user is allowed to see a song // belonging to the given music folder (per their folder restriction). func UserCanSeeMediaFile(db *sql.DB, user *database.User, mediaFile *database.MediaFile) (bool, error) { return UserCanSeeFolder(db, user, mediaFile.MusicFolderID) }