diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml
new file mode 100644
index 00000000..86d6f8d0
--- /dev/null
+++ b/.github/workflows/dotnet.yml
@@ -0,0 +1,25 @@
+name: .NET
+
+on:
+ push:
+ branches: [ dev ]
+ pull_request:
+ branches: [ dev ]
+
+jobs:
+ build:
+
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v2
+ - name: Setup .NET
+ uses: actions/setup-dotnet@v1
+ with:
+ dotnet-version: 5.0.x
+ - name: Restore dependencies
+ run: dotnet restore Platforms/Anf.sln
+ - name: Build
+ run: dotnet build Platforms/Anf.sln --no-restore
+ - name: Test
+ run: dotnet test Platforms/Anf.sln --no-build --verbosity normal
diff --git a/Platforms/Anf.Avalon/Anf.Avalon.csproj b/Platforms/Anf.Avalon/Anf.Avalon.csproj
index 5622df18..3c2d405b 100644
--- a/Platforms/Anf.Avalon/Anf.Avalon.csproj
+++ b/Platforms/Anf.Avalon/Anf.Avalon.csproj
@@ -10,7 +10,7 @@
false
- net472;net6.0
+ net472;net5.0
net472
diff --git a/Platforms/Anf.Avalon/App.axaml.cs b/Platforms/Anf.Avalon/App.axaml.cs
index 0e1e9448..0a6d8824 100644
--- a/Platforms/Anf.Avalon/App.axaml.cs
+++ b/Platforms/Anf.Avalon/App.axaml.cs
@@ -51,7 +51,7 @@ private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionE
private void InitServices()
{
AppEngine.Reset();
- AppEngine.AddServices(NetworkAdapterTypes.WebRequest);
+ AppEngine.AddServices(NetworkAdapterTypes.HttpClient);
var store = FileStoreService.FromMd5Default(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, XComicConst.CacheFolderName));
var hp = new Lazy(() => new HomePage());
var cv = new Lazy(() => new ComicView());
@@ -90,8 +90,8 @@ public override void OnFrameworkInitializationCompleted()
var nav = AppEngine.GetRequiredService();
var mainWin = AppEngine.GetRequiredService();
desktop.MainWindow =mainWin;
- nav.Navigate(new VisitingView());
- //nav.Navigate();
+ //nav.Navigate(new VisitingView());
+ nav.Navigate();
AppEngine.GetRequiredService().Bind(mainWin);
mainWin.KeyDown += OnMainWinKeyDown;
diff --git a/Platforms/Anf.Avalon/MainWindow.axaml b/Platforms/Anf.Avalon/MainWindow.axaml
index 178f5528..9f9efe72 100644
--- a/Platforms/Anf.Avalon/MainWindow.axaml
+++ b/Platforms/Anf.Avalon/MainWindow.axaml
@@ -9,33 +9,35 @@
x:Class="Anf.Avalon.MainWindow"
Title="Anf">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ IsVisible="{Binding HasException}"
+ VerticalAlignment="Stretch"
+ HorizontalAlignment="Stretch"
+ Padding="16">
@@ -65,6 +67,5 @@
-
diff --git a/Platforms/Anf.Avalon/ViewModels/AvalonVisitingViewModel.cs b/Platforms/Anf.Avalon/ViewModels/AvalonVisitingViewModel.cs
index 8bf66c3a..33b7332d 100644
--- a/Platforms/Anf.Avalon/ViewModels/AvalonVisitingViewModel.cs
+++ b/Platforms/Anf.Avalon/ViewModels/AvalonVisitingViewModel.cs
@@ -211,5 +211,10 @@ protected async override void OnCurrentChaterCursorChanged(IDataCursor
-
+
-
+
diff --git a/Platforms/Anf.Web/Anf.Web.csproj b/Platforms/Anf.Web/Anf.Web.csproj
index 8d994a0a..32ccc88d 100644
--- a/Platforms/Anf.Web/Anf.Web.csproj
+++ b/Platforms/Anf.Web/Anf.Web.csproj
@@ -2,7 +2,7 @@
Exe
- net6.0
+ net5.0
8.0
$(NoWarn);CS1591
false
diff --git a/Platforms/Engines/Anf.KnowEngines/BilibiliComicOperator.cs b/Platforms/Engines/Anf.KnowEngines/BilibiliComicOperator.cs
index 62b1eba1..67bf4239 100644
--- a/Platforms/Engines/Anf.KnowEngines/BilibiliComicOperator.cs
+++ b/Platforms/Engines/Anf.KnowEngines/BilibiliComicOperator.cs
@@ -1,4 +1,7 @@
using Anf.Networks;
+using HtmlAgilityPack;
+using JavaScriptEngineSwitcher.Core;
+using Jint.Native.Array;
#if !NETSTANDARD1_3
using Microsoft.IO;
#endif
@@ -9,6 +12,7 @@
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
+using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace Anf.KnowEngines
diff --git a/Platforms/Engines/Anf.KnowEngines/KnowEnginesExtensions.cs b/Platforms/Engines/Anf.KnowEngines/KnowEnginesExtensions.cs
index 1c724267..2adf1e00 100644
--- a/Platforms/Engines/Anf.KnowEngines/KnowEnginesExtensions.cs
+++ b/Platforms/Engines/Anf.KnowEngines/KnowEnginesExtensions.cs
@@ -18,6 +18,8 @@ public static void AddKnowEngines(this IServiceCollection services)
services.AddScoped();
services.AddScoped();
services.AddScoped();
+ services.AddScoped();
+ services.AddScoped();
}
public static void UseKnowEngines(this IServiceProvider provider)
{
@@ -29,6 +31,8 @@ public static void UseKnowEngines(this IServiceProvider provider)
eng.Add(new TencentComicSourceCondition());
eng.Add(new BilibiliComicSourceCondition());
eng.Add(new QimianComicSourceCondition());
+ eng.Add(new MangabzComicCondition());
+ eng.Add(new XmanhuaComicCondition());
var searchEng = provider.GetRequiredService();
searchEng.Add(typeof(SomanSearchProvider));
}
diff --git a/Platforms/Engines/Anf.KnowEngines/MangabzComicCondition.cs b/Platforms/Engines/Anf.KnowEngines/MangabzComicCondition.cs
new file mode 100644
index 00000000..f156f0fe
--- /dev/null
+++ b/Platforms/Engines/Anf.KnowEngines/MangabzComicCondition.cs
@@ -0,0 +1,16 @@
+using System;
+
+namespace Anf.KnowEngines
+{
+ public class MangabzComicCondition : ComicSourceConditionBase
+ {
+ public override string EnginName => "Mangabz";
+
+ public override Uri Address { get; } = new Uri("http://www.mangabz.com/");
+
+ public override bool Condition(ComicSourceContext context)
+ {
+ return context.Uri.Host == Address.Host;
+ }
+ }
+}
diff --git a/Platforms/Engines/Anf.KnowEngines/MangabzComicOperator.cs b/Platforms/Engines/Anf.KnowEngines/MangabzComicOperator.cs
new file mode 100644
index 00000000..ced93c22
--- /dev/null
+++ b/Platforms/Engines/Anf.KnowEngines/MangabzComicOperator.cs
@@ -0,0 +1,164 @@
+using Anf.Networks;
+using HtmlAgilityPack;
+using JavaScriptEngineSwitcher.Core;
+using Jint.Native.Array;
+using Newtonsoft.Json.Linq;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text.RegularExpressions;
+using System.Threading.Tasks;
+
+namespace Anf.KnowEngines
+{
+ public class MangabzComicOperator : IComicSourceProvider
+ {
+ private static readonly Regex cidRegex = new Regex(@"var MANGABZ_CID=(.*)?;", RegexOptions.Compiled);
+ private static readonly Regex dtRegex = new Regex(@"var MANGABZ_VIEWSIGN_DT=""(.*)?"";", RegexOptions.Compiled);
+ private static readonly Regex midRegex = new Regex(@"var MANGABZ_MID=(.*)?;", RegexOptions.Compiled);
+ private static readonly Regex viewSignRegex = new Regex(@"var MANGABZ_VIEWSIGN=(.*)?;", RegexOptions.Compiled);
+ private static readonly Regex imageCountRegex = new Regex(@"var MANGABZ_IMAGE_COUNT=(.*)?;", RegexOptions.Compiled);
+
+ private readonly INetworkAdapter networkAdapter;
+ private readonly IJsEngine jsEngine;
+ private static readonly Dictionary headers = new Dictionary
+ {
+ ["User-Agent"] = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4437.0 Safari/537.36 Edg/91.0.831.1",
+ };
+
+ public MangabzComicOperator(INetworkAdapter networkAdapter, IJsEngine jsEngine)
+ {
+ this.networkAdapter = networkAdapter;
+ this.jsEngine = jsEngine;
+ }
+
+ protected virtual Task GetStreamAsync(string address)
+ {
+ return networkAdapter.GetStreamAsync(new RequestSettings
+ {
+ Address = address,
+ Host = new Uri(address).Host,
+ Referrer = GetBaseAddress(),
+ Headers = headers
+ });
+ }
+ protected virtual string GetBaseAddress()
+ {
+ return "http://www.mangabz.com/";
+ }
+ public async Task GetChaptersAsync(string targetUrl)
+ {
+ var str = string.Empty;
+ using (var sr = new StreamReader(await GetStreamAsync(targetUrl)))
+ {
+ str = sr.ReadToEnd();
+ }
+ var html = new HtmlDocument();
+ html.LoadHtml(str);
+ var img = html.DocumentNode.SelectSingleNode("//div[@class='detail-info']/img[@class='detail-info-cover']");
+ var title = html.DocumentNode.SelectSingleNode("//div[@class='detail-info']/p[@class='detail-info-title']");
+ var desc = html.DocumentNode.SelectSingleNode("//div[@class='detail-info']/div[@class='detail-info-content']");
+
+ var chpsBox = html.DocumentNode.SelectNodes("//div[@id='chapterlistload']/a");
+ var chps = new List();
+ foreach (var item in chpsBox)
+ {
+ var name = item.InnerText.Replace(" ", string.Empty);
+ var addr = item.Attributes["href"].Value;
+ var chp = new ComicChapter
+ {
+ Title = name,
+ TargetUrl = "http://www.mangabz.com" + addr
+ };
+ chps.Add(chp);
+ }
+ var entity = new ComicEntity
+ {
+ ComicUrl = targetUrl,
+ Descript = desc?.InnerText,
+ ImageUrl = img?.Attributes["src"].Value,
+ Name = title?.InnerText,
+ Chapters = chps.ToArray()
+ };
+ return entity;
+ }
+
+ public Task GetImageStreamAsync(string targetUrl)
+ {
+ return GetStreamAsync(targetUrl);
+ }
+
+ public async Task GetPagesAsync(string targetUrl)
+ {
+ var str = string.Empty;
+ using (var sr = new StreamReader(await GetStreamAsync(targetUrl)))
+ {
+ str = sr.ReadToEnd();
+ }
+ var cidRgx = cidRegex.Match(str).Groups[0].Value;
+ var dtRgx = dtRegex.Match(str).Groups[0].Value;
+ var midRgx = midRegex.Match(str).Groups[0].Value;
+ var viewSignRgx = viewSignRegex.Match(str).Groups[0].Value;
+ var imgCountRgx = imageCountRegex.Match(str).Groups[0].Value;
+
+ var cid = cidRgx.Substring(0, cidRgx.IndexOf(';')).Split('=').Last();
+ var dt = dtRgx.Substring(0, dtRgx.IndexOf(';')).Split('=').Last().Trim('\"');
+ var mid = midRgx.Substring(0, midRgx.IndexOf(';')).Split('=').Last();
+ var viewSign = viewSignRgx.Substring(0, viewSignRgx.IndexOf(';')).Split('=').Last().Trim('\"');
+ var imgCount = imgCountRgx.Substring(0, imgCountRgx.IndexOf(';')).Split('=').Last().Trim('\"');
+ var val = int.Parse(imgCount);
+
+ var refAddr = new Uri(targetUrl).Segments.Last();
+
+ var part = $"{GetBaseAddress()}/{refAddr}/chapterimage.ashx?cid={cid}&page={{0}}&key=&_cid={cid}&_mid={mid}&_dt={DateTime.Now}&_sign={viewSign}";
+
+ async Task RunBlockAsync(int index)
+ {
+ var pgs = new List();
+ var partBlock = string.Format(part, index + 1);
+
+ string partEncod = null;
+ using (var sr = new StreamReader(await GetStreamAsync(partBlock)))
+ {
+ partEncod = sr.ReadToEnd();
+ }
+ if (!string.IsNullOrEmpty(partEncod))
+ {
+ var ret = (ArrayInstance)jsEngine.Evaluate(partEncod);
+ var length = ret.GetLength();
+ for (int i = 0; i < length; i++)
+ {
+ pgs.Add(new ComicPage
+ {
+ Name = (index + 1).ToString(),
+ TargetUrl = ret.GetProperty(i.ToString()).Value.ToString()
+ });
+ }
+ }
+ return pgs.ToArray();
+ }
+ var datas = new List();
+ for (int i = 0; i < val; i++)
+ {
+ var j = i;
+ datas.Add(await RunBlockAsync(j));
+ }
+ var containPages = new HashSet();
+ var pages = new List(datas.Count);
+ for (int i = 0; i < datas.Count; i++)
+ {
+ var res = datas[i];
+ for (int q = 0; q < res.Length; q++)
+ {
+ var r = res[q];
+ if (containPages.Add(r.TargetUrl))
+ {
+ pages.Add(r);
+ }
+ }
+ }
+ return pages.ToArray();
+ }
+ }
+}
diff --git a/Platforms/Engines/Anf.KnowEngines/XmanhuaComicCondition.cs b/Platforms/Engines/Anf.KnowEngines/XmanhuaComicCondition.cs
new file mode 100644
index 00000000..30f16d1e
--- /dev/null
+++ b/Platforms/Engines/Anf.KnowEngines/XmanhuaComicCondition.cs
@@ -0,0 +1,16 @@
+using System;
+
+namespace Anf.KnowEngines
+{
+ public class XmanhuaComicCondition : ComicSourceConditionBase
+ {
+ public override string EnginName => "Xmanhua";
+
+ public override Uri Address { get; } = new Uri("http://www.xmanhua.com/");
+
+ public override bool Condition(ComicSourceContext context)
+ {
+ return context.Uri.Host == Address.Host;
+ }
+ }
+}
diff --git a/Platforms/Engines/Anf.KnowEngines/XmanhuaComicOperator.cs b/Platforms/Engines/Anf.KnowEngines/XmanhuaComicOperator.cs
new file mode 100644
index 00000000..aaa9d1fd
--- /dev/null
+++ b/Platforms/Engines/Anf.KnowEngines/XmanhuaComicOperator.cs
@@ -0,0 +1,17 @@
+using Anf.Networks;
+using JavaScriptEngineSwitcher.Core;
+
+namespace Anf.KnowEngines
+{
+ public class XmanhuaComicOperator : MangabzComicOperator
+ {
+ public XmanhuaComicOperator(INetworkAdapter networkAdapter, IJsEngine jsEngine) : base(networkAdapter, jsEngine)
+ {
+ }
+
+ protected override string GetBaseAddress()
+ {
+ return "http://www.xmanhua.com";
+ }
+ }
+}
diff --git a/azure-pipelines.yml b/azure-pipelines.yml
new file mode 100644
index 00000000..3123672c
--- /dev/null
+++ b/azure-pipelines.yml
@@ -0,0 +1,54 @@
+# .NET Desktop
+# Build and run tests for .NET Desktop or Windows classic desktop solutions.
+# Add steps that publish symbols, save build artifacts, and more:
+# https://docs.microsoft.com/azure/devops/pipelines/apps/windows/dot-net
+
+trigger:
+- dev
+
+pool:
+ vmImage: 'windows-latest'
+
+variables:
+ solution: '**/*.sln'
+ buildPlatform: 'Any CPU'
+ buildConfiguration: 'Release'
+
+steps:
+- task: NuGetToolInstaller@1
+
+- task: NuGetCommand@2
+ inputs:
+ restoreSolution: '$(solution)'
+
+- task: VSBuild@1
+ inputs:
+ solution: '$(solution)'
+ platform: '$(buildPlatform)'
+ configuration: '$(buildConfiguration)'
+
+- task: VSTest@2
+ inputs:
+ platform: '$(buildPlatform)'
+ configuration: '$(buildConfiguration)'
+
+- task: DotNetCoreCLI@2
+ displayName: 'dotnet test'
+ inputs:
+ command: test
+ projects: '**/*.Test.csproj'
+ arguments: '--configuration $(BuildConfiguration) --collect "XPlat Code coverage" -- RunConfiguration.DisableAppDomain=true'
+ testRunTitle: MyProject.UnitTests
+
+- script: 'dotnet tool install --global dotnet-reportgenerator-globaltool --version 4.5.8'
+ displayName: 'Install ReportGenerator tool'
+
+- script: 'reportgenerator -reports:$(Agent.TempDirectory)/**/coverage.cobertura.xml -targetdir:$(Build.SourcesDirectory)/coverlet/reports -reporttypes:"Cobertura"'
+ displayName: 'Create reports'
+
+- task: PublishCodeCoverageResults@1
+ displayName: 'Publish code coverage'
+ inputs:
+ codeCoverageTool: Cobertura
+ summaryFileLocation: '$(Build.SourcesDirectory)/coverlet/reports/Cobertura.xml'
+
diff --git a/test/Anf.Easy.Test/Anf.Easy.Test.csproj b/test/Anf.Easy.Test/Anf.Easy.Test.csproj
index 38afeb6b..311620a1 100644
--- a/test/Anf.Easy.Test/Anf.Easy.Test.csproj
+++ b/test/Anf.Easy.Test/Anf.Easy.Test.csproj
@@ -6,6 +6,7 @@
+
diff --git a/test/Anf.Easy.Test/ComicHostExtensionsTest.cs b/test/Anf.Easy.Test/ComicHostExtensionsTest.cs
index 0c092832..417d0911 100644
--- a/test/Anf.Easy.Test/ComicHostExtensionsTest.cs
+++ b/test/Anf.Easy.Test/ComicHostExtensionsTest.cs
@@ -30,7 +30,7 @@ public async Task GetVisitingAndLoadAsync_MustReturnLoadedVisitor()
[typeof(IComicVisiting)]=()=>ComicVisitingHelper.CreateResrouceVisitor()
}
};
- var visitor=await ComicHostExtensions.GetVisitingAndLoadAsync(provider, "http://localhost:8765");
+ var visitor=await ComicHostExtensions.GetVisitingAndLoadAsync(provider, "http://localhost:8887");
Assert.IsNotNull(visitor);
Assert.IsNotNull(visitor.Entity);
}
@@ -44,7 +44,7 @@ public async Task GetVisitingAndLoadAsync_FailToLoad_MustReturnNull()
[typeof(IComicVisiting)] = () => new NullComicVisiting { LoadSucceed=false}
}
};
- var visitor = await ComicHostExtensions.GetVisitingAndLoadAsync(provider, "http://localhost:8765");
+ var visitor = await ComicHostExtensions.GetVisitingAndLoadAsync(provider, "http://localhost:8889");
Assert.IsNull(visitor);
}
[TestMethod]
diff --git a/test/Anf.Easy.Test/Downloading/DownloadManagersTest.cs b/test/Anf.Easy.Test/Downloading/DownloadManagersTest.cs
index 566a6e97..34102822 100644
--- a/test/Anf.Easy.Test/Downloading/DownloadManagersTest.cs
+++ b/test/Anf.Easy.Test/Downloading/DownloadManagersTest.cs
@@ -22,7 +22,7 @@ private async Task Run(AsyncDownloadManager mgr,int taskCount,int preCount)
}
mgr.Start();
var tks = new CancellationTokenSource();
- var timeOutTask = Task.Delay(10 * 1000).ContinueWith(_ => tks.Cancel());
+ var timeOutTask = Task.Delay(TimeSpan.FromMinutes(30)).ContinueWith(_ => tks.Cancel());
while (!tks.IsCancellationRequested)
{
if (mgr.Count == 0)
diff --git a/test/Anf.Easy.Test/Visiting/BlockSlotsTest.cs b/test/Anf.Easy.Test/Visiting/BlockSlotsTest.cs
index de0c869d..bdd7d41f 100644
--- a/test/Anf.Easy.Test/Visiting/BlockSlotsTest.cs
+++ b/test/Anf.Easy.Test/Visiting/BlockSlotsTest.cs
@@ -39,9 +39,10 @@ public async Task GivenDisposeableObject_Dispose_AllDisposed()
await slot.GetAsync(i);
}
slot.Dispose();
- for (int i = 0; i < slot.Size; i++)
+ var objs = slot.GetCreatedValues().OfType().ToArray();
+ for (int i = 0; i < objs.Length; i++)
{
- var obj = (DispoableObject)slot[i];
+ var obj = objs[i];
Assert.IsTrue(obj.IsDisposed);
}
}
diff --git a/test/Anf.Easy.Test/Visiting/ComicVisitingHelper.cs b/test/Anf.Easy.Test/Visiting/ComicVisitingHelper.cs
index 4c1010e0..bbfc5823 100644
--- a/test/Anf.Easy.Test/Visiting/ComicVisitingHelper.cs
+++ b/test/Anf.Easy.Test/Visiting/ComicVisitingHelper.cs
@@ -9,7 +9,7 @@ namespace Anf.Easy.Test.Visiting
{
internal static class ComicVisitingHelper
{
- public static readonly Uri AnyUri = new Uri("http://localhost:8765/");
+ public static readonly Uri AnyUri = new Uri("http://localhost:8886/");
public static ComicVisiting CreateResrouceVisitor()
{
var creator = new StreamResourceFactoryCreator();