/Code/Source/Teaching.Wpf.MediaBuddy/Library/MediaIndexer.cs
C# | 98 lines | 75 code | 19 blank | 4 comment | 8 complexity | 23311eda43f602488fbb34793069cd67 MD5 | raw file
- using System;
- using System.Collections.Generic;
- using System.Diagnostics.Contracts;
- using System.IO;
- using System.Linq;
- using System.Threading.Tasks;
- using Teaching.Wpf.MediaBuddy.Io;
- using BufferedStream = Teaching.Wpf.MediaBuddy.Io.BufferedStream;
-
- namespace Teaching.Wpf.MediaBuddy.Library
- {
- public class MediaIndexer
- {
- private const int BufferSize = 4096;
-
- private readonly IEnumerable<IContentTypeDetector> contentTypeDetectors;
- private readonly IEnumerable<IMediaItemContributor> mediaItemContributors;
-
- public async Task<MediaItem> Index(IFileDescription fileDescription)
- {
- Contract.Requires<ArgumentNullException>( fileDescription != null,"fileDescription");
-
- using( var fileData = await fileDescription.OpenAsync())
- {
- var contentType = fileData.ContentType;
-
- foreach( var contentTypeDetector in contentTypeDetectors)
- {
- // LINQ does not yet have overloads that take async lambdas
- var detectedContentType = await contentTypeDetector.DetectContentTypeAsync(fileDescription);
- contentType = detectedContentType ?? contentType;
- }
-
- var hashStream = new HashStream(fileData.Stream);
- var bufferedStream = new BufferedStream(hashStream, 10*1024);
-
- // Perform dummy read
- await ReadFile(bufferedStream);
-
- var hashValue = hashStream.FinishHash();
-
- var fileReference = new MediaFileReference()
- {
- Id = fileDescription.Id,
- ContentType = contentType,
- Extension = Path.GetExtension(fileDescription.Name),
- Hash = hashValue,
- Name = fileDescription.Name
- };
-
- var mediaItem = new MediaItem() { Name = fileDescription.Name};
- mediaItem.Files.Add(fileReference);
-
- foreach( var mediaItemContributor in mediaItemContributors )
- {
- await mediaItemContributor.Contribute(mediaItem, fileDescription, bufferedStream.Clone);
- }
-
- if (contentType != null && WellKnownContentTypes.All.Contains(contentType))
- {
- return mediaItem;
- }
-
- return null;
- }
- }
-
- private async Task<long> ReadFile(Stream stream)
- {
- // We do not actually consume the data, but need to walk the file for hash generation and other similar things.
- // Common hooks can be used to split of data for further processing.
- var buffer = new byte[BufferSize];
- var fullBlockCount = stream.Length/BufferSize;
- var lastBlockSize = stream.Length%BufferSize;
-
- for( long i = 0L;i < fullBlockCount; ++i )
- {
- await stream.ReadAsync(buffer, 0, BufferSize);
- }
-
- if ( lastBlockSize > 0 )
- {
- await stream.ReadAsync(buffer, 0, (int)lastBlockSize);
- }
-
- return stream.Length;
- }
-
- public MediaIndexer(IEnumerable<IContentTypeDetector> contentTypeDetectors,IEnumerable<IMediaItemContributor> mediaItemContributors)
- {
- Contract.Requires<ArgumentNullException>(contentTypeDetectors != null,"contentTypeDetectors");
- Contract.Requires<ArgumentNullException>(mediaItemContributors != null,"mediaItemContributors");
-
- this.contentTypeDetectors = contentTypeDetectors;
- this.mediaItemContributors = mediaItemContributors;
- }
- }
- }