From 5b8e02a04b13abeaff1f3bac15c375512e060146 Mon Sep 17 00:00:00 2001
From: Tsanie Lily <tsorgy@gmail.com>
Date: Thu, 21 May 2020 08:43:34 +0800
Subject: [PATCH] optimize logs, users/related always refresh

---
 Pixiview.Android/Pixiview.Android.csproj      |   6 +-
 .../Properties/AndroidManifest.xml            |   2 +-
 Pixiview.iOS.OpenExtension/Info.plist         |   4 +-
 Pixiview.iOS/AppDelegate.cs                   |   4 +-
 Pixiview.iOS/Info.plist                       |   4 +-
 Pixiview.iOS/Pixiview.iOS.csproj              |   6 +-
 Pixiview/App.cs                               |  20 ++-
 Pixiview/AppShell.xaml.cs                     |   2 +-
 Pixiview/Illust/FavoritesPage.xaml.cs         |   8 +-
 Pixiview/Illust/IllustCollectionPage.cs       |   2 +-
 Pixiview/Illust/RelatedIllustsPage.xaml.cs    |   2 +-
 Pixiview/Illust/ViewIllustPage.xaml.cs        |   6 +-
 Pixiview/OptionPage.xaml.cs                   |  10 +-
 Pixiview/UI/AdaptedPage.cs                    |   2 +-
 Pixiview/Utils/EnvironmentService.cs          |   2 +-
 Pixiview/Utils/Extensions.cs                  |  43 ++++--
 Pixiview/Utils/Stores.cs                      |  19 ++-
 Pixiview/Utils/Ugoira.cs                      | 138 ++++++++++--------
 18 files changed, 164 insertions(+), 116 deletions(-)

diff --git a/Pixiview.Android/Pixiview.Android.csproj b/Pixiview.Android/Pixiview.Android.csproj
index bfc83d9..3799741 100644
--- a/Pixiview.Android/Pixiview.Android.csproj
+++ b/Pixiview.Android/Pixiview.Android.csproj
@@ -28,15 +28,19 @@
     <DebugType>portable</DebugType>
     <Optimize>false</Optimize>
     <OutputPath>bin\Debug</OutputPath>
-    <DefineConstants>DEBUG;</DefineConstants>
+    <DefineConstants>DEBUG;LOG</DefineConstants>
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
     <AndroidLinkMode>None</AndroidLinkMode>
+    <ConsolePause>true</ConsolePause>
+    <EmbedAssembliesIntoApk></EmbedAssembliesIntoApk>
+    <AndroidSupportedAbis>arm64-v8a;armeabi-v7a;x86;x86_64</AndroidSupportedAbis>
   </PropertyGroup>
   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
     <DebugType></DebugType>
     <Optimize>true</Optimize>
     <OutputPath>bin\Release</OutputPath>
+    <DefineConstants>LOG</DefineConstants>
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
     <AndroidManagedSymbols>true</AndroidManagedSymbols>
diff --git a/Pixiview.Android/Properties/AndroidManifest.xml b/Pixiview.Android/Properties/AndroidManifest.xml
index 1092bec..d850bfa 100644
--- a/Pixiview.Android/Properties/AndroidManifest.xml
+++ b/Pixiview.Android/Properties/AndroidManifest.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="1.0.519" package="org.tsanie.pixiview" android:versionCode="8">
+<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="1.0.520" package="org.tsanie.pixiview" android:versionCode="9">
 	<uses-sdk android:minSdkVersion="25" android:targetSdkVersion="28" />
 	<application android:label="Pixiview" android:icon="@mipmap/icon" android:roundIcon="@mipmap/icon_round"></application>
 	<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
diff --git a/Pixiview.iOS.OpenExtension/Info.plist b/Pixiview.iOS.OpenExtension/Info.plist
index 68abcd0..6b3226c 100644
--- a/Pixiview.iOS.OpenExtension/Info.plist
+++ b/Pixiview.iOS.OpenExtension/Info.plist
@@ -29,8 +29,8 @@
 		<string>com.apple.share-services</string>
 	</dict>
 	<key>CFBundleShortVersionString</key>
-	<string>1.0.519</string>
+	<string>1.0.520</string>
 	<key>CFBundleVersion</key>
-	<string>8</string>
+	<string>9</string>
 </dict>
 </plist>
diff --git a/Pixiview.iOS/AppDelegate.cs b/Pixiview.iOS/AppDelegate.cs
index 455b65e..3e6edd1 100644
--- a/Pixiview.iOS/AppDelegate.cs
+++ b/Pixiview.iOS/AppDelegate.cs
@@ -26,8 +26,8 @@ namespace Pixiview.iOS
 
         public override bool OpenUrl(UIApplication app, NSUrl url, NSDictionary options)
         {
-#if DEBUG
-            App.DebugPrint($"url: {url}.");
+#if LOG
+            App.DebugPrint($"open url: {url}.");
 #endif
             return App.OpenUrl(url);
         }
diff --git a/Pixiview.iOS/Info.plist b/Pixiview.iOS/Info.plist
index 0c9e7bd..42b1a82 100644
--- a/Pixiview.iOS/Info.plist
+++ b/Pixiview.iOS/Info.plist
@@ -79,8 +79,8 @@
 		</dict>
 	</array>
 	<key>CFBundleShortVersionString</key>
-	<string>1.0.519</string>
+	<string>1.0.520</string>
 	<key>CFBundleVersion</key>
-	<string>8</string>
+	<string>9</string>
 </dict>
 </plist>
diff --git a/Pixiview.iOS/Pixiview.iOS.csproj b/Pixiview.iOS/Pixiview.iOS.csproj
index dc3adb2..cbb3272 100644
--- a/Pixiview.iOS/Pixiview.iOS.csproj
+++ b/Pixiview.iOS/Pixiview.iOS.csproj
@@ -21,7 +21,7 @@
     <DebugType>full</DebugType>
     <Optimize>false</Optimize>
     <OutputPath>bin\iPhoneSimulator\Debug</OutputPath>
-    <DefineConstants>DEBUG</DefineConstants>
+    <DefineConstants>DEBUG;LOG</DefineConstants>
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
     <MtouchArch>x86_64</MtouchArch>
@@ -32,6 +32,7 @@
     <DebugType>none</DebugType>
     <Optimize>true</Optimize>
     <OutputPath>bin\iPhoneSimulator\Release</OutputPath>
+    <DefineConstants>LOG</DefineConstants>
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
     <MtouchLink>None</MtouchLink>
@@ -42,7 +43,7 @@
     <DebugType>full</DebugType>
     <Optimize>false</Optimize>
     <OutputPath>bin\iPhone\Debug</OutputPath>
-    <DefineConstants>DEBUG</DefineConstants>
+    <DefineConstants>DEBUG;LOG</DefineConstants>
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
     <MtouchArch>ARM64</MtouchArch>
@@ -56,6 +57,7 @@
     <DebugType>none</DebugType>
     <Optimize>true</Optimize>
     <OutputPath>bin\iPhone\Release</OutputPath>
+    <DefineConstants>LOG</DefineConstants>
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
     <MtouchArch>ARM64</MtouchArch>
diff --git a/Pixiview/App.cs b/Pixiview/App.cs
index 614dee7..dd4a760 100644
--- a/Pixiview/App.cs
+++ b/Pixiview/App.cs
@@ -1,5 +1,7 @@
 using System;
+#if DEBUG
 using System.Diagnostics;
+#endif
 using System.IO;
 using System.Linq;
 using System.Text.RegularExpressions;
@@ -44,7 +46,7 @@ namespace Pixiview
                 if (!string.IsNullOrEmpty(host) && port > 0)
                 {
                     Configs.Proxy = new System.Net.WebProxy(host, port);
-#if DEBUG
+#if LOG
                     DebugPrint($"load proxy: {host}:{port}");
 #endif
                 }
@@ -76,7 +78,7 @@ namespace Pixiview
             {
                 return;
             }
-#if DEBUG
+#if LOG
             DebugPrint($"application theme: {theme}");
 #endif
             ThemeBase themeInstance;
@@ -117,17 +119,25 @@ namespace Pixiview
             var theme = AppInfo.RequestedTheme;
             SetTheme(theme);
         }
-
+#if DEBUG
         public static void DebugPrint(string message)
         {
             Debug.WriteLine("[{0:HH:mm:ss.ffff}] - {1}", DateTime.Now, message);
         }
-
         public static void DebugError(string category, string message)
         {
             Debug.Fail(string.Format("[{0:HH:mm:ss.ffff}] - {1} - {2}", DateTime.Now, category, message));
         }
-
+#else
+        public static void DebugPrint(string message)
+        {
+            Console.WriteLine("[Debug.Print] - {0}", message);
+        }
+        public static void DebugError(string category, string message)
+        {
+            Console.Error.WriteLine(string.Format("[Debug.Error] - {0} - {1}", category, message));
+        }
+#endif
         public static bool OpenUrl(Uri uri)
         {
             var current = Current.MainPage;
diff --git a/Pixiview/AppShell.xaml.cs b/Pixiview/AppShell.xaml.cs
index cd5e428..309a5e7 100644
--- a/Pixiview/AppShell.xaml.cs
+++ b/Pixiview/AppShell.xaml.cs
@@ -57,7 +57,7 @@ namespace Pixiview
             BindingContext = this;
             InitializeComponent();
 
-#if DEBUG
+#if LOG
             App.DebugPrint($"folder: {Stores.PersonalFolder}");
             App.DebugPrint($"cache: {Stores.CacheFolder}");
 #endif
diff --git a/Pixiview/Illust/FavoritesPage.xaml.cs b/Pixiview/Illust/FavoritesPage.xaml.cs
index 429635c..6a15402 100644
--- a/Pixiview/Illust/FavoritesPage.xaml.cs
+++ b/Pixiview/Illust/FavoritesPage.xaml.cs
@@ -280,7 +280,7 @@ namespace Pixiview.Illust
                         if (bookmarkId != null)
                         {
                             // not exists in remote any more
-#if DEBUG
+#if LOG
                             App.DebugPrint($"remove bookmark ({bookmarkId}) - {b.Id}: {b.Title}");
 #endif
                             nows.RemoveAt(i);
@@ -289,7 +289,7 @@ namespace Pixiview.Illust
                     else if (bookmarkId != bookmark.BookmarkId)
                     {
                         // update bookmark id
-#if DEBUG
+#if LOG
                         App.DebugPrint($"change bookmark ({bookmarkId}) to ({bookmark.BookmarkId}) - {b.Id}: {b.Title}");
 #endif
                         b.BookmarkId = bookmark.BookmarkId;
@@ -303,7 +303,7 @@ namespace Pixiview.Illust
                     for (var i = 0; i < list.Length; i++)
                     {
                         var item = list[i];
-#if DEBUG
+#if LOG
                         App.DebugPrint($"add bookmark ({item.BookmarkId}) - {item.Id}: {item.Title}");
 #endif
                         item.Image = StyleDefinition.DownloadBackground;
@@ -316,7 +316,7 @@ namespace Pixiview.Illust
                 return;
             }
 
-            ParallelTask.Start(0, list.Length, Configs.MaxPageThreads, i =>
+            ParallelTask.Start("favorite.loadimages", 0, list.Length, Configs.MaxPageThreads, i =>
             {
                 var illustItem = list[i];
                 var data = Stores.LoadIllustPreloadData(illustItem.Id);
diff --git a/Pixiview/Illust/IllustCollectionPage.cs b/Pixiview/Illust/IllustCollectionPage.cs
index 21c04ab..ac8332c 100644
--- a/Pixiview/Illust/IllustCollectionPage.cs
+++ b/Pixiview/Illust/IllustCollectionPage.cs
@@ -595,7 +595,7 @@ namespace Pixiview.Illust
                 task.Dispose();
                 task = null;
             }
-            task = ParallelTask.Start(0, collection.Count, Configs.MaxThreads, i =>
+            task = ParallelTask.Start("collection.load", 0, collection.Count, Configs.MaxThreads, i =>
             {
                 if (!collection.Running)
                 {
diff --git a/Pixiview/Illust/RelatedIllustsPage.xaml.cs b/Pixiview/Illust/RelatedIllustsPage.xaml.cs
index 815e4ce..c9e4c8a 100644
--- a/Pixiview/Illust/RelatedIllustsPage.xaml.cs
+++ b/Pixiview/Illust/RelatedIllustsPage.xaml.cs
@@ -45,7 +45,7 @@ namespace Pixiview.Illust
             if (startIndex < 0)
             {
                 // init
-                data = Stores.LoadIllustRecommendsInitData(illustItem.Id, force);
+                data = Stores.LoadIllustRecommendsInitData(illustItem.Id);
                 if (data == null || data.body == null)
                 {
                     return null;
diff --git a/Pixiview/Illust/ViewIllustPage.xaml.cs b/Pixiview/Illust/ViewIllustPage.xaml.cs
index 4bab17d..8c19cdb 100644
--- a/Pixiview/Illust/ViewIllustPage.xaml.cs
+++ b/Pixiview/Illust/ViewIllustPage.xaml.cs
@@ -400,7 +400,7 @@ namespace Pixiview.Illust
                 task.Dispose();
                 task = null;
             }
-            task = ParallelTask.Start(0, items.Length, Configs.MaxPageThreads, i =>
+            task = ParallelTask.Start("view.illusts", 0, items.Length, Configs.MaxPageThreads, i =>
             {
                 DoLoadImage(i);
                 return true;
@@ -545,6 +545,10 @@ namespace Pixiview.Illust
             {
                 return;
             }
+            if (Configs.Cookie == null)
+            {
+                return;
+            }
             if (!add && string.IsNullOrEmpty(bookmarkId))
             {
                 return;
diff --git a/Pixiview/OptionPage.xaml.cs b/Pixiview/OptionPage.xaml.cs
index 127baf3..cdac905 100644
--- a/Pixiview/OptionPage.xaml.cs
+++ b/Pixiview/OptionPage.xaml.cs
@@ -102,7 +102,7 @@ namespace Pixiview
             {
                 Preferences.Set(Configs.IsOnR18Key, r18);
                 Configs.IsOnR18 = r18;
-#if DEBUG
+#if LOG
                 App.DebugPrint($"r-18 filter: {r18}");
 #endif
             }
@@ -111,7 +111,7 @@ namespace Pixiview
             {
                 Preferences.Set(Configs.SyncFavTypeKey, syncType);
                 Configs.SyncFavType = (SyncType)syncType;
-#if DEBUG
+#if LOG
                 App.DebugPrint($"favorite sync type changed to {Configs.SyncFavType}");
 #endif
             }
@@ -134,7 +134,7 @@ namespace Pixiview
                     if (!string.IsNullOrEmpty(h) && pt > 0)
                     {
                         Configs.Proxy = new System.Net.WebProxy(h, pt);
-#if DEBUG
+#if LOG
                         App.DebugPrint($"set proxy to: {h}:{pt}");
 #endif
                     }
@@ -151,7 +151,7 @@ namespace Pixiview
                 if (proxy != null)
                 {
                     Configs.Proxy = null;
-#if DEBUG
+#if LOG
                     App.DebugPrint("clear proxy");
 #endif
                 }
@@ -170,7 +170,7 @@ namespace Pixiview
                     {
                         session = session.Substring(0, index);
                         Configs.SetUserId(session, true);
-#if DEBUG
+#if LOG
                         App.DebugPrint($"cookie changed, user id: {session}");
 #endif
                     }
diff --git a/Pixiview/UI/AdaptedPage.cs b/Pixiview/UI/AdaptedPage.cs
index 808f708..661be8e 100644
--- a/Pixiview/UI/AdaptedPage.cs
+++ b/Pixiview/UI/AdaptedPage.cs
@@ -132,7 +132,7 @@ namespace Pixiview.UI
         {
             if (Tap.IsBusy)
             {
-#if DEBUG
+#if LOG
                 App.DebugPrint("gesture recognizer is now busy...");
 #endif
                 return;
diff --git a/Pixiview/Utils/EnvironmentService.cs b/Pixiview/Utils/EnvironmentService.cs
index 2c3e601..b37e185 100644
--- a/Pixiview/Utils/EnvironmentService.cs
+++ b/Pixiview/Utils/EnvironmentService.cs
@@ -109,7 +109,7 @@ namespace Pixiview.Utils
         {
             Thread.CurrentThread.CurrentCulture = ci;
             Thread.CurrentThread.CurrentUICulture = ci;
-#if DEBUG
+#if LOG
             App.DebugPrint($"CurrentCulture set: {ci.Name}");
 #endif
         }
diff --git a/Pixiview/Utils/Extensions.cs b/Pixiview/Utils/Extensions.cs
index 8702cbe..b0650cf 100644
--- a/Pixiview/Utils/Extensions.cs
+++ b/Pixiview/Utils/Extensions.cs
@@ -1,4 +1,5 @@
 using System;
+using System.Collections.Generic;
 using System.Threading;
 using System.Threading.Tasks;
 using Xamarin.Forms;
@@ -96,19 +97,19 @@ namespace Pixiview.Utils
 
     public class ParallelTask : IDisposable
     {
-        public static ParallelTask Start(int from, int toExclusive, int maxCount, Predicate<int> action, Action complete = null)
+        public static ParallelTask Start(string tag, int from, int toExclusive, int maxCount, Predicate<int> action, Action complete = null)
         {
             if (toExclusive <= from)
             {
                 if (complete != null)
                 {
-                    ThreadPool.QueueUserWorkItem(o => complete());
+                    Task.Run(complete);
                 }
                 return null;
             }
-            var task = new ParallelTask(from, toExclusive, maxCount, action, complete);
-            //Task.Run(task.Start);
-            ThreadPool.QueueUserWorkItem(task.Start);
+            var task = new ParallelTask(tag, from, toExclusive, maxCount, action, complete);
+            Task.Run(task.Start);
+            //ThreadPool.QueueUserWorkItem(task.Start);
             return task;
         }
 
@@ -116,13 +117,14 @@ namespace Pixiview.Utils
         private int count;
         private bool disposed;
 
+        private readonly string tag;
         private readonly int max;
         private readonly int from;
         private readonly int to;
         private readonly Predicate<int> action;
         private readonly Action complete;
 
-        private ParallelTask(int from, int to, int maxCount, Predicate<int> action, Action complete)
+        private ParallelTask(string tag, int from, int to, int maxCount, Predicate<int> action, Action complete)
         {
             if (maxCount <= 0)
             {
@@ -133,14 +135,16 @@ namespace Pixiview.Utils
             {
                 throw new ArgumentOutOfRangeException(nameof(from));
             }
+            this.tag = tag;
             this.from = from;
             this.to = to;
             this.action = action;
             this.complete = complete;
         }
 
-        private void Start(object o)
+        private void Start()
         {
+            var list = new List<Task>();
             for (int i = from; i < to; i++)
             {
                 var index = i;
@@ -152,8 +156,8 @@ namespace Pixiview.Utils
                     }
                     if (disposed)
                     {
-#if DEBUG
-                        App.DebugPrint($"parallel task determinate, disposed");
+#if LOG
+                        App.DebugPrint($"parallel task determinate, disposed ({tag})");
 #endif
                         return;
                     }
@@ -163,7 +167,7 @@ namespace Pixiview.Utils
                 {
                     count++;
                 }
-                Task.Run(() =>
+                list.Add(Task.Run(() =>
                 {
                     try
                     {
@@ -174,7 +178,7 @@ namespace Pixiview.Utils
                     }
                     catch (Exception ex)
                     {
-                        App.DebugError("parallel.start", $"failed to run action, index: {i}, error: {ex.Message}");
+                        App.DebugError("parallel.start ({tag})", $"failed to run action, index: {i}, error: {ex.Message}");
                     }
                     finally
                     {
@@ -183,10 +187,21 @@ namespace Pixiview.Utils
                             count--;
                         }
                     }
-                });
+                }));
             }
-#if DEBUG
-            App.DebugPrint($"parallel task done");
+            while (count > 0)
+            {
+                if (disposed)
+                {
+#if LOG
+                    App.DebugPrint($"parallel task determinate, disposed ({tag})");
+#endif
+                    return;
+                }
+                Thread.Sleep(100);
+            }
+#if LOG
+            App.DebugPrint($"parallel task done ({tag})");
 #endif
             complete?.Invoke();
         }
diff --git a/Pixiview/Utils/Stores.cs b/Pixiview/Utils/Stores.cs
index ccf1700..7192d1c 100644
--- a/Pixiview/Utils/Stores.cs
+++ b/Pixiview/Utils/Stores.cs
@@ -29,7 +29,7 @@ namespace Pixiview.Utils
         private const string preloadsFolder = "preloads";
         private const string thumbFolder = "img-thumb";
         private const string userFolder = "user-profile";
-        private const string recommendsFolder = "recommends";
+        //private const string recommendsFolder = "recommends";
 
         public static bool NetworkAvailable
         {
@@ -238,18 +238,17 @@ namespace Pixiview.Utils
             return result;
         }
 
-        public static IllustRecommendsData LoadIllustRecommendsInitData(string id, bool force = false)
+        public static IllustRecommendsData LoadIllustRecommendsInitData(string id)
         {
-            var file = Path.Combine(CacheFolder, recommendsFolder, $"{id}.json");
+            //var file = Path.Combine(CacheFolder, recommendsFolder, $"{id}.json");
             var result = HttpUtility.LoadObject<IllustRecommendsData>(
-                file,
+                null,
                 string.Format(Configs.UrlIllustRecommendsInit, id),
                 string.Format(Configs.RefererIllust, id),
-                out _,
-                force: force);
+                out _);
             if (result == null || result.error)
             {
-                App.DebugPrint($"error when load recommends init data: {result?.message}, force({force})");
+                App.DebugPrint($"error when load recommends init data: {result?.message}");
             }
             return result;
         }
@@ -303,7 +302,7 @@ namespace Pixiview.Utils
             }
             else
             {
-#if DEBUG
+#if LOG
                 App.DebugPrint($"current csrf token: {result.token}");
 #endif
                 Configs.CsrfToken = result.token;
@@ -338,7 +337,7 @@ namespace Pixiview.Utils
             }
             else
             {
-#if DEBUG
+#if LOG
                 App.DebugPrint($"successs, bookmark id: {result.body.last_bookmark_id}, status: {result.body.stacc_status_id}");
 #endif
                 return result.body.last_bookmark_id;
@@ -374,7 +373,7 @@ namespace Pixiview.Utils
                 App.DebugPrint("failed to delete bookmark, result is null");
                 return false;
             }
-#if DEBUG
+#if LOG
             App.DebugPrint($"successs, delete bookmark");
 #endif
             return true;
diff --git a/Pixiview/Utils/Ugoira.cs b/Pixiview/Utils/Ugoira.cs
index 04b67bf..b793ba6 100644
--- a/Pixiview/Utils/Ugoira.cs
+++ b/Pixiview/Utils/Ugoira.cs
@@ -30,6 +30,7 @@ namespace Pixiview.Utils
         private readonly ImageSource[] frames;
         private Timer timer;
         private int index = 0;
+        private ParallelTask downloadTask;
 
         public bool IsPlaying { get; private set; }
         public readonly int FrameCount;
@@ -51,6 +52,11 @@ namespace Pixiview.Utils
             {
                 TogglePlay(false);
             }
+            if (downloadTask != null)
+            {
+                downloadTask.Dispose();
+                downloadTask = null;
+            }
             ClearTimer();
         }
 
@@ -178,7 +184,7 @@ namespace Pixiview.Utils
                 var url = ugoira.originalSrc;
                 var id = detailItem.Id;
                 var (size, lastModified, client) = HttpUtility.GetUgoiraHeader(url, id);
-#if DEBUG
+#if LOG
                 App.DebugPrint($"starting download ugoira: {size} bytes, last modified: {lastModified}");
 #endif
 
@@ -283,7 +289,12 @@ namespace Pixiview.Utils
                     }
                 }
 
-                ParallelTask.Start(0, inSegs.Count, 2, i =>
+                if (downloadTask != null)
+                {
+                    downloadTask.Dispose();
+                    downloadTask = null;
+                }
+                downloadTask = ParallelTask.Start("ugoira.download", 0, inSegs.Count, 2, i =>
                 {
                     var seg = inSegs[i];
 #if DEBUG
@@ -325,8 +336,8 @@ namespace Pixiview.Utils
                         }
                     }
                 }
-#if DEBUG
-                App.DebugPrint("download over");
+#if LOG
+                App.DebugPrint("load frames over");
 #endif
             }
         }
@@ -454,78 +465,81 @@ namespace Pixiview.Utils
 #endif
                 for (int i = 0; i < images.Length; i++)
                 {
-                    while (true)
+                    while (!writerInput.ReadyForMoreMediaData)
                     {
-                        if (writerInput.ReadyForMoreMediaData)
+                        lock (sync)
                         {
-                            // get pixel buffer and fill it with the image
-                            using (CVPixelBuffer pixelBufferImage = pixelBufferAdaptor.PixelBufferPool.CreatePixelBuffer())
+                            if (timer == null)
                             {
-                                pixelBufferImage.Lock(CVPixelBufferLock.None);
+                                return null;
+                            }
+                        }
+                        Thread.Sleep(50);
+                    }
+                    // get pixel buffer and fill it with the image
+                    using (CVPixelBuffer pixelBufferImage = pixelBufferAdaptor.PixelBufferPool.CreatePixelBuffer())
+                    {
+                        pixelBufferImage.Lock(CVPixelBufferLock.None);
 
-                                try
+                        try
+                        {
+                            IntPtr pxdata = pixelBufferImage.BaseAddress;
+
+                            if (pxdata != IntPtr.Zero)
+                            {
+                                using (var rgbColorSpace = CGColorSpace.CreateDeviceRGB())
                                 {
-                                    IntPtr pxdata = pixelBufferImage.BaseAddress;
-
-                                    if (pxdata != IntPtr.Zero)
+                                    var cgImage = images[i].CGImage;
+                                    var width = cgImage.Width;
+                                    var height = cgImage.Height;
+                                    var bitsPerComponent = cgImage.BitsPerComponent;
+                                    var bytesPerRow = cgImage.BytesPerRow;
+                                    // padding to 64
+                                    var bytes = bytesPerRow >> 6 << 6;
+                                    if (bytes < bytesPerRow)
                                     {
-                                        using (var rgbColorSpace = CGColorSpace.CreateDeviceRGB())
-                                        {
-                                            var cgImage = images[i].CGImage;
-                                            var width = cgImage.Width;
-                                            var height = cgImage.Height;
-                                            var bitsPerComponent = cgImage.BitsPerComponent;
-                                            var bytesPerRow = cgImage.BytesPerRow;
-                                            // padding to 64
-                                            var bytes = bytesPerRow >> 6 << 6;
-                                            if (bytes < bytesPerRow)
-                                            {
-                                                bytes += 64;
-                                            }
+                                        bytes += 64;
+                                    }
 #if DEBUG
-                                            if (!log)
-                                            {
-                                                log = true;
-                                                App.DebugPrint($"animation, width: {width}, height: {height}, type: {cgImage.UTType}\n" +
-                                                    $"bitmapInfo: {cgImage.BitmapInfo}\n" +
-                                                    $"bpc: {bitsPerComponent}\n" +
-                                                    $"bpp: {cgImage.BitsPerPixel}\n" +
-                                                    $"calculated: {bytesPerRow} => {bytes}");
-                                            }
+                                    if (!log)
+                                    {
+                                        log = true;
+                                        App.DebugPrint($"animation, width: {width}, height: {height}, type: {cgImage.UTType}\n" +
+                                            $"bitmapInfo: {cgImage.BitmapInfo}\n" +
+                                            $"bpc: {bitsPerComponent}\n" +
+                                            $"bpp: {cgImage.BitsPerPixel}\n" +
+                                            $"calculated: {bytesPerRow} => {bytes}");
+                                    }
 #endif
-                                            using (CGBitmapContext bitmapContext = new CGBitmapContext(
-                                                pxdata, width, height,
-                                                bitsPerComponent,
-                                                bytes,
-                                                rgbColorSpace,
-                                                CGImageAlphaInfo.NoneSkipFirst))
-                                            {
-                                                if (bitmapContext != null)
-                                                {
-                                                    bitmapContext.DrawImage(new CGRect(0, 0, width, height), cgImage);
-                                                }
-                                            }
+                                    using (CGBitmapContext bitmapContext = new CGBitmapContext(
+                                        pxdata, width, height,
+                                        bitsPerComponent,
+                                        bytes,
+                                        rgbColorSpace,
+                                        CGImageAlphaInfo.NoneSkipFirst))
+                                    {
+                                        if (bitmapContext != null)
+                                        {
+                                            bitmapContext.DrawImage(new CGRect(0, 0, width, height), cgImage);
                                         }
                                     }
                                 }
-                                finally
-                                {
-                                    pixelBufferImage.Unlock(CVPixelBufferLock.None);
-                                }
-
-                                // and finally append buffer to adapter
-                                if (pixelBufferAdaptor.AssetWriterInput.ReadyForMoreMediaData && pixelBufferImage != null)
-                                {
-                                    pixelBufferAdaptor.AppendPixelBufferWithPresentationTime(pixelBufferImage, lastTime);
-                                }
                             }
-
-                            var frameTime = new CMTime(ugoira.frames[i].delay, 1000);
-                            lastTime = CMTime.Add(lastTime, frameTime);
-                            break;
                         }
-                        Thread.Sleep(32);
+                        finally
+                        {
+                            pixelBufferImage.Unlock(CVPixelBufferLock.None);
+                        }
+
+                        // and finally append buffer to adapter
+                        if (pixelBufferAdaptor.AssetWriterInput.ReadyForMoreMediaData && pixelBufferImage != null)
+                        {
+                            pixelBufferAdaptor.AppendPixelBufferWithPresentationTime(pixelBufferImage, lastTime);
+                        }
                     }
+
+                    var frameTime = new CMTime(ugoira.frames[i].delay, 1000);
+                    lastTime = CMTime.Add(lastTime, frameTime);
                 }
                 writerInput.MarkAsFinished();
                 await videoWriter.FinishWritingAsync();