Storage Library Permissions#
Screenbox accesses the Windows MusicLibrary and VideosLibrary KnownFolders at startup and re-checks access whenever the coordinator re-initializes watchers. Because UWP apps require explicit user consent for these folders, the codebase has a structured flow for requesting access, detecting denial, and surfacing a user-facing error notification.
Key Components#
| Component | Role |
|---|---|
LibraryCoordinator | Stateful singleton; owns watchers/timers, calls KnownFolders.RequestAccessAsync |
LibraryService | Stateless service; initializes StorageLibrary objects, creates file queries, fetches and caches media |
MainPageViewModel | Calls FetchLibraries() at startup; catches UnauthorizedAccessException and sends notification messages |
NotificationViewModel | Receives RaiseLibraryAccessDeniedNotificationMessage; shows error notification with deep-link to OS privacy settings |
RaiseLibraryAccessDeniedNotificationMessage | Simple message DTO carrying the denied KnownLibraryId |
All of these are registered in ServiceHelpers.PopulateCoreServices β ILibraryCoordinator and ILibraryService as singletons, and LibraryContext as a singleton shared state container.
Startup Sequence#
On app launch, App.OnLaunched fires StartupInitAsync() (database initialization only), and then the UI layer calls MainPageViewModel.FetchLibraries(). The sequence inside FetchLibraries is:
EnsureWatchingAsync()β called first; wrapped in its owntry/catchso a failure here does not block library fetching .- Concurrent fetch β
FetchMusicLibraryAsync(),FetchVideosLibraryAsync(), andFetchPlaylistsAsync()run in parallel viaTask.WhenAll. - Second playlist fetch β after libraries complete, playlists are re-fetched so playlist items can reference the now-loaded library media .
Permission Check in LibraryCoordinator#
EnsureWatchingMusicAsync and EnsureWatchingVideosAsync each:
- Lazily initialize the
StorageLibraryviaLibraryService.InitializeMusicLibraryAsync()/InitializeVideosLibraryAsync(), which callStorageLibrary.GetLibraryAsyncand enable theChangeTracker. - Call
KnownFolders.RequestAccessAsync(KnownFolderId.MusicLibrary)/KnownFolderId.VideosLibrary. - Only create and register the
StorageFileQueryResultwatcher if the result isAllowedorAllowedPerAppFolder. If access is denied, no query watcher is created andFetchMusicAsync/FetchVideosAsyncwill be no-ops (they guard on_musicQuery is null) .
On Xbox, removable storage access (KnownFolderId.RemovableDevices) follows the same RequestAccessAsync pattern inside FetchMusicAsync/FetchVideosAsync .
Unauthorized Access Error Handling#
FetchMusicLibraryAsync and FetchVideosLibraryAsync in MainPageViewModel each wrap the coordinator fetch call in a specific handler :
catch (UnauthorizedAccessException)
{
Messenger.Send(new RaiseLibraryAccessDeniedNotificationMessage(KnownLibraryId.Music /* or Videos */));
}
The same pattern appears in SettingsPageViewModel for library refreshes triggered from the settings page.
NotificationViewModel.Receive(RaiseLibraryAccessDeniedNotificationMessage) handles the message :
- Selects a localized title (
AccessDeniedMusicLibraryTitle/AccessDeniedVideosLibraryTitle). - Sets the deep-link URI to
ms-settings:privacy-musiclibraryorms-settings:privacy-videos. - Displays an error-level notification with an "Open Privacy Settings" action button that launches the URI.
- Auto-dismisses after 15 seconds .
Note:
KnownLibraryId.Documentsaccess denial is silently ignored βReceivereturns early without showing a notification .
Change Tracking & Cache Invalidation#
LibraryService uses StorageLibrary.ChangeTracker to avoid full re-scans on subsequent launches. The cache (SQLite via IDatabaseService) stores folder paths alongside media records; if the library's folder set changes, the cache is invalidated and a full scan runs . Content changes (file added, removed, renamed) are reconciled incrementally via TryResolveLibraryBatchChangeAsync.
Watcher ContentsChanged events from StorageFileQueryResult are debounced at 1 second before triggering a re-fetch .