From d2ba2fa2515050934b1ef1da62af9fb6820a794d Mon Sep 17 00:00:00 2001 From: Harry Yu Date: Sat, 6 Feb 2021 11:53:29 +0800 Subject: [PATCH 1/3] download manager and upgrade dict --- src/DictDownloadManager.cs | 110 +++++++++++++++++++++++++++++++++++++ src/Dictionary.cs | 10 +++- src/ECDict.cs | 20 ++++--- 3 files changed, 132 insertions(+), 8 deletions(-) create mode 100644 src/DictDownloadManager.cs diff --git a/src/DictDownloadManager.cs b/src/DictDownloadManager.cs new file mode 100644 index 0000000..fb9a4e8 --- /dev/null +++ b/src/DictDownloadManager.cs @@ -0,0 +1,110 @@ +using Flow.Launcher.Plugin; +using System; +using System.Collections.Generic; +using System.IO; +using System.IO.Compression; +using System.Net; +using System.Threading.Tasks; + +namespace Dictionary +{ + public class DictDownloadManager + { + private string dictPath; + private bool downloading = false; + private int downloadPercentage = 0; + private PluginInitContext context; + + public DictDownloadManager(string dictPath, PluginInitContext context) + { + this.dictPath = dictPath; + this.context = context; + } + + private async Task CheckForGoogleConnection() + { + try + { + var request = WebRequest.Create("https://google.com/generate_204"); + request.Timeout = 2000; + await request.GetResponseAsync(); + return true; + } + catch + { + return false; + } + } + + private async Task GetDownloadUrl() + { + bool shouldUseMirror = !await CheckForGoogleConnection(); + if (shouldUseMirror) + return "https://nullptr_t.coding.net/p/ECDICT-sqlite/d/ECDICT-sqlite/git/raw/master/ecdict-ultimate-sqlite.zip"; + else + return "https://github.com/skywind3000/ECDICT-ultimate/releases/download/1.0.0/ecdict-ultimate-sqlite.zip"; + } + + public async void PerformDownload() + { + downloading = true; + + var url = await GetDownloadUrl(); + var path = Path.GetDirectoryName(dictPath); + if (!Directory.Exists(path)) Directory.CreateDirectory(path); + + var client = new WebClient(); + + client.DownloadProgressChanged += delegate (object sender, DownloadProgressChangedEventArgs e) + { + downloadPercentage = e.ProgressPercentage; + }; + + var tmpDictFileLoc = dictPath + ".download"; + await client.DownloadFileTaskAsync(new Uri(url), tmpDictFileLoc).ConfigureAwait(false); + + await Task.Run(() => ZipFile.ExtractToDirectory(tmpDictFileLoc, Path.GetDirectoryName(dictPath))); + + File.Delete(tmpDictFileLoc); + + downloading = false; + } + + public List HandleQuery(Query query) + { + if (downloading) + { + var progress = ""; + if (downloadPercentage != 0) progress = $"{progress} %"; + return new List { new Result() { + Title = $"Downloading dictionary database... {progress}", + SubTitle = "Press enter to refresh precentage.", + IcoPath = "Images\\plugin.png", + Action = (e) => { + context.API.ChangeQuery("d downloading" + new string('.',new Random().Next(0,10))); + return false; + } + }}; + } + else + { + return new List { new Result() { + Title = "Dictionary database not found (~1GB Decompressed)", + SubTitle = $"Press enter to download to {dictPath} (~230MB)", + IcoPath = "Images\\plugin.png", + Action = (e) => + { + if(!downloading) PerformDownload(); + context.API.ChangeQuery("d downloading"); + return false; + } + }}; + } + } + + public bool NeedsDownload() + { + return !File.Exists(dictPath); + } + } +} diff --git a/src/Dictionary.cs b/src/Dictionary.cs index 527a010..a82ba91 100644 --- a/src/Dictionary.cs +++ b/src/Dictionary.cs @@ -22,8 +22,11 @@ public class Main : IPlugin, ISettingProvider, IResultUpdated private Iciba iciba; private PluginInitContext context; private Settings settings; + private DictDownloadManager dictDownloadManager; //private SpeechSynthesizer synth; + private string ecdictLocation = Environment.ExpandEnvironmentVariables(@"%LocalAppData%\Flow.Dictionary\ultimate.db"); + // These two are only for jumping in MakeResultItem private string ActionWord; private string QueryWord; @@ -49,7 +52,7 @@ public void Init(PluginInitContext context) settings = new Settings(); settings.ConfigFile = ConfigFile; - ecdict = new ECDict(CurrentPath + "/dicts/ecdict.db"); + dictDownloadManager = new DictDownloadManager(ecdictLocation, context); wordCorrection = new WordCorrection(CurrentPath + "/dicts/frequency_dictionary_en_82_765.txt", settings.MaxEditDistance); synonyms = new Synonyms(settings.BighugelabsToken); iciba = new Iciba(settings.ICIBAToken); @@ -297,11 +300,16 @@ private bool IsChinese(string cn) public List Query(Query query) { + if (dictDownloadManager.NeedsDownload()) + return dictDownloadManager.HandleQuery(query); + ActionWord = query.ActionKeyword; string queryWord = query.Search; if (queryWord == "") return new List(); QueryWord = queryWord; + if (ecdict == null) ecdict = new ECDict(ecdictLocation); + if (queryWord.Length < 2) return FirstLevelQuery(query); diff --git a/src/ECDict.cs b/src/ECDict.cs index 62255f2..d0e754a 100644 --- a/src/ECDict.cs +++ b/src/ECDict.cs @@ -1,22 +1,27 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Data; using System.Data.SQLite; using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.Text.RegularExpressions; namespace Dictionary { class ECDict { readonly SQLiteConnection conn; + Regex stripWord = new Regex("[^a-zA-Z0-9]"); + public ECDict(string filename) { conn = new SQLiteConnection("Data Source=" + filename + ";Version=3;"); conn.Open(); } + public string StripWord(string word) + { + return stripWord.Replace(word.Trim().ToLower(), ""); + } + // This will only return exact match. // Return null if not found. public Word Query(string word) @@ -38,11 +43,11 @@ public Word Query(string word) public IEnumerable QueryRange(IEnumerable words) { - string queryTerms = string.Join(',', words.Select(w => $"'{w.term}'")); + string queryTerms = string.Join(',', words.Select(w => $"'{StripWord(w.term)}'")); if (queryTerms.Length == 0) yield break; - string sql = $"select * from stardict where word in ({queryTerms})"; + string sql = $"select * from stardict where sw in ({queryTerms})"; using SQLiteCommand cmd = new SQLiteCommand(sql, conn); @@ -56,9 +61,10 @@ public IEnumerable QueryRange(IEnumerable words) // This will include exact match and words beginning with it public IEnumerable QueryBeginningWith(string word, int limit = 20) { + word = StripWord(word); if (word.Length == 0) yield break; - string sql = "select * from stardict where word like '" + word + + string sql = "select * from stardict where sw like '" + word + "%' order by frq > 0 desc, frq asc limit " + limit; using SQLiteCommand cmd = new SQLiteCommand(sql, conn); From c66f7ac1db9a39352662632fa5375ad713afaa39 Mon Sep 17 00:00:00 2001 From: Harry Yu Date: Sat, 6 Feb 2021 17:38:39 +0800 Subject: [PATCH 2/3] move config file --- src/Dictionary.cs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/Dictionary.cs b/src/Dictionary.cs index b632b7d..5201ce8 100644 --- a/src/Dictionary.cs +++ b/src/Dictionary.cs @@ -28,6 +28,7 @@ public class Main : IAsyncPlugin, ISettingProvider, IResultUpdated //private SpeechSynthesizer synth; private string ecdictLocation = Environment.ExpandEnvironmentVariables(@"%LocalAppData%\Flow.Dictionary\ultimate.db"); + private string configLocation = Environment.ExpandEnvironmentVariables(@"%AppData%\FlowLauncher\Settings\Plugins\Flow.Dictionary\config.json"); // These two are only for jumping in MakeResultItem private string ActionWord; @@ -44,15 +45,13 @@ public async Task InitAsync(PluginInitContext context) { string CurrentPath = context.CurrentPluginMetadata.PluginDirectory; - if (!Directory.Exists(Path.Combine(CurrentPath, "config"))) - Directory.CreateDirectory(Path.Combine(CurrentPath, "config")); + Directory.CreateDirectory(Path.GetDirectoryName(configLocation)); - string ConfigFile = CurrentPath + "/config/config.json"; - if (File.Exists(ConfigFile)) - settings = await JsonSerializer.DeserializeAsync(File.OpenRead(ConfigFile)).ConfigureAwait(false); + if (File.Exists(configLocation)) + settings = await JsonSerializer.DeserializeAsync(File.OpenRead(configLocation)).ConfigureAwait(false); else settings = new Settings(); - settings.ConfigFile = ConfigFile; + settings.ConfigFile = configLocation; dictDownloadManager = new DictDownloadManager(ecdictLocation, context); wordCorrection = new WordCorrection(CurrentPath + "/dicts/frequency_dictionary_en_82_765.txt", settings.MaxEditDistance); From 14bd072aa2de6c1286b39e3035dad3d62e038de5 Mon Sep 17 00:00:00 2001 From: Harry Yu Date: Sat, 6 Feb 2021 18:12:35 +0800 Subject: [PATCH 3/3] fix --- generate_dist.bat | 17 ----------------- src/DictDownloadManager.cs | 2 +- src/Settings.cs | 14 +++++++------- 3 files changed, 8 insertions(+), 25 deletions(-) delete mode 100644 generate_dist.bat diff --git a/generate_dist.bat b/generate_dist.bat deleted file mode 100644 index 7824af0..0000000 --- a/generate_dist.bat +++ /dev/null @@ -1,17 +0,0 @@ -@echo off - -IF NOT EXIST dicts\ecdict.db echo Dictionary file missing. It may not work. Please download it! -mkdir dist -mkdir dist\config -mkdir dist\x64 -mkdir dist\x86 -mkdir dist\Images -xcopy dicts dist\dicts /i /s /y -copy Images\plugin.png dist\Images -copy bin\Release\Dictionary.dll dist -copy bin\Release\Newtonsoft.Json.dll dist -copy bin\Release\x64\SQLite.Interop.dll dist\x64\ -copy bin\Release\x86\SQLite.Interop.dll dist\x86\ -copy bin\Release\System.Data.SQLite.dll dist -copy plugin.json dist -pause \ No newline at end of file diff --git a/src/DictDownloadManager.cs b/src/DictDownloadManager.cs index c12ce59..8be4369 100644 --- a/src/DictDownloadManager.cs +++ b/src/DictDownloadManager.cs @@ -75,7 +75,7 @@ public async Task> HandleQueryAsync(Query query) if (downloading) { var progress = ""; - if (downloadPercentage != 0) progress = $"{progress} %"; + if (downloadPercentage != 0) progress = $"{downloadPercentage} %"; return new List { new Result() { Title = $"Downloading dictionary database... {progress}", SubTitle = "Press enter to refresh precentage.", diff --git a/src/Settings.cs b/src/Settings.cs index b7f6fab..946f2d4 100644 --- a/src/Settings.cs +++ b/src/Settings.cs @@ -11,15 +11,15 @@ namespace Dictionary public class Settings { public string ConfigFile; - public string ICIBAToken = "BEBC0A981CB63ED5198597D732BD8956"; - public string BighugelabsToken = ""; - public int MaxEditDistance = 3; - public bool ShowEnglishDefinition = false; - public string WordWebsite = ""; + public string ICIBAToken { get; set; } = "BEBC0A981CB63ED5198597D732BD8956"; + public string BighugelabsToken { get; set; } = ""; + public int MaxEditDistance { get; set; } = 3; + public bool ShowEnglishDefinition { get; set; } = false; + public string WordWebsite { get; set; } = ""; - public async void Save() + public void Save() { - await JsonSerializer.SerializeAsync(File.OpenWrite(ConfigFile), this); + File.WriteAllText(ConfigFile, JsonSerializer.Serialize(this)); } } }