public async Task <bool> CopyToDestination(PLAsset photo, string destPath, IFileSystem fileSystem, DateTime filetime) { try { if (!photo.IsAvailable) { throw new InvalidOperationException("This photo is no longer available."); } var options = new PHAssetResourceRequestOptions { NetworkAccessAllowed = true }; NSError lastError = null; var original = photo.Resources.FirstOrDefault(x => x.ResourceType == PHAssetResourceType.FullSizeVideo || x.ResourceType == PHAssetResourceType.FullSizePhoto || x.ResourceType == PHAssetResourceType.Photo || x.ResourceType == PHAssetResourceType.Video || x.ResourceType == PHAssetResourceType.Audio); if (original == null) { throw new InvalidOperationException("Backup failed for this photo."); } var destTmpFile = destPath + ".temp"; var tcs = new TaskCompletionSource <int>(); long datawritten = 0; PHAssetResourceManager.DefaultManager.RequestData(original, options, data => { var bytes = data.ToArray(); WriteToDest(bytes, datawritten, bytes.Length, destTmpFile, fileSystem).Wait(); datawritten += bytes.Length; }, error => { if (error != null) { tcs.SetException(new InvalidOperationException(lastError.LocalizedDescription)); } tcs.SetResult(0); }); await tcs.Task.ConfigureAwait(false); return(await RenameDestinationFile(fileSystem, destTmpFile, destPath, filetime).ConfigureAwait(false)); } catch (Exception) { return(false); } }
public void WriteArchive(Stream zip) { if (!Photo.IsAvailable) { throw new InvalidOperationException("This photo is no longer available."); } using var archive = new ZipArchive(zip, ZipArchiveMode.Update, true); var options = new PHAssetResourceRequestOptions { NetworkAccessAllowed = true }; var waitables = new List <ManualResetEvent>(Photo.Resources.Count + 1); NSError lastError = null; var original = Photo.Resources.FirstOrDefault(x => x.ResourceType == PHAssetResourceType.FullSizeVideo || x.ResourceType == PHAssetResourceType.FullSizePhoto || x.ResourceType == PHAssetResourceType.Photo || x.ResourceType == PHAssetResourceType.Video || x.ResourceType == PHAssetResourceType.Audio); if (original == null) { throw new InvalidOperationException("Backup failed for this photo."); } var baseName = Path.GetFileNameWithoutExtension(Photo.FileName); var extension = Path.GetExtension(Photo.FileName)?.ToLowerInvariant() ?? string.Empty; foreach (var resource in Photo.Resources) { var entryName = $"{baseName} ({resource.ResourceType:G}){extension}"; var entryStream = archive.CreateEntry(entryName, CompressionLevel.NoCompression).Open(); var waitable = new ManualResetEvent(false); waitables.Add(waitable); PHAssetResourceManager.DefaultManager.RequestData(resource, options, data => { var bytes = data.ToArray(); entryStream.Write(bytes, 0, bytes.Length); }, error => { if (error != null) { lastError = error; } entryStream.Dispose(); waitable.Set(); }); } WaitHandle.WaitAll(waitables.ToArray()); if (lastError != null) { throw new InvalidOperationException(lastError.LocalizedDescription); } // Write meta entry. Photo.BackupDate = DateTime.Now; using var metaStream = archive.CreateEntry("@", CompressionLevel.NoCompression).Open(); using var textStream = new StreamWriter(metaStream, Encoding.UTF8); using var jsonWriter = new JsonTextWriter(textStream) { Indentation = 4, IndentChar = ' ', Formatting = Formatting.Indented }; JsonSerializer.CreateDefault().Serialize(jsonWriter, Photo); zip.Flush(); }
public Task <IEnumerable <MediaAsset> > Query(MediaTypes mediaTypes, DateTimeOffset date) { var tcs = new TaskCompletionSource <IEnumerable <MediaAsset> >(); Task.Run(() => { var filter = "creationDate >= %@ && " + GetFilter(mediaTypes); var fetchOptions = new PHFetchOptions { IncludeHiddenAssets = false, IncludeAllBurstAssets = false, Predicate = NSPredicate.FromFormat(filter, (NSDate)date.LocalDateTime), SortDescriptors = new [] { new NSSortDescriptor("creationDate", false) } }; var fetchAssets = PHAsset .FetchAssets(fetchOptions) .OfType <PHAsset>() .ToArray(); var options = new PHAssetResourceRequestOptions { NetworkAccessAllowed = false }; var imageCache = new PHCachingImageManager(); imageCache.StartCaching( fetchAssets, PHImageManager.MaximumSize, PHImageContentMode.Default, new PHImageRequestOptions { NetworkAccessAllowed = false } ); var assets = new List <MediaAsset>(fetchAssets.Count()); foreach (var asset in fetchAssets) { //result.MediaType //result.Hidden //result.Duration //result.LocalIdentifier //result.Location; //result.ModificationDate //result.PixelHeight; //result.PixelWidth; //result.CreationDate switch (asset.MediaType) { case PHAssetMediaType.Image: imageCache.RequestImageData( asset, new PHImageRequestOptions { }, (data, fn, orientation, dict) => { } ); break; case PHAssetMediaType.Video: imageCache.RequestAvAsset( asset, new PHVideoRequestOptions { NetworkAccessAllowed = false, DeliveryMode = PHVideoRequestOptionsDeliveryMode.HighQualityFormat }, (ass, mix, dict) => { } ); break; case PHAssetMediaType.Audio: break; } } imageCache.StopCaching(); tcs.SetResult(assets); }); return(tcs.Task); }