public async Task DetectAllTracksAsync(string albumName, CancellationToken cancelToken = default) { Guard.NotEmpty(albumName, nameof(albumName)); // Get album info... var albumInfo = _albumRegistry.GetAlbumByName(albumName); if (albumInfo == null) { throw new InvalidOperationException(T("Admin.Media.Exception.AlbumNonexistent", albumName)); } if (!albumInfo.HasTrackDetector) { throw new InvalidOperationException(T("Admin.Media.Exception.AlbumNoTrack", albumName)); } // Load corresponding track detectors for current album... var trackDetectors = albumInfo .TrackDetectorTypes .Select(x => _trackDetectorFactory[x]) .ToArray(); var isInstallation = !EngineContext.Current.Application.IsInstalled; if (!isInstallation) { // First delete all tracks for current album... await DeleteAllTracksAsync(albumName); } IAsyncEnumerable <MediaTrack> allTracks = null; for (int i = 0; i < trackDetectors.Length; i++) { // >>>>> DO detection (potentially a long process)... var tracks = trackDetectors[i].DetectAllTracksAsync(albumName, cancelToken); if (i == 0) { allTracks = tracks; } else if (allTracks != null) { // Must be this way to prevent namespace collision with EF. allTracks = Dasync.Collections.IAsyncEnumerableExtensions.Concat(allTracks, tracks); } } // (perf) Batch result data... await foreach (var batch in allTracks.SliceAsync(500)) { cancelToken.ThrowIfCancellationRequested(); // process the batch await TrackManyCoreAsync(batch, albumName); } }
public TreeNode <MediaFolderNode> GetRootNode() { var cacheKey = FolderTreeKey; var root = _cache.Get(cacheKey, () => { var query = from x in _folderRepo.TableUntracked orderby x.ParentId, x.Name select x; var unsortedNodes = query.ToList().Select(x => { var item = new MediaFolderNode { Id = x.Id, Name = x.Name, ParentId = x.ParentId, CanDetectTracks = x.CanDetectTracks, FilesCount = x.FilesCount, Slug = x.Slug }; if (x is MediaAlbum album) { item.IsAlbum = true; item.AlbumName = album.Name; item.Path = album.Name; item.ResKey = album.ResKey; item.IncludePath = album.IncludePath; item.Order = album.Order ?? 0; var albumInfo = _albumRegistry.GetAlbumByName(album.Name); if (albumInfo != null) { var displayHint = albumInfo.DisplayHint; item.Color = displayHint.Color; item.OverlayColor = displayHint.OverlayColor; item.OverlayIcon = displayHint.OverlayIcon; } } return(item); }); var nodeMap = unsortedNodes.ToMultimap(x => x.ParentId ?? 0, x => x); var rootNode = new TreeNode <MediaFolderNode>(new MediaFolderNode { Name = "Root", Id = 0 }); AddChildTreeNodes(rootNode, 0, nodeMap); return(rootNode); }, FolderTreeCacheDuration); return(root);
public virtual MediaFile InsertPicture( byte[] pictureBinary, string mimeType, string fileName, int width, int height, bool isTransient = true, string album = null) { var mime = mimeType.EmptyNull().Truncate(100); var name = NormalizeFileName(fileName, ref mime, out string ext); var file = new MediaFile { MimeType = mime, Extension = ext, Name = name, IsTransient = isTransient }; file.MediaType = _mediaTypeResolver.Resolve(file); if (album.HasValue()) { var albumId = _albumRegistry.GetAlbumByName(album)?.Id; if (albumId > 0) { file.FolderId = albumId; } } var stream = pictureBinary?.ToStream(); file.RefreshMetadata(stream); _pictureRepository.Insert(file); // Save to storage. _storageProvider.Value.Save(file, stream); return(file); }
public RoxyFileManagerController( IMediaService mediaService, IFolderService folderService, IAlbumRegistry albumRegistry, IMediaTypeResolver mediaTypeResolver, MediaHelper mediaHelper, MediaExceptionFactory exceptionFactory, //IMediaFileSystem fileSystem, ILocalizationFileResolver locFileResolver) { _mediaTypeResolver = mediaTypeResolver; _mediaHelper = mediaHelper; _locFileResolver = locFileResolver; _album = albumRegistry.GetAlbumByName(SystemAlbumProvider.Files); _fileSystem = new MediaServiceFileSystemAdapter(mediaService, folderService, _mediaHelper, exceptionFactory); _fileRoot = _album.Name; //_fileSystem = fileSystem; //_fileRoot = "Uploaded"; }
public void DetectAllTracks(string albumName, bool isMigration = false) { Guard.NotEmpty(albumName, nameof(albumName)); // Get album info... var albumInfo = _albumRegistry.GetAlbumByName(albumName); if (albumInfo == null) { throw new InvalidOperationException(T("Admin.Media.Exception.AlbumNonexistent", albumName)); } // load corresponding detector provider for current album... var provider = _albumProviderFactory[albumInfo.ProviderType] as IMediaTrackDetector; if (provider == null) { throw new InvalidOperationException(T("Admin.Media.Exception.AlbumNoTrack", albumName)); } if (!isMigration) { // first delete all tracks for current album... DeleteAllTracks(albumName); } // >>>>> DO detection (potentially a very long process)... var tracks = provider.DetectAllTracks(albumName); // (perf) batch result data... foreach (var batch in tracks.Slice(500)) { // process the batch TrackManyCore(batch, albumName, isMigration); } }
protected virtual void TrackManyCore(IEnumerable <MediaTrackAction> actions, string albumName, bool isMigration) { Guard.NotNull(actions, nameof(actions)); if (!actions.Any()) { return; } var ctx = _dbContext; using (var scope = new DbContextScope(ctx, validateOnSave: false, hooksEnabled: false, autoDetectChanges: false)) { // Get the id for an album (necessary later to set FolderId)... int?albumId = albumName.HasValue() ? _albumRegistry.GetAlbumByName(albumName)?.Id : null; // Get distinct ids of all detected files... var mediaFileIds = actions.Select(x => x.MediaFileId).Distinct().ToArray(); // fetch these files from database... var query = ctx.Set <MediaFile>().Include(x => x.Tracks).Where(x => mediaFileIds.Contains(x.Id)); if (isMigration) { query = query.Where(x => x.Version == 1); } var files = query.ToDictionary(x => x.Id); // for each media file relation to an entity... foreach (var action in actions) { // fetch the file from local dictionary by its id... if (files.TryGetValue(action.MediaFileId, out var file)) { if (isMigration) { // set album id as folder id (during initial migration there are no sub-folders) file.FolderId = albumId; // remember that we processed tracks for this file already file.Version = 2; } var track = action.ToTrack(); if (albumName.HasValue() && track.Album.IsEmpty()) { // Overwrite track album if scope album was passed. track.Album = albumName; } // add or remove the track from file if (action.Operation == MediaTrackOperation.Track) { file.Tracks.Add(track); } else { var dbTrack = file.Tracks.FirstOrDefault(x => x == track); if (dbTrack != null) { file.Tracks.Remove(track); _dbContext.ChangeState(dbTrack, System.Data.Entity.EntityState.Deleted); } } if (file.Tracks.Count > 0) { // A file with tracks can NEVER be transient file.IsTransient = false; } else if (_makeFilesTransientWhenOrphaned) { // But an untracked file can OPTIONALLY be transient file.IsTransient = true; } } } // Save whole batch to database int num = ctx.SaveChanges(); // Breathe ctx.DetachEntities <MediaFile>(deep: true); } }
public int GetAlbumIdByName(string albumName) { Guard.NotEmpty(albumName, nameof(albumName)); return(_albumRegistry.GetAlbumByName(albumName)?.Id ?? 0); }