├── .github ├── dependabot.yml ├── workflows-bak │ ├── build-macos-x86_64.yaml │ ├── build-windows.yaml │ ├── codeql-analysis.yml │ ├── node-ci.yml │ ├── release-latest.yml │ └── release-macos.yml └── workflows │ └── package-and-release.yaml ├── .gitignore ├── .prettierrc ├── .yarnclean ├── .yarnrc ├── CHANGELOG.md ├── LICENSE ├── Makefile ├── README.md ├── app.go ├── app_inner.go ├── build ├── README.md ├── appicon.png ├── assets │ └── darwin │ │ ├── appicon.icns │ │ ├── appicon.png │ │ ├── dmg_bg.png │ │ ├── dmg_icon.icns │ │ └── dmg_icon.png ├── darwin │ ├── Info.dev.plist │ └── Info.plist └── windows │ ├── icon.ico │ ├── info.json │ ├── installer │ ├── project.nsi │ └── wails_tools.nsh │ └── wails.exe.manifest ├── docs ├── .gitignore ├── 404.html ├── CNAME ├── Gemfile ├── Gemfile.lock ├── LICENSE ├── README.md ├── _assets │ ├── baidu_translate_config.md │ ├── faq.md │ ├── image-20230927112451745.png │ ├── image-20230927112656769.png │ ├── image-20230927113137569.png │ ├── image-20230927113331495-5785613-5785617.png │ ├── image-20230927113331495.png │ ├── index.md │ ├── license.md │ ├── pic_add_dict_btn.jpg │ ├── pic_add_dict_modal.jpg │ ├── pic_dict_window.jpg │ ├── pic_settings_window.jpg │ ├── pic_translate_window.jpg │ ├── pic_usage_step1.jpg │ ├── pic_usage_step2.jpg │ ├── select_and_use_dict.md │ ├── terms_and_service.md │ ├── v3-medict-app-index.png │ ├── youdao_traslate_config.md │ └── zov3hq.png ├── _config.yml ├── _includes │ ├── head-custom-google-analytics.html │ └── head-custom.html ├── _layouts │ ├── default.html │ ├── home.html │ ├── page.html │ └── post.html ├── _posts │ └── 2023-09-24-welcome-to-jekyll.markdown ├── _sass │ ├── jekyll-theme-modernist.scss │ ├── modernist.scss │ └── rouge-base16-dark.scss ├── _scripts │ └── serve.sh ├── about.markdown ├── another-page.md ├── assets │ ├── css │ │ └── style.scss │ ├── images │ │ └── checker.png │ └── js │ │ ├── html5shiv.min.js │ │ └── scale.fix.js ├── docs │ ├── CODE_OF_CONDUCT.md │ ├── CONTRIBUTING.md │ └── SUPPORT.md ├── index.markdown ├── jekyll-theme-modernist.gemspec ├── script │ ├── bootstrap │ ├── cibuild │ ├── release │ └── validate-html └── thumbnail.png ├── frontend ├── .gitignore ├── index.html ├── package.json ├── package.json.md5 ├── pnpm-lock.yaml ├── src │ ├── App.vue │ ├── apis │ │ ├── apis.ts │ │ ├── config.ts │ │ ├── dicts-api.ts │ │ ├── model.ts │ │ └── types.d.ts │ ├── assets │ │ ├── docs │ │ │ ├── about.md │ │ │ ├── faq.md │ │ │ ├── images │ │ │ │ ├── image-20230927112451745.png │ │ │ │ ├── image-20230927112656769.png │ │ │ │ ├── image-20230927113137569.png │ │ │ │ ├── image-20230927113331495-5785613-5785617.png │ │ │ │ ├── image-20230927113331495.png │ │ │ │ └── zov3hq.png │ │ │ ├── index.md │ │ │ ├── license.md │ │ │ ├── select_and_use_dict.md │ │ │ └── terms_and_service.md │ │ └── images │ │ │ ├── docs │ │ │ └── index.png │ │ │ ├── logo-dark.png │ │ │ └── logo.png │ ├── components │ │ ├── layout │ │ │ ├── AppFooter.vue │ │ │ ├── AppFunctions.vue │ │ │ ├── AppHeader.vue │ │ │ ├── AppMainContent.vue │ │ │ ├── AppRightToolbar.vue │ │ │ └── AppSidebar.vue │ │ ├── lazy-iframe │ │ │ └── index.vue │ │ └── setting │ │ │ └── SettingItem.vue │ ├── main.js │ ├── renderer.init.ts │ ├── router │ │ └── index.ts │ ├── settings.ts │ ├── store │ │ ├── StoreDataType.ts │ │ ├── dict │ │ │ └── index.ts │ │ └── ui │ │ │ └── index.ts │ ├── style │ │ ├── photon │ │ │ ├── bars.scss │ │ │ ├── base.scss │ │ │ ├── button-groups.scss │ │ │ ├── buttons.scss │ │ │ ├── docs.scss │ │ │ ├── fonts │ │ │ │ ├── photon-entypo.eot │ │ │ │ ├── photon-entypo.svg │ │ │ │ ├── photon-entypo.ttf │ │ │ │ └── photon-entypo.woff │ │ │ ├── forms.scss │ │ │ ├── grid.scss │ │ │ ├── icons.scss │ │ │ ├── images.scss │ │ │ ├── lists.scss │ │ │ ├── mixins.scss │ │ │ ├── navs.scss │ │ │ ├── normalize.scss │ │ │ ├── photon.scss │ │ │ ├── tables.scss │ │ │ ├── tabs.scss │ │ │ ├── utilities.scss │ │ │ └── variables.scss │ │ ├── renderer.scss │ │ └── variables.scss │ ├── utils │ │ ├── history-stack.ts │ │ ├── index.ts │ │ └── request.ts │ ├── view │ │ ├── about │ │ │ └── index.vue │ │ ├── debug │ │ │ ├── DebugEditDict.vue │ │ │ ├── DebugResourceSearch.vue │ │ │ └── index.vue │ │ ├── dict │ │ │ └── index.vue │ │ ├── docs │ │ │ └── index.vue │ │ ├── main │ │ │ ├── MainContentFrame.vue │ │ │ ├── MainDictsToolbar.vue │ │ │ ├── MainFooter.vue │ │ │ ├── MainFunctions.vue │ │ │ ├── MainRightToolbar.vue │ │ │ ├── MainSidebar.vue │ │ │ └── index.vue │ │ ├── plugins │ │ │ └── index.vue │ │ └── setting │ │ │ ├── SettingDict.vue │ │ │ ├── SettingPlugin.vue │ │ │ ├── SettingSoftware.vue │ │ │ ├── SettingTheme.vue │ │ │ ├── SettingUpdate.vue │ │ │ └── index.vue │ └── vue-shim.d.ts ├── tsconfig.json ├── vite.config.js ├── wailsjs │ ├── go │ │ ├── main │ │ │ ├── App.d.ts │ │ │ └── App.js │ │ └── models.ts │ └── runtime │ │ ├── package.json │ │ ├── runtime.d.ts │ │ └── runtime.js └── yarn.lock ├── go.mod ├── go.sum ├── internal ├── config │ ├── config.go │ ├── config_test.go │ ├── config_tmpl_darwin.go │ ├── config_tmpl_linux.go │ ├── config_tmpl_windows.go │ ├── preset_dict.go │ └── testdata │ │ └── test.toml ├── entry │ ├── app_loader.go │ ├── app_loader_test.go │ ├── app_preset.go │ ├── app_preset_test.go │ └── preset │ │ ├── cc-cedict │ │ ├── cc-cedict.css │ │ ├── cc-cedict.mdd │ │ ├── cc-cedict.mdx │ │ └── cover.png │ │ └── dictd-elements │ │ ├── cover.png │ │ ├── dictd-elements.dict.dz │ │ ├── dictd-elements.idx │ │ └── dictd-elements.ifo ├── libs │ ├── bktree │ │ ├── .gitignore │ │ ├── LICENSE │ │ ├── README.md │ │ ├── _example │ │ │ ├── hamming │ │ │ │ └── main.go │ │ │ └── levenshtein │ │ │ │ └── main.go │ │ ├── bktree.go │ │ └── bktree_test.go │ ├── go-adaptive-radix-tree │ │ ├── .github │ │ │ └── dependabot.yml │ │ ├── .gitignore │ │ ├── .travis.yml │ │ ├── LICENSE │ │ ├── README.md │ │ ├── api.go │ │ ├── consts.go │ │ ├── doc.go │ │ ├── examples │ │ │ └── tree.go │ │ ├── factory.go │ │ ├── makefile │ │ ├── node.go │ │ ├── node_test.go │ │ ├── test │ │ │ └── assets │ │ │ │ ├── hsk_words.txt │ │ │ │ ├── uuid.txt │ │ │ │ └── words.txt │ │ ├── tree.go │ │ ├── tree_dump.go │ │ ├── tree_dump_test.go │ │ ├── tree_test.go │ │ ├── tree_traversal.go │ │ └── utils.go │ ├── go-mdict │ │ ├── .gitignore │ │ ├── mdict.go │ │ ├── mdict_accessor.go │ │ ├── mdict_base.go │ │ ├── mdict_base_test.go │ │ ├── mdict_def.go │ │ ├── mdict_extend.go │ │ ├── mdict_oale9_test.go │ │ ├── mdict_record_range_tree.go │ │ ├── mdict_record_range_tree_test.go │ │ ├── mdict_test.go │ │ ├── util.go │ │ └── xml_dictionary.go │ ├── go-patricia │ │ ├── .gitignore │ │ ├── AUTHORS │ │ ├── LICENSE │ │ ├── README.md │ │ └── patricia │ │ │ ├── children.go │ │ │ ├── patricia.go │ │ │ ├── patricia_dense_test.go │ │ │ ├── patricia_sparse_test.go │ │ │ └── patricia_test.go │ └── go-stardict │ │ ├── .gitignore │ │ ├── LICENSE │ │ ├── README.md │ │ └── stardict │ │ ├── dict.go │ │ ├── idx.go │ │ ├── ifo.go │ │ ├── stardict.go │ │ ├── stardict_test.go │ │ └── testdata │ │ └── stardict │ │ ├── eedic.pdb │ │ ├── eedic.pdb.dict.dz │ │ ├── eedic.pdb.idx │ │ └── eedic.pdb.ifo │ │ └── elements-2.4.2 │ │ ├── elements.dict.dz │ │ ├── elements.idx │ │ └── elements.ifo ├── static │ ├── consts.go │ ├── handler │ │ ├── content_pipeline.go │ │ ├── content_pipeline_test.go │ │ ├── content_test.go │ │ ├── handler.go │ │ ├── handler_font.go │ │ ├── handler_font_test.go │ │ ├── replacer.go │ │ ├── replacer_css.go │ │ ├── replacer_css_test.go │ │ ├── replacer_entry.go │ │ ├── replacer_entry_test.go │ │ ├── replacer_image.go │ │ ├── replacer_image_test.go │ │ ├── replacer_ini.go │ │ ├── replacer_javascript.go │ │ ├── replacer_javascript_test.go │ │ ├── replacer_link.go │ │ ├── replacer_sound.go │ │ └── replacer_sound_test.go │ └── tmpl │ │ ├── dict_def_templ.go │ │ └── dict_desc_templ.go └── utils │ ├── encoding_util.go │ ├── encoding_util_test.go │ ├── hashutil.go │ ├── pathhome_darwin.go │ ├── pathhome_linux.go │ ├── pathhome_windows.go │ └── pathutil.go ├── main.go ├── pkg ├── apis │ ├── dicts_controller.go │ ├── dicts_handler.go │ └── server_api.go ├── backserver │ ├── back_server.go │ └── back_server_inner.go ├── model │ ├── decoder.go │ ├── dict_def.go │ ├── dict_interface.go │ └── response.go └── service │ ├── .gitignore │ ├── dict_item.go │ ├── dict_item_test.go │ ├── dicts_service.go │ ├── dicts_service_test.go │ ├── log.go │ ├── mdict │ ├── leveldb-repo │ │ ├── leveldb.go │ │ └── log.go │ ├── log.go │ ├── mdict-idxer │ │ ├── indexer.go │ │ ├── leveldb_indexer.go │ │ ├── leveldb_indexer_test.go │ │ ├── log.go │ │ ├── search_tree.go │ │ ├── sqlite_indexer.go │ │ ├── sqlite_indexer_test.go │ │ └── testdata │ │ │ ├── .gitignore │ │ │ └── testleveldb │ │ │ ├── 000026.ldb │ │ │ ├── 000027.ldb │ │ │ ├── 000030.ldb │ │ │ ├── CURRENT │ │ │ ├── CURRENT.bak │ │ │ ├── LOCK │ │ │ ├── LOG │ │ │ └── MANIFEST-000032 │ ├── mdict_holder.go │ ├── mdict_holder_test.go │ ├── mdict_svc.go │ └── mdict_svc_test.go │ ├── stardict │ ├── stardict_test.go │ └── startdict.go │ ├── support │ ├── filewalker.go │ ├── filewalker_test.go │ └── testdata │ │ └── dicts │ │ ├── ccedit │ │ ├── ccedit.dz │ │ ├── ccedit.idx │ │ └── ccedit.ifo │ │ ├── mdict-type │ │ ├── dict.license │ │ ├── mdict.toml │ │ ├── test.jpg │ │ ├── test.mdd │ │ └── test.mdx │ │ ├── oale3 │ │ ├── assets │ │ │ └── test.png │ │ ├── dict.license │ │ ├── fonts │ │ │ └── test.ttf │ │ ├── test.mdd │ │ ├── test.mdx │ │ └── test.png │ │ └── startdict-type │ │ └── stardict.toml │ └── testdata │ └── stardict │ ├── cover.png │ ├── eedic.pdb.dict.dz │ ├── eedic.pdb.idx │ └── eedic.pdb.ifo └── wails.json /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: npm 4 | directory: "/" 5 | schedule: 6 | interval: weekly 7 | time: '11:00' 8 | open-pull-requests-limit: 30 9 | target-branch: develop 10 | -------------------------------------------------------------------------------- /.github/workflows-bak/node-ci.yml: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2023 Quan Chen 3 | # 4 | # This program is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | 17 | name: Node CI 18 | on: 19 | push: 20 | branches: 21 | - master 22 | - develop 23 | pull_request: 24 | 25 | defaults: 26 | run: 27 | shell: bash 28 | 29 | jobs: 30 | build: 31 | runs-on: ${{matrix.os}} 32 | env: 33 | BAIDU_APPID: ${{ secrets.BAIDU_APPID }} 34 | BAIDU_APP_KEY: ${{ secrets.BAIDU_APP_KEY }} 35 | strategy: 36 | matrix: 37 | node-version: [12.x] 38 | os: [macos-10.15, ubuntu-latest] 39 | fail-fast: false 40 | steps: 41 | - name: Checkout 42 | uses: actions/checkout@v2 43 | 44 | - name: Create env file 45 | run: | 46 | touch .env 47 | echo BAIDU_APPID=${{ secrets.BAIDU_APPID }} >> .env 48 | echo BAIDU_APP_KEY=${{ secrets.BAIDU_APP_KEY }} >> .env 49 | 50 | - name: Setup Node.js ${{ matrix.node-version }} 51 | uses: actions/setup-node@v1 52 | with: 53 | node-version: ${{ matrix.node-version }} 54 | 55 | - name: Install 56 | run: yarn install 57 | 58 | - name: Test 59 | run: yarn run test -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.vscode/ 2 | # Logs 3 | logs 4 | *.log 5 | npm-debug.log* 6 | yarn-debug.log* 7 | yarn-error.log* 8 | lerna-debug.log* 9 | 10 | # Diagnostic reports (https://nodejs.org/api/report.html) 11 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 12 | 13 | # Runtime data 14 | pids 15 | *.pid 16 | *.seed 17 | *.pid.lock 18 | .DS_Store 19 | 20 | # Directory for instrumented libs generated by jscoverage/JSCover 21 | lib-cov 22 | 23 | # Coverage directory used by tools like istanbul 24 | coverage 25 | *.lcov 26 | 27 | # nyc test coverage 28 | .nyc_output 29 | 30 | # node-waf configuration 31 | .lock-wscript 32 | 33 | # Compiled binary addons (https://nodejs.org/api/addons.html) 34 | build/Release 35 | 36 | # Dependency directories 37 | node_modules/ 38 | jspm_packages/ 39 | 40 | # TypeScript v1 declaration files 41 | typings/ 42 | 43 | # TypeScript cache 44 | *.tsbuildinfo 45 | 46 | # Optional npm cache directory 47 | .npm 48 | 49 | # Optional eslint cache 50 | .eslintcache 51 | 52 | # Optional REPL history 53 | .node_repl_history 54 | 55 | # Output of 'npm pack' 56 | *.tgz 57 | 58 | # Yarn Integrity file 59 | .yarn-integrity 60 | 61 | # dotenv environment variables file 62 | .env 63 | .env.test 64 | 65 | # parcel-bundler cache (https://parceljs.org/) 66 | .cache 67 | 68 | # next.js build output 69 | .next 70 | 71 | # nuxt.js build output 72 | .nuxt 73 | 74 | # vuepress build output 75 | .vuepress/dist 76 | 77 | # Serverless directories 78 | .serverless/ 79 | 80 | # FuseBox cache 81 | .fusebox/ 82 | 83 | # DynamoDB Local files 84 | .dynamodb/ 85 | 86 | # Webpack 87 | .webpack/ 88 | 89 | # Electron-Forge 90 | out/ 91 | 92 | libdict/ 93 | testdict/ 94 | /build/bin/ 95 | .idea 96 | 97 | *.mdx 98 | *.meidx 99 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "es5", 3 | "tabWidth": 2, 4 | "semi": true, 5 | "singleQuote": true, 6 | "lineLength": 200 7 | } -------------------------------------------------------------------------------- /.yarnclean: -------------------------------------------------------------------------------- 1 | # test directories 2 | __tests__ 3 | test 4 | tests 5 | powered-test 6 | 7 | # asset directories 8 | docs 9 | doc 10 | website 11 | images 12 | assets 13 | 14 | # examples 15 | example 16 | examples 17 | 18 | # code coverage directories 19 | coverage 20 | .nyc_output 21 | 22 | # build scripts 23 | Makefile 24 | Gulpfile.js 25 | Gruntfile.js 26 | 27 | # configs 28 | appveyor.yml 29 | circle.yml 30 | codeship-services.yml 31 | codeship-steps.yml 32 | wercker.yml 33 | .tern-project 34 | .gitattributes 35 | .editorconfig 36 | .*ignore 37 | .eslintrc 38 | .jshintrc 39 | .flowconfig 40 | .documentup.json 41 | .yarn-metadata.json 42 | .travis.yml 43 | 44 | # misc 45 | *.md 46 | -------------------------------------------------------------------------------- /.yarnrc: -------------------------------------------------------------------------------- 1 | registry "https://registry.yarnpkg.com" 2 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terasum/medict/138f5198ef0034909f9872ce580bb4fddf31fca9/CHANGELOG.md -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | dev: 2 | wails dev --loglevel info 3 | build: 4 | wails build -devtools 5 | 6 | license: 7 | addlicense -c "Quan Chen " -l gpl3 -v -y 2023 -ignore frontend/**/* -ignore build/**/* -ignore .github/**/* frontend/src 8 | 9 | create-dmg: 10 | create-dmg --volname "Medict" --volicon "build/assets/darwin/dmg_icon.icns" --background "build/assets/darwin/dmg_bg.png" --window-size 512 360 --icon-size 100 --icon "Medict.app" 100 185 --hide-extension "Medict.app" --app-drop-link 388 185 "Medict_3.0.1_Darwin_x86_64.dmg" "build/bin" 11 | 12 | 13 | 14 | .PHONY: build license 15 | -------------------------------------------------------------------------------- /app_inner.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2023 Quan Chen 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | package main 18 | 19 | import ( 20 | "context" 21 | "fmt" 22 | "github.com/wailsapp/wails/v2/pkg/runtime" 23 | ) 24 | 25 | func (b *App) errorChanListen(ctx context.Context) { 26 | for { 27 | select { 28 | case err := <-b.errorChannel: 29 | panicWithErrorMessageDialog(ctx, err) 30 | case <-b.stopChannel: 31 | return 32 | } 33 | } 34 | } 35 | 36 | func (b *App) stopChanListen(ctx context.Context) { 37 | for { 38 | select { 39 | case <-b.stopChannel: 40 | return 41 | } 42 | } 43 | } 44 | 45 | func panicWithErrorMessageDialog(ctx context.Context, err error) { 46 | _, dialogErr := runtime.MessageDialog(ctx, runtime.MessageDialogOptions{ 47 | Title: "Error", 48 | Type: runtime.ErrorDialog, 49 | Message: err.Error(), 50 | Buttons: []string{"OK"}, 51 | DefaultButton: "OK", 52 | }) 53 | if dialogErr != nil { 54 | fmt.Printf("[CRITIC] open dialog error %s\n", dialogErr.Error()) 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /build/README.md: -------------------------------------------------------------------------------- 1 | # Build Directory 2 | 3 | The build directory is used to house all the build files and assets for your application. 4 | 5 | The structure is: 6 | 7 | * bin - Output directory 8 | * dialog - Icons for dialogs 9 | * tray - Icons for the system tray 10 | * mac - MacOS specific files 11 | * linux - Linux specific files 12 | * windows - Windows specific files 13 | 14 | ## Dialog Icons 15 | 16 | Place any PNG file in this directory to be able to use them in message dialogs. 17 | The files should have names in the following format: `name[-(light|dark)][2x].png` 18 | 19 | Examples: 20 | 21 | * `mypic.png` - Standard definition icon with ID `mypic` 22 | * `mypic-light.png` - Standard definition icon with ID `mypic`, used when system theme is light 23 | * `mypic-dark.png` - Standard definition icon with ID `mypic`, used when system theme is dark 24 | * `mypic2x.png` - High definition icon with ID `mypic` 25 | * `mypic-light2x.png` - High definition icon with ID `mypic`, used when system theme is light 26 | * `mypic-dark2x.png` - High definition icon with ID `mypic`, used when system theme is dark 27 | 28 | ### Order of preference 29 | 30 | Icons are selected with the following order of preference: 31 | 32 | For High Definition displays: 33 | * name-(theme)2x.png 34 | * name2x.png 35 | * name-(theme).png 36 | * name.png 37 | 38 | For Standard Definition displays: 39 | * name-(theme).png 40 | * name.png 41 | 42 | ## Tray 43 | 44 | Place any PNG file in this directory to be able to use them as tray icons. 45 | The name of the filename will be the ID to reference the image. 46 | 47 | Example: 48 | 49 | * `mypic.png` - May be referenced using `runtime.Tray.SetIcon("mypic")` 50 | 51 | ## Mac 52 | 53 | The `darwin` directory holds files specific to Mac builds, such as `Info.plist`. 54 | These may be customised and used as part of the build. To return these files to the default state, simply delete them and 55 | build with the `-package` flag. 56 | 57 | ## Windows 58 | 59 | The `windows` directory contains the manifest and rc files used when building with the `-package` flag. 60 | These may be customised for your application. To return these files to the default state, simply delete them and 61 | build with the `-package` flag. -------------------------------------------------------------------------------- /build/appicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terasum/medict/138f5198ef0034909f9872ce580bb4fddf31fca9/build/appicon.png -------------------------------------------------------------------------------- /build/assets/darwin/appicon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terasum/medict/138f5198ef0034909f9872ce580bb4fddf31fca9/build/assets/darwin/appicon.icns -------------------------------------------------------------------------------- /build/assets/darwin/appicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terasum/medict/138f5198ef0034909f9872ce580bb4fddf31fca9/build/assets/darwin/appicon.png -------------------------------------------------------------------------------- /build/assets/darwin/dmg_bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terasum/medict/138f5198ef0034909f9872ce580bb4fddf31fca9/build/assets/darwin/dmg_bg.png -------------------------------------------------------------------------------- /build/assets/darwin/dmg_icon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terasum/medict/138f5198ef0034909f9872ce580bb4fddf31fca9/build/assets/darwin/dmg_icon.icns -------------------------------------------------------------------------------- /build/assets/darwin/dmg_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terasum/medict/138f5198ef0034909f9872ce580bb4fddf31fca9/build/assets/darwin/dmg_icon.png -------------------------------------------------------------------------------- /build/darwin/Info.dev.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | CFBundlePackageType 5 | APPL 6 | CFBundleName 7 | {{.Info.ProductName}} 8 | CFBundleExecutable 9 | {{.Name}} 10 | CFBundleIdentifier 11 | com.wails.{{.Name}} 12 | CFBundleVersion 13 | {{.Info.ProductVersion}} 14 | CFBundleGetInfoString 15 | {{.Info.Comments}} 16 | CFBundleShortVersionString 17 | {{.Info.ProductVersion}} 18 | CFBundleIconFile 19 | iconfile 20 | LSMinimumSystemVersion 21 | 10.13.0 22 | NSHighResolutionCapable 23 | true 24 | NSHumanReadableCopyright 25 | {{.Info.Copyright}} 26 | NSAppTransportSecurity 27 | 28 | NSAllowsLocalNetworking 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /build/darwin/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | CFBundlePackageTypeAPPL 4 | CFBundleName{{.Info.ProductName}} 5 | CFBundleExecutable{{.Name}} 6 | CFBundleIdentifiercom.wails.{{.Name}} 7 | CFBundleVersion{{.Info.ProductVersion}} 8 | CFBundleGetInfoString{{.Info.Comments}} 9 | CFBundleShortVersionString{{.Info.ProductVersion}} 10 | CFBundleIconFileiconfile 11 | LSMinimumSystemVersion10.13.0 12 | NSHighResolutionCapabletrue 13 | NSHumanReadableCopyright{{.Info.Copyright}} 14 | -------------------------------------------------------------------------------- /build/windows/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terasum/medict/138f5198ef0034909f9872ce580bb4fddf31fca9/build/windows/icon.ico -------------------------------------------------------------------------------- /build/windows/info.json: -------------------------------------------------------------------------------- 1 | { 2 | "fixed": { 3 | "file_version": "{{.Info.ProductVersion}}" 4 | }, 5 | "info": { 6 | "0000": { 7 | "ProductVersion": "{{.Info.ProductVersion}}", 8 | "CompanyName": "{{.Info.CompanyName}}", 9 | "FileDescription": "{{.Info.ProductName}}", 10 | "LegalCopyright": "{{.Info.Copyright}}", 11 | "ProductName": "{{.Info.ProductName}}", 12 | "Comments": "{{.Info.Comments}}" 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /build/windows/wails.exe.manifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | true/pm 12 | permonitorv2,permonitor 13 | 14 | 15 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | _site 2 | .sass-cache 3 | .jekyll-cache 4 | .jekyll-metadata 5 | vendor 6 | -------------------------------------------------------------------------------- /docs/404.html: -------------------------------------------------------------------------------- 1 | --- 2 | permalink: /404.html 3 | layout: default 4 | --- 5 | 6 | 19 | 20 |
21 |

404

22 | 23 |

Page not found :(

24 |

The requested page could not be found.

25 |
26 | -------------------------------------------------------------------------------- /docs/CNAME: -------------------------------------------------------------------------------- 1 | medict.chenquan.me -------------------------------------------------------------------------------- /docs/Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | # Hello! This is where you manage which Jekyll version is used to run. 3 | # When you want to use a different version, change it below, save the 4 | # file and run `bundle install`. Run Jekyll with `bundle exec`, like so: 5 | # 6 | # bundle exec jekyll serve 7 | # 8 | # This will help ensure the proper Jekyll version is running. 9 | # Happy Jekylling! 10 | # gem "jekyll", "~> 4.3.2" 11 | # This is the default theme for new Jekyll sites. You may change this to anything you like. 12 | # gem "minima", "~> 2.5" 13 | # If you want to use GitHub Pages, remove the "gem "jekyll"" above and 14 | # uncomment the line below. To upgrade, run `bundle update github-pages`. 15 | gem "github-pages", group: :jekyll_plugins 16 | # If you have any plugins, put them here! 17 | group :jekyll_plugins do 18 | gem "jekyll-feed", "~> 0.12" 19 | end 20 | 21 | # Windows and JRuby does not include zoneinfo files, so bundle the tzinfo-data gem 22 | # and associated library. 23 | platforms :mingw, :x64_mingw, :mswin, :jruby do 24 | gem "tzinfo", ">= 1", "< 3" 25 | gem "tzinfo-data" 26 | end 27 | 28 | # Performance-booster for watching directories on Windows 29 | gem "wdm", "~> 0.1.1", :platforms => [:mingw, :x64_mingw, :mswin] 30 | 31 | # Lock `http_parser.rb` gem to `v0.6.x` on JRuby builds since newer versions of the gem 32 | # do not have a Java counterpart. 33 | gem "http_parser.rb", "~> 0.6.0", :platforms => [:jruby] 34 | 35 | gem "webrick", "~> 1.8" 36 | -------------------------------------------------------------------------------- /docs/_assets/baidu_translate_config.md: -------------------------------------------------------------------------------- 1 | # Baidu 翻译 API申请与配置 -------------------------------------------------------------------------------- /docs/_assets/faq.md: -------------------------------------------------------------------------------- 1 | # FAQ 2 | 3 | ### 发音问题 4 | 5 | 目前 oale8 词典这种内嵌发音按钮的,将音频资源嵌入在 mdd 文件中的词典是可以支持发音的,但是目前采用的是 js 替换的方式完成,不一定适用于所有词典,需要 case by case 调试 6 | 7 | ### 跳转问题 8 | 9 | 目前有两种跳转: 10 | 11 | 1. @@Link 的跳转,自动跳转,但是如果出现跳转环路,会停止跳转,直接展示 @@Link== 12 | 2. 内部跳转即 `` 的方式,如果 entry 中间是完整词条,可以支持跳转,如果是特殊词条,目前还不支持 13 | -------------------------------------------------------------------------------- /docs/_assets/image-20230927112451745.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terasum/medict/138f5198ef0034909f9872ce580bb4fddf31fca9/docs/_assets/image-20230927112451745.png -------------------------------------------------------------------------------- /docs/_assets/image-20230927112656769.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terasum/medict/138f5198ef0034909f9872ce580bb4fddf31fca9/docs/_assets/image-20230927112656769.png -------------------------------------------------------------------------------- /docs/_assets/image-20230927113137569.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terasum/medict/138f5198ef0034909f9872ce580bb4fddf31fca9/docs/_assets/image-20230927113137569.png -------------------------------------------------------------------------------- /docs/_assets/image-20230927113331495-5785613-5785617.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terasum/medict/138f5198ef0034909f9872ce580bb4fddf31fca9/docs/_assets/image-20230927113331495-5785613-5785617.png -------------------------------------------------------------------------------- /docs/_assets/image-20230927113331495.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terasum/medict/138f5198ef0034909f9872ce580bb4fddf31fca9/docs/_assets/image-20230927113331495.png -------------------------------------------------------------------------------- /docs/_assets/index.md: -------------------------------------------------------------------------------- 1 | # Medict 界面介绍 2 | 3 | Medict 是一个跨平台的词典 APP, 主要支持 \*.mdx/\*.mdd 词典格式, 目前支持 v1.x 和 v2.0 格式的词典。 4 | 5 | ## 下载与更新 6 | 7 | 目前 Medict 正在紧张开发阶段,版本为自动打包滚动发布,请自行到 https://github.com/terasum/medict/releases 页面寻找最新开发版本, 所有版本均有打包日期,选择最新版本即可。 8 | 9 | ## 界面概览 10 | 11 | 软件目前包括 “词典”,“翻译”,“插件”,“设置” 四个界面,其中“插件”目前尚在开发当中。 12 | 13 | ### 词典界面 14 | 15 | 词典界面 16 | 17 | ### 翻译界面 18 | 19 | 翻译界面 20 | 21 | ### 设置界面 22 | 23 | 设置界面 24 | 25 | -------------------------------------------------------------------------------- /docs/_assets/license.md: -------------------------------------------------------------------------------- 1 | # 软件开源协议信息 2 | 3 | ``` 4 | Copyright 2019-2021 terasum (Chen Quan) 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 7 | 8 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 9 | 10 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 11 | ``` -------------------------------------------------------------------------------- /docs/_assets/pic_add_dict_btn.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terasum/medict/138f5198ef0034909f9872ce580bb4fddf31fca9/docs/_assets/pic_add_dict_btn.jpg -------------------------------------------------------------------------------- /docs/_assets/pic_add_dict_modal.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terasum/medict/138f5198ef0034909f9872ce580bb4fddf31fca9/docs/_assets/pic_add_dict_modal.jpg -------------------------------------------------------------------------------- /docs/_assets/pic_dict_window.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terasum/medict/138f5198ef0034909f9872ce580bb4fddf31fca9/docs/_assets/pic_dict_window.jpg -------------------------------------------------------------------------------- /docs/_assets/pic_settings_window.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terasum/medict/138f5198ef0034909f9872ce580bb4fddf31fca9/docs/_assets/pic_settings_window.jpg -------------------------------------------------------------------------------- /docs/_assets/pic_translate_window.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terasum/medict/138f5198ef0034909f9872ce580bb4fddf31fca9/docs/_assets/pic_translate_window.jpg -------------------------------------------------------------------------------- /docs/_assets/pic_usage_step1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terasum/medict/138f5198ef0034909f9872ce580bb4fddf31fca9/docs/_assets/pic_usage_step1.jpg -------------------------------------------------------------------------------- /docs/_assets/pic_usage_step2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terasum/medict/138f5198ef0034909f9872ce580bb4fddf31fca9/docs/_assets/pic_usage_step2.jpg -------------------------------------------------------------------------------- /docs/_assets/select_and_use_dict.md: -------------------------------------------------------------------------------- 1 | # 词典配置与使用说明 2 | 3 | ## 步骤1: 添加词典 4 | 5 | 1. 点击右上角设置 6 | 2. 点击下方 "+" 号 7 | 8 | pic_add_dict_btn.jpg 9 | 10 | 3. 在弹出框中填写词典信息 11 | 4. 选择词典文件 12 | 13 | 14 | pic_add_dict_modal.jpg 15 | 16 | **注意:** mdx文件所在的文件夹中的js/css/font文件均会被拷贝到缓存文件夹中,请把一个独立词典放在一个独立的文件夹中,并将相关资源放在一起。 17 | 18 | **注意:** mdx/mdd 本身不会被拷贝,删除之后,词典将无法找到该mdx文件 19 | 20 | 21 | ## 步骤 2: 查词 22 | 23 | 1. 选择词典并输入目标词(模糊) 24 | 25 | pic_usage_step1.jpg 26 | 27 | 2. 在左边栏选择你想要查的具体词汇, 如果该词汇和其他词汇同一个意思(即@@Link==) 则直接展示该同意义词汇 28 | 29 | pic_usage_step2.jpg 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /docs/_assets/terms_and_service.md: -------------------------------------------------------------------------------- 1 | # 免责与隐私保护声明 2 | 3 | 本免责及隐私保护声明(以下简称“隐私声明”或“本声明”)适用于软件 Medict (以下简称 "Medict" ) 在您阅读本声明后若不同意此声明中的任何条款,或对本声明存在质疑,请立刻停止使用本软件。若您已经开始或正在使用 Medict 软件,则表示您已阅读并同意本声明的所有条款之约定。 4 | 5 | 1. 您通过安装 Medict 软件并使用 Medict 软件提供的服务与功能即表示您已经同意与软件作者立本协议。软件作者可随时执行全权决定更改“条款”。如“条款”有任何变更,软件官方发布网站 (https://github.com/terasum/medict) 上刊载公告作为通知。经修订的“条款”一经在官方网站上公布后,立即自动生效。 6 | 7 | 2. 一切因使用 Medict 软件而引致之任何意外、疏忽、合约毁坏、诽谤、版权或知识产权侵犯及其所造成的损失(包括在非官方站点下载Medict 软件而感染电脑病毒),软件作者概不负责,亦不承担任何法律责任。 8 | 9 | 3. 用户对使用 Medict 软件自行承担风险,我们不做任何形式的保证, 因网络状况、通讯线路等任何技术原因而导致用户不能正常升级更新,作者也不承担任何法律责任。 10 | 11 | 4. Medict 软件尊重并保护所有用户的个人隐私权,不会窃取任何用户计算机中的信息, 亦不会将用户文件上载至互联网服务器。 12 | 13 | 5. Medict 以 MIT 协议发布, 软件著作权属软件作者所有。 -------------------------------------------------------------------------------- /docs/_assets/v3-medict-app-index.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terasum/medict/138f5198ef0034909f9872ce580bb4fddf31fca9/docs/_assets/v3-medict-app-index.png -------------------------------------------------------------------------------- /docs/_assets/youdao_traslate_config.md: -------------------------------------------------------------------------------- 1 | # 有道翻译 API申请与配置 -------------------------------------------------------------------------------- /docs/_assets/zov3hq.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terasum/medict/138f5198ef0034909f9872ce580bb4fddf31fca9/docs/_assets/zov3hq.png -------------------------------------------------------------------------------- /docs/_includes/head-custom-google-analytics.html: -------------------------------------------------------------------------------- 1 | {% if site.google_analytics %} 2 | 10 | {% endif %} 11 | -------------------------------------------------------------------------------- /docs/_includes/head-custom.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {% include head-custom-google-analytics.html %} 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /docs/_layouts/default.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | {% seo %} 8 | 9 | 10 | 11 | 12 | 13 | 16 | 17 | {% include head-custom.html %} 18 | 19 | 20 | 42 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /docs/_layouts/home.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | {% seo %} 8 | 9 | 10 | 11 | 12 | 13 | 16 | 17 | {% include head-custom.html %} 18 | 19 | 20 |
21 |
22 |

{{ site.title | default: site.github.repository_name }}

23 | {% if site.description or site.github.project_tagline %} 24 |

{{ site.description | default: site.github.project_tagline }}

25 | {% endif %} 26 |

View the Project on GitHub {{ github_name }}

27 | 35 |
36 |
37 | 38 | {{ content }} 39 | 40 |
41 |
42 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /docs/_layouts/page.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | {% seo %} 8 | 9 | 10 | 11 | 12 | 13 | 16 | 17 | {% include head-custom.html %} 18 | 19 | 20 |
21 |
22 |

{{ site.title | default: site.github.repository_name }}

23 | {% if site.description or site.github.project_tagline %} 24 |

{{ site.description | default: site.github.project_tagline }}

25 | {% endif %} 26 |

View the Project on GitHub {{ github_name }}

27 | 34 |
35 |
36 | 37 | {{ content }} 38 | 39 |
40 |
41 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /docs/_layouts/post.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | {% seo %} 8 | 9 | 10 | 11 | 12 | 13 | 16 | 17 | {% include head-custom.html %} 18 | 19 | 20 |
21 |
22 |

{{ site.title | default: site.github.repository_name }}

23 | {% if site.description or site.github.project_tagline %} 24 |

{{ site.description | default: site.github.project_tagline }}

25 | {% endif %} 26 |

View the Project on GitHub {{ github_name }}

27 | 34 |
35 |
36 | 37 | {{ content }} 38 | 39 |
40 |
41 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /docs/_posts/2023-09-24-welcome-to-jekyll.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | layout: post 3 | title: "Welcome to Medict!" 4 | date: 2023-09-24 12:14:29 +0800 5 | categories: jekyll update 6 | --- 7 | You’ll find this post in your `_posts` directory. Go ahead and edit it and re-build the site to see your changes. You can rebuild the site in many different ways, but the most common way is to run `jekyll serve`, which launches a web server and auto-regenerates your site when a file is updated. 8 | 9 | Jekyll requires blog post files to be named according to the following format: 10 | 11 | `YEAR-MONTH-DAY-title.MARKUP` 12 | 13 | Where `YEAR` is a four-digit number, `MONTH` and `DAY` are both two-digit numbers, and `MARKUP` is the file extension representing the format used in the file. After that, include the necessary front matter. Take a look at the source for this post to get an idea about how it works. 14 | 15 | Jekyll also offers powerful support for code snippets: 16 | 17 | {% highlight ruby %} 18 | def print_hi(name) 19 | puts "Hi, #{name}" 20 | end 21 | print_hi('Tom') 22 | #=> prints 'Hi, Tom' to STDOUT. 23 | {% endhighlight %} 24 | 25 | Check out the [Jekyll docs][jekyll-docs] for more info on how to get the most out of Jekyll. File all bugs/feature requests at [Jekyll’s GitHub repo][jekyll-gh]. If you have questions, you can ask them on [Jekyll Talk][jekyll-talk]. 26 | 27 | [jekyll-docs]: https://jekyllrb.com/docs/home 28 | [jekyll-gh]: https://github.com/jekyll/jekyll 29 | [jekyll-talk]: https://talk.jekyllrb.com/ 30 | -------------------------------------------------------------------------------- /docs/_sass/modernist.scss: -------------------------------------------------------------------------------- 1 | // Placeholder file. If your site uses 2 | // @import "{{ site.theme }}"; 3 | // Then using this theme with jekyll-remote-theme will work fine. 4 | @import "jekyll-theme-modernist"; 5 | -------------------------------------------------------------------------------- /docs/_sass/rouge-base16-dark.scss: -------------------------------------------------------------------------------- 1 | /* 2 | generated by rouge http://rouge.jneen.net/ 3 | original base16 by Chris Kempson (https://github.com/chriskempson/base16) 4 | */ 5 | 6 | .highlight table td { padding: 5px; } 7 | .highlight table pre { margin: 0; } 8 | .highlight, .highlight .w { 9 | color: #d0d0d0; 10 | } 11 | .highlight .err { 12 | color: #151515; 13 | background-color: #ac4142; 14 | } 15 | .highlight .c, .highlight .cd, .highlight .cm, .highlight .c1, .highlight .cs { 16 | color: #888; 17 | } 18 | .highlight .cp { 19 | color: #f4bf75; 20 | } 21 | .highlight .nt { 22 | color: #f4bf75; 23 | } 24 | .highlight .o, .highlight .ow { 25 | color: #d0d0d0; 26 | } 27 | .highlight .p, .highlight .pi { 28 | color: #d0d0d0; 29 | } 30 | .highlight .gi { 31 | color: #90a959; 32 | } 33 | .highlight .gd { 34 | color: #ac4142; 35 | } 36 | .highlight .gh { 37 | color: #6a9fb5; 38 | font-weight: bold; 39 | } 40 | .highlight .k, .highlight .kn, .highlight .kp, .highlight .kr, .highlight .kv { 41 | color: #aa759f; 42 | } 43 | .highlight .kc { 44 | color: #d28445; 45 | } 46 | .highlight .kt { 47 | color: #d28445; 48 | } 49 | .highlight .kd { 50 | color: #d28445; 51 | } 52 | .highlight .s, .highlight .sb, .highlight .sc, .highlight .sd, .highlight .s2, .highlight .sh, .highlight .sx, .highlight .s1 { 53 | color: #90a959; 54 | } 55 | .highlight .sr { 56 | color: #75b5aa; 57 | } 58 | .highlight .si { 59 | color: #8f5536; 60 | } 61 | .highlight .se { 62 | color: #8f5536; 63 | } 64 | .highlight .nn { 65 | color: #f4bf75; 66 | } 67 | .highlight .nc { 68 | color: #f4bf75; 69 | } 70 | .highlight .no { 71 | color: #f4bf75; 72 | } 73 | .highlight .na { 74 | color: #6a9fb5; 75 | } 76 | .highlight .m, .highlight .mf, .highlight .mh, .highlight .mi, .highlight .il, .highlight .mo, .highlight .mb, .highlight .mx { 77 | color: #90a959; 78 | } 79 | .highlight .ss { 80 | color: #90a959; 81 | } 82 | -------------------------------------------------------------------------------- /docs/_scripts/serve.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | bundle exec jekyll serve 3 | -------------------------------------------------------------------------------- /docs/about.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | layout: page 3 | title: About 4 | permalink: /about/ 5 | --- 6 | 7 | This is the base Jekyll theme. You can find out more info about customizing your Jekyll theme, as well as basic Jekyll usage documentation at [jekyllrb.com](https://jekyllrb.com/) 8 | 9 | You can find the source code for Minima at GitHub: 10 | [jekyll][jekyll-organization] / 11 | [minima](https://github.com/jekyll/minima) 12 | 13 | You can find the source code for Jekyll at GitHub: 14 | [jekyll][jekyll-organization] / 15 | [jekyll](https://github.com/jekyll/jekyll) 16 | 17 | 18 | [jekyll-organization]: https://github.com/jekyll 19 | -------------------------------------------------------------------------------- /docs/another-page.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | --- 4 | 5 | ## Welcome to another page 6 | 7 | _yay_ 8 | 9 | [back](./) 10 | -------------------------------------------------------------------------------- /docs/assets/css/style.scss: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | 4 | @import "jekyll-theme-modernist"; 5 | -------------------------------------------------------------------------------- /docs/assets/images/checker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terasum/medict/138f5198ef0034909f9872ce580bb4fddf31fca9/docs/assets/images/checker.png -------------------------------------------------------------------------------- /docs/assets/js/scale.fix.js: -------------------------------------------------------------------------------- 1 | fixScale = function(doc) { 2 | 3 | var addEvent = 'addEventListener', 4 | type = 'gesturestart', 5 | qsa = 'querySelectorAll', 6 | scales = [1, 1], 7 | meta = qsa in doc ? doc[qsa]('meta[name=viewport]') : []; 8 | 9 | function fix() { 10 | meta.content = 'width=device-width,minimum-scale=' + scales[0] + ',maximum-scale=' + scales[1]; 11 | doc.removeEventListener(type, fix, true); 12 | } 13 | 14 | if ((meta = meta[meta.length - 1]) && addEvent in doc) { 15 | fix(); 16 | scales = [.25, 1.6]; 17 | doc[addEvent](type, fix, true); 18 | } 19 | 20 | }; -------------------------------------------------------------------------------- /docs/docs/SUPPORT.md: -------------------------------------------------------------------------------- 1 | ## Where to get help 2 | 3 | If you think you've found a bug in the Modernist theme, please [check the existing issues](https://github.com/pages-themes/modernist/issues), and if no one has reported the problem, [open a new issue](https://github.com/pages-themes/modernist/issues/new). 4 | 5 | If you have a general question about the theme, how to implement it, or how to customize it for your site you have two options: 6 | 7 | 1. Search for your query on [`support.github.com`](https://support.github.com/?q=pages+Modernist+theme), which will also look for similar topics on [`github.community`](https://github.community/search?q=pages+Modernist+theme) 8 | 2. Ask your question of the Jekyll community on [talk.jekyllrb.com](https://talk.jekyllrb.com/) 9 | 3. [Contact GitHub Support](https://github.com/contact?form%5Bsubject%5D=GitHub%20Pages%20theme%20pages-themes/modernist) 10 | -------------------------------------------------------------------------------- /docs/jekyll-theme-modernist.gemspec: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | Gem::Specification.new do |s| 4 | s.name = "jekyll-theme-modernist" 5 | s.version = "0.2.0" 6 | s.license = "CC0-1.0" 7 | s.authors = ["Steve Smith", "GitHub, Inc."] 8 | s.email = ["opensource+jekyll-theme-modernist@github.com"] 9 | s.homepage = "https://github.com/pages-themes/modernist" 10 | s.summary = "Modernist is a Jekyll theme for GitHub Pages" 11 | 12 | s.files = `git ls-files -z`.split("\x0").select do |f| 13 | f.match(%r{^((_includes|_layouts|_sass|assets)/|(LICENSE|README)((\.(txt|md|markdown)|$)))}i) 14 | end 15 | 16 | s.required_ruby_version = ">= 2.4.0" 17 | 18 | s.platform = Gem::Platform::RUBY 19 | s.add_runtime_dependency "jekyll", "> 3.5", "< 5.0" 20 | s.add_runtime_dependency "jekyll-seo-tag", "~> 2.0" 21 | s.add_development_dependency "html-proofer", "~> 3.0" 22 | s.add_development_dependency "rubocop-github", "~> 0.16" 23 | s.add_development_dependency "w3c_validators", "~> 1.3" 24 | end 25 | -------------------------------------------------------------------------------- /docs/script/bootstrap: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | gem install bundler 6 | bundle install 7 | -------------------------------------------------------------------------------- /docs/script/cibuild: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | bundle exec jekyll build 6 | bundle exec htmlproofer ./_site --check-html --check-sri 7 | bundle exec rubocop -D --config .rubocop.yml 8 | bundle exec script/validate-html 9 | gem build jekyll-theme-modernist.gemspec 10 | -------------------------------------------------------------------------------- /docs/script/release: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Tag and push a release. 3 | 4 | set -e 5 | 6 | # Make sure we're in the project root. 7 | 8 | cd $(dirname "$0")/.. 9 | 10 | # Make sure the darn thing works 11 | 12 | bundle update 13 | 14 | # Build a new gem archive. 15 | 16 | rm -rf jekyll-theme-modernist-*.gem 17 | gem build -q jekyll-theme-modernist.gemspec 18 | 19 | # Make sure we're on the master branch. 20 | 21 | (git branch | grep -q 'master') || { 22 | echo "Only release from the master branch." 23 | exit 1 24 | } 25 | 26 | # Figure out what version we're releasing. 27 | 28 | tag=v`ls jekyll-theme-modernist-*.gem | sed 's/^jekyll-theme-modernist-\(.*\)\.gem$/\1/'` 29 | 30 | # Make sure we haven't released this version before. 31 | 32 | git fetch -t origin 33 | 34 | (git tag -l | grep -q "$tag") && { 35 | echo "Whoops, there's already a '${tag}' tag." 36 | exit 1 37 | } 38 | 39 | # Tag it and bag it. 40 | 41 | gem push jekyll-theme-modernist-*.gem && git tag "$tag" && 42 | git push origin master && git push origin "$tag" 43 | -------------------------------------------------------------------------------- /docs/script/validate-html: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | require "w3c_validators" 5 | 6 | def validator(file) 7 | extension = File.extname(file) 8 | if extension == ".html" 9 | W3CValidators::NuValidator.new 10 | elsif extension == ".css" 11 | W3CValidators::CSSValidator.new 12 | end 13 | end 14 | 15 | def validate(file) 16 | puts "Checking #{file}..." 17 | 18 | path = File.expand_path "../_site/#{file}", __dir__ 19 | results = validator(file).validate_file(path) 20 | 21 | return puts "Valid!" if results.errors.empty? 22 | 23 | results.errors.each { |err| puts err.to_s } 24 | exit 1 25 | end 26 | 27 | validate "index.html" 28 | validate File.join "assets", "css", "style.css" 29 | -------------------------------------------------------------------------------- /docs/thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terasum/medict/138f5198ef0034909f9872ce580bb4fddf31fca9/docs/thumbnail.png -------------------------------------------------------------------------------- /frontend/.gitignore: -------------------------------------------------------------------------------- 1 | /dist 2 | /node_modules 3 | -------------------------------------------------------------------------------- /frontend/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | medict 7 | 8 | 9 |
10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "frontend", 3 | "private": true, 4 | "version": "1.0.0", 5 | "scripts": { 6 | "dev": "vite", 7 | "build": "vite build", 8 | "preview": "vite preview" 9 | }, 10 | "type": "module", 11 | "dependencies": { 12 | "axios": "^1.8.2", 13 | "normalize.css": "^8.0.1", 14 | "pinia": "^2.1.6", 15 | "uuid": "^9.0.0", 16 | "vue": "^3.3.4", 17 | "vue-friendly-iframe": "^0.20.0", 18 | "vue-router": "^4.2.4", 19 | "vuex": "^4.1.0" 20 | }, 21 | "devDependencies": { 22 | "@rollup/plugin-alias": "^5.0.0", 23 | "@vicons/antd": "^0.12.0", 24 | "@vicons/fa": "^0.12.0", 25 | "@vicons/fluent": "^0.12.0", 26 | "@vicons/tabler": "^0.12.0", 27 | "@vitejs/plugin-vue": "^4.3.4", 28 | "@vue/compiler-sfc": "^3.3.4", 29 | "@yankeeinlondon/code-builder": "^1.2.1", 30 | "highlight.js": "^11.8.0", 31 | "markdown-it": "^13.0.1", 32 | "markdown-it-prism": "^2.3.0", 33 | "naive-ui": "^2.34.4", 34 | "sass": "^1.66.1", 35 | "vfonts": "^0.0.3", 36 | "vite": "^4.5.14", 37 | "vite-plugin-inspect": "^0.7.38", 38 | "vite-plugin-md": "^0.21.5" 39 | } 40 | } -------------------------------------------------------------------------------- /frontend/package.json.md5: -------------------------------------------------------------------------------- 1 | d787a9fd0cd73ac50fe1e621853e3147 -------------------------------------------------------------------------------- /frontend/src/apis/apis.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright (C) 2023 Quan Chen 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | import { Dispatch, ResourceServerAddr, OpenFinder, BaseDictDir } from '../../wailsjs/go/main/App'; 20 | 21 | import { model } from '../../wailsjs/go/models'; 22 | 23 | function objectToPathParams(obj) { 24 | const params = []; 25 | for (const key in obj) { 26 | if (obj.hasOwnProperty(key)) { 27 | params.push(`${encodeURIComponent(key)}=${encodeURIComponent(obj[key])}`); 28 | } 29 | } 30 | return params.join('&'); 31 | } 32 | 33 | export const StaticDictServerURL = function (): Promise { 34 | if (window['go']) { 35 | return ResourceServerAddr(); 36 | } else { 37 | Promise.resolve("http://localhost:1") 38 | } 39 | }; 40 | 41 | export const OpenDirOrFile = function(filepath :string):Promise{ 42 | if (window['go']) { 43 | return OpenFinder(filepath) 44 | } else { 45 | Promise.resolve() 46 | } 47 | } 48 | 49 | export const BaseDictDirectory = function():Promise{ 50 | if (window['go']) { 51 | return BaseDictDir() 52 | } else { 53 | Promise.resolve("internal error") 54 | } 55 | } 56 | 57 | 58 | 59 | export async function requestBackend(apiName, data): Promise { 60 | if (window['go']) { 61 | console.log(`[dicts-api] ipc call, dispatch [${apiName}] event, args:`, data) 62 | return Dispatch(apiName, data); 63 | } else { 64 | return Promise.resolve({ 65 | data:"", 66 | err: "browser not support or system not initialzd yet", 67 | code: 500, 68 | }) 69 | 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /frontend/src/apis/config.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright (C) 2023 Quan Chen 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | -------------------------------------------------------------------------------- /frontend/src/apis/model.ts: -------------------------------------------------------------------------------- 1 | export namespace model { 2 | 3 | export class KeyBlockEntry { 4 | id: number; 5 | record_start_offset: number; 6 | record_end_offset: number; 7 | keyword: string; 8 | key_block_idx: number; 9 | 10 | static createFrom(source: any = {}) { 11 | return new KeyBlockEntry(source); 12 | } 13 | 14 | constructor(source: any = {}) { 15 | if ('string' === typeof source) source = JSON.parse(source); 16 | this.id = source["id"]; 17 | this.record_start_offset = source["record_start_offset"]; 18 | this.record_end_offset = source["record_end_offset"]; 19 | this.keyword = source["keyword"]; 20 | this.key_block_idx = source["key_block_idx"]; 21 | } 22 | } 23 | export class PlainDictionaryItem { 24 | id: string; 25 | name: string; 26 | path: string; 27 | 28 | static createFrom(source: any = {}) { 29 | return new PlainDictionaryItem(source); 30 | } 31 | 32 | constructor(source: any = {}) { 33 | if ('string' === typeof source) source = JSON.parse(source); 34 | this.id = source["id"]; 35 | this.name = source["name"]; 36 | this.path = source["path"]; 37 | } 38 | } 39 | export class Resp { 40 | data: any; 41 | err: string; 42 | code: number; 43 | 44 | static createFrom(source: any = {}) { 45 | return new Resp(source); 46 | } 47 | 48 | constructor(source: any = {}) { 49 | if ('string' === typeof source) source = JSON.parse(source); 50 | this.data = source["data"]; 51 | this.err = source["err"]; 52 | this.code = source["code"]; 53 | } 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /frontend/src/apis/types.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright (C) 2023 Quan Chen 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | export interface IDict { 20 | id: string 21 | name: string 22 | discrption?: string 23 | imageURL?: string 24 | mdxFileURL?: string 25 | mddFileURL?: string 26 | } 27 | 28 | export interface IWordEntry { 29 | word: string, 30 | keyText: string, 31 | record_start: number, 32 | record_end: number, 33 | } 34 | 35 | export interface IArticleData { 36 | id: number 37 | status: string 38 | title: string 39 | abstractContent: string 40 | fullContent: string 41 | sourceURL: string 42 | imageURL: string 43 | timestamp: string | number 44 | platforms: string[] 45 | disableComment: boolean 46 | importance: number 47 | author: string 48 | reviewer: string 49 | type: string 50 | pageviews: number 51 | } 52 | 53 | export interface IRoleData { 54 | key: string 55 | name: string 56 | description: string 57 | routes: any 58 | } 59 | 60 | export interface ITransactionData { 61 | orderId: string 62 | timestamp: string | number 63 | username: string 64 | price: number 65 | status: string 66 | } 67 | 68 | export interface IUserData { 69 | id: number 70 | username: string 71 | password: string 72 | name: string 73 | email: string 74 | phone: string 75 | avatar: string 76 | introduction: string 77 | roles: string[] 78 | } -------------------------------------------------------------------------------- /frontend/src/assets/docs/about.md: -------------------------------------------------------------------------------- 1 | # About 2 | ## 软件信息 3 | 4 | ### 软件简介 5 | Medict, 现代跨平台词典App 6 | 7 | ### 软件版本 8 | v3.0.1-alpha 9 | 10 | ## 致谢 11 | ### 开发人员 12 | Chen, Quan 13 | 14 | ### 设计人员 15 | Zhang, Mingjiao

16 | 17 | ### 特别鸣谢 18 | Song, Xing 19 | 20 | -------------------------------------------------------------------------------- /frontend/src/assets/docs/faq.md: -------------------------------------------------------------------------------- 1 | # FAQ 2 | 3 | ### 发音问题 4 | 5 | 目前 oale8 词典这种内嵌发音按钮的,将音频资源嵌入在 mdd 文件中的词典是可以支持发音的,但是目前采用的是 js 替换的方式完成,不一定适用于所有词典,需要 case by case 调试 6 | 7 | ### 跳转问题 8 | 9 | 目前有两种跳转: 10 | 11 | 1. @@Link 的跳转,自动跳转,但是如果出现跳转环路,会停止跳转,直接展示 @@Link== 12 | 2. 内部跳转即 `` 的方式,如果 entry 中间是完整词条,可以支持跳转,如果是特殊词条,目前还不支持 13 | -------------------------------------------------------------------------------- /frontend/src/assets/docs/images/image-20230927112451745.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terasum/medict/138f5198ef0034909f9872ce580bb4fddf31fca9/frontend/src/assets/docs/images/image-20230927112451745.png -------------------------------------------------------------------------------- /frontend/src/assets/docs/images/image-20230927112656769.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terasum/medict/138f5198ef0034909f9872ce580bb4fddf31fca9/frontend/src/assets/docs/images/image-20230927112656769.png -------------------------------------------------------------------------------- /frontend/src/assets/docs/images/image-20230927113137569.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terasum/medict/138f5198ef0034909f9872ce580bb4fddf31fca9/frontend/src/assets/docs/images/image-20230927113137569.png -------------------------------------------------------------------------------- /frontend/src/assets/docs/images/image-20230927113331495-5785613-5785617.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terasum/medict/138f5198ef0034909f9872ce580bb4fddf31fca9/frontend/src/assets/docs/images/image-20230927113331495-5785613-5785617.png -------------------------------------------------------------------------------- /frontend/src/assets/docs/images/image-20230927113331495.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terasum/medict/138f5198ef0034909f9872ce580bb4fddf31fca9/frontend/src/assets/docs/images/image-20230927113331495.png -------------------------------------------------------------------------------- /frontend/src/assets/docs/images/zov3hq.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terasum/medict/138f5198ef0034909f9872ce580bb4fddf31fca9/frontend/src/assets/docs/images/zov3hq.png -------------------------------------------------------------------------------- /frontend/src/assets/docs/select_and_use_dict.md: -------------------------------------------------------------------------------- 1 | # 词典配置与使用说明 2 | 3 | ## 步骤1: 添加词典 4 | 5 | 1. 点击右上角设置 6 | 2. 点击下方 "+" 号 7 | 8 | 翻译界面 9 | 10 | 3. 在弹出框中填写词典信息 11 | 4. 选择词典文件 12 | 13 | 14 | ![pic_add_dict_modal.jpg](@/assets/images/docs/index.png) 15 | 16 | **注意:** mdx文件所在的文件夹中的js/css/font文件均会被拷贝到缓存文件夹中,请把一个独立词典放在一个独立的文件夹中,并将相关资源放在一起。 17 | 18 | **注意:** mdx/mdd 本身不会被拷贝,删除之后,词典将无法找到该mdx文件 19 | 20 | 21 | ## 步骤 2: 查词 22 | 23 | 1. 选择词典并输入目标词(模糊) 24 | 25 | 26 | 翻译界面 27 | 28 | 2. 在左边栏选择你想要查的具体词汇, 如果该词汇和其他词汇同一个意思(即@@Link==) 则直接展示该同意义词汇 29 | 30 | 翻译界面 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /frontend/src/assets/docs/terms_and_service.md: -------------------------------------------------------------------------------- 1 | # 免责与隐私保护声明 2 | 3 | 本免责及隐私保护声明(以下简称“隐私声明”或“本声明”)适用于软件 Medict (以下简称 "Medict" ) 在您阅读本声明后若不同意此声明中的任何条款,或对本声明存在质疑,请立刻停止使用本软件。若您已经开始或正在使用 Medict 软件,则表示您已阅读并同意本声明的所有条款之约定。 4 | 5 | 1. 您通过安装 Medict 软件并使用 Medict 软件提供的服务与功能即表示您已经同意与软件作者立本协议。软件作者可随时执行全权决定更改“条款”。如“条款”有任何变更,软件官方发布网站 (https://github.com/terasum/medict) 上刊载公告作为通知。经修订的“条款”一经在官方网站上公布后,立即自动生效。 6 | 7 | 2. 一切因使用 Medict 软件而引致之任何意外、疏忽、合约毁坏、诽谤、版权或知识产权侵犯及其所造成的损失(包括在非官方站点下载Medict 软件而感染电脑病毒),软件作者概不负责,亦不承担任何法律责任。 8 | 9 | 3. 用户对使用 Medict 软件自行承担风险,我们不做任何形式的保证, 因网络状况、通讯线路等任何技术原因而导致用户不能正常升级更新,作者也不承担任何法律责任。 10 | 11 | 4. Medict 软件尊重并保护所有用户的个人隐私权,不会窃取任何用户计算机中的信息, 亦不会将用户文件上载至互联网服务器。 12 | 13 | 5. Medict 以 GPLv3 协议发布, 软件著作权属软件作者所有。 -------------------------------------------------------------------------------- /frontend/src/assets/images/docs/index.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terasum/medict/138f5198ef0034909f9872ce580bb4fddf31fca9/frontend/src/assets/images/docs/index.png -------------------------------------------------------------------------------- /frontend/src/assets/images/logo-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terasum/medict/138f5198ef0034909f9872ce580bb4fddf31fca9/frontend/src/assets/images/logo-dark.png -------------------------------------------------------------------------------- /frontend/src/assets/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terasum/medict/138f5198ef0034909f9872ce580bb4fddf31fca9/frontend/src/assets/images/logo.png -------------------------------------------------------------------------------- /frontend/src/components/layout/AppMainContent.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 33 | 40 | 41 | 43 | -------------------------------------------------------------------------------- /frontend/src/components/layout/AppRightToolbar.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 39 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /frontend/src/components/layout/AppSidebar.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 69 | 76 | 77 | 79 | -------------------------------------------------------------------------------- /frontend/src/components/setting/SettingItem.vue: -------------------------------------------------------------------------------- 1 | 18 | 23 | 68 | -------------------------------------------------------------------------------- /frontend/src/main.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright (C) 2023 Quan Chen 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | import naive from 'naive-ui'; 20 | import { createApp } from 'vue'; 21 | import { createRouter, createWebHashHistory } from 'vue-router'; 22 | import { createPinia } from 'pinia'; 23 | 24 | import routes from '@/router'; 25 | import App from '@/App.vue'; 26 | 27 | import 'normalize.css/normalize.css'; 28 | // 通用字体 29 | import 'vfonts/Lato.css'; 30 | // 等宽字体 31 | import 'vfonts/FiraCode.css'; 32 | 33 | import '@/style/renderer.scss'; 34 | 35 | import '@/renderer.init'; 36 | 37 | 38 | const router = createRouter({ 39 | history: createWebHashHistory(), 40 | routes, 41 | }); 42 | 43 | const pinia = createPinia(); 44 | 45 | const app = createApp(App); 46 | 47 | router.push({ path: '/' }); // store.state.defaultWindow }); 48 | app.use(router); 49 | 50 | app.use(naive); 51 | app.use(pinia); 52 | 53 | // remove skeleton 54 | let skeleton = document.querySelector('#skeleton-wrapper'); 55 | if (skeleton) { 56 | skeleton.innerHTML = ''; 57 | } 58 | 59 | // appMain.$mount('#app'); 60 | app.mount('#app'); 61 | -------------------------------------------------------------------------------- /frontend/src/renderer.init.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright (C) 2023 Quan Chen 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | console.log('👋 This message is being logged by "renderer.init.ts", included via webpack'); 20 | 21 | 22 | (function errorListen() { 23 | window.onerror = function (error, url, line) { 24 | // ipcRenderer.send('errorInWindow', { error, url, line }); 25 | }; 26 | })(); 27 | 28 | -------------------------------------------------------------------------------- /frontend/src/settings.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright (C) 2023 Quan Chen 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | interface ISettings { 20 | title: string // Overrides the default title 21 | showSettings: boolean // Controls settings panel display 22 | showTagsView: boolean // Controls tagsview display 23 | showSidebarLogo: boolean // Controls siderbar logo display 24 | fixedHeader: boolean // If true, will fix the header component 25 | errorLog: string[] // The env to enable the errorlog component, default 'production' only 26 | sidebarTextTheme: boolean // If true, will change active text color for sidebar based on theme 27 | devServerPort: number // Port number for webpack-dev-server 28 | mockServerPort: number // Port number for mock server 29 | } 30 | 31 | // You can customize below settings :) 32 | const settings: ISettings = { 33 | title: 'Vue Typescript Admin', 34 | showSettings: true, 35 | showTagsView: true, 36 | fixedHeader: false, 37 | showSidebarLogo: false, 38 | errorLog: ['production'], 39 | sidebarTextTheme: true, 40 | devServerPort: 9527, 41 | mockServerPort: 9528 42 | } 43 | 44 | export default settings -------------------------------------------------------------------------------- /frontend/src/store/StoreDataType.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright (C) 2023 Quan Chen 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | import { Dictionary } from '../model/Dictionary'; 20 | 21 | export declare class DictItem { 22 | id: string; 23 | name: string; 24 | } 25 | 26 | export declare class StoreDataType { 27 | defaultWindow: string; 28 | // defaultWindow: '/', 29 | headerData: { 30 | currentTab: string; 31 | // currentTab: '词典', 32 | }; 33 | sideBarData: { 34 | selectedWordIdx: number; 35 | candidateWordNum: number; 36 | }; 37 | 38 | dictionaries: Dictionary[]; 39 | dictBaseDir: string; 40 | suggestWords: any[]; 41 | historyStack: any[]; 42 | currentWord: { dictid: string, word:string }; 43 | currentLookupWord: string; 44 | currentActualWord: string; 45 | currentContent: string; 46 | currentSelectDict: DictItem; 47 | translateApi: { 48 | baidu: { 49 | appid: string; 50 | appkey: string; 51 | }; 52 | }; 53 | } 54 | -------------------------------------------------------------------------------- /frontend/src/store/ui/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright (C) 2023 Quan Chen 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | import { defineStore } from 'pinia'; 20 | 21 | export const useUIStore = defineStore('ui', { 22 | state: () => ({ 23 | currentTab: 'search', 24 | 25 | progressHint: "", 26 | 27 | }), 28 | actions: { 29 | updateCurrentTab(tabName: string) { 30 | this.currentTab = tabName; 31 | }, 32 | isSearchInputActive() { 33 | return this.currentTab === "search"; 34 | }, 35 | updateProgress(hint:string, progress:number) { 36 | if (progress > 100) { 37 | progress = 100; 38 | } 39 | if (progress < 0) { 40 | progress = 0 41 | } 42 | 43 | this.progressHint = hint; 44 | 45 | } 46 | }, 47 | }); 48 | -------------------------------------------------------------------------------- /frontend/src/style/photon/bars.scss: -------------------------------------------------------------------------------- 1 | // 2 | // Bars.css 3 | // -------------------------------------------------- 4 | 5 | .toolbar { 6 | min-height: 22px; 7 | box-shadow: inset 0 1px 0 #f5f4f5; 8 | @include linear-gradient(#e8e6e8, #d1cfd1); 9 | @include clearfix; 10 | } 11 | 12 | .toolbar-header { 13 | border-bottom: 1px solid $dark-border-color; 14 | 15 | .title { 16 | margin-top: 1px; 17 | } 18 | } 19 | 20 | .toolbar-footer { 21 | border-top: 1px solid $dark-border-color; 22 | -webkit-app-region: drag; 23 | } 24 | 25 | // Simple centered title to go in the toolbar 26 | .title { 27 | margin: 0; 28 | font-size: 12px; 29 | font-weight: 400; 30 | text-align: center; 31 | color: #555; 32 | cursor: default; 33 | } 34 | 35 | // Borderless toolbar for the clean look 36 | .toolbar-borderless { 37 | border-top: 0; 38 | border-bottom: 0; 39 | } 40 | 41 | // Buttons in toolbars 42 | .toolbar-actions { 43 | margin-top: 4px; 44 | margin-bottom: 3px; 45 | padding-right: 3px; 46 | padding-left: 3px; 47 | padding-bottom: 3px; 48 | -webkit-app-region: drag; 49 | @include clearfix; 50 | 51 | > .btn, 52 | > .btn-group { 53 | margin-left: 4px; 54 | margin-right: 4px; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /frontend/src/style/photon/base.scss: -------------------------------------------------------------------------------- 1 | // 2 | // Base styles 3 | // -------------------------------------------------- 4 | 5 | * { 6 | cursor: default; 7 | -webkit-user-drag: text; 8 | -webkit-user-select: none; 9 | -webkit-box-sizing: border-box; 10 | box-sizing: border-box; 11 | } 12 | 13 | html { 14 | height: 100%; 15 | width: 100%; 16 | overflow: hidden; 17 | } 18 | 19 | body { 20 | height: 100%; 21 | padding: 0; 22 | margin: 0; 23 | font-family: $font-family-default; 24 | font-size: $font-size-default; 25 | line-height: $line-height-default; 26 | color: $gray-color; 27 | background-color: transparent; 28 | } 29 | 30 | hr { 31 | margin: 15px 0; 32 | overflow: hidden; 33 | background: transparent; 34 | border: 0; 35 | border-bottom: 1px solid $border-color; 36 | } 37 | 38 | // Typography 39 | h1, h2, h3, h4, h5, h6 { 40 | margin-top: 20px; 41 | margin-bottom: 10px; 42 | font-weight: 500; 43 | white-space: nowrap; 44 | overflow: hidden; 45 | text-overflow: ellipsis; 46 | } 47 | 48 | h1 { font-size: 36px; } 49 | h2 { font-size: 30px; } 50 | h3 { font-size: 24px; } 51 | h4 { font-size: 18px; } 52 | h5 { font-size: 14px; } 53 | h6 { font-size: 12px; } 54 | 55 | // Basic app structure 56 | .window { 57 | position: absolute; 58 | top: 0; 59 | right: 0; 60 | bottom: 0; 61 | left: 0; 62 | display: flex; 63 | flex-direction: column; 64 | background-color: $chrome-color; 65 | } 66 | 67 | .window-content { 68 | position: relative; 69 | overflow-y: auto; 70 | display: flex; 71 | flex: 1; 72 | } 73 | -------------------------------------------------------------------------------- /frontend/src/style/photon/button-groups.scss: -------------------------------------------------------------------------------- 1 | // 2 | // Button-groups.css 3 | // Adapted from Bootstrap's button-groups.less (https://github.com/twbs/bootstrap/blob/master/less/button-groups.less) 4 | // -------------------------------------------------- 5 | 6 | // Button groups 7 | .btn-group { 8 | position: relative; 9 | display: inline-block; 10 | vertical-align: middle; // match .btn alignment given font-size hack above 11 | -webkit-app-region: no-drag; 12 | 13 | .btn { 14 | position: relative; 15 | float: left; 16 | 17 | // Bring the "active" button to the front 18 | &:focus, 19 | &:active{ 20 | z-index: 2; 21 | } 22 | 23 | &.active { 24 | z-index: 3; 25 | } 26 | } 27 | } 28 | 29 | // Prevent double borders when buttons are next to each other 30 | .btn-group { 31 | .btn + .btn, 32 | .btn + .btn-group, 33 | .btn-group + .btn, 34 | .btn-group + .btn-group { 35 | margin-left: -1px; 36 | } 37 | 38 | > .btn:first-child { 39 | border-top-right-radius: 0; 40 | border-bottom-right-radius: 0; 41 | } 42 | 43 | > .btn:last-child { 44 | border-top-left-radius: 0; 45 | border-bottom-left-radius: 0; 46 | } 47 | 48 | > .btn:not(:first-child):not(:last-child) { 49 | border-radius: 0; 50 | } 51 | 52 | .btn + .btn { 53 | border-left: 1px solid $dark-border-color; 54 | } 55 | 56 | .btn + .btn.active { 57 | border-left: 0; 58 | } 59 | 60 | // Selected state 61 | .active { 62 | color: #fff; 63 | border: 1px solid transparent; 64 | background-color: #6d6c6d; 65 | background-image: none; 66 | } 67 | 68 | // Invert the icon in the active button 69 | .active .icon { 70 | color: #fff; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /frontend/src/style/photon/fonts/photon-entypo.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terasum/medict/138f5198ef0034909f9872ce580bb4fddf31fca9/frontend/src/style/photon/fonts/photon-entypo.eot -------------------------------------------------------------------------------- /frontend/src/style/photon/fonts/photon-entypo.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terasum/medict/138f5198ef0034909f9872ce580bb4fddf31fca9/frontend/src/style/photon/fonts/photon-entypo.ttf -------------------------------------------------------------------------------- /frontend/src/style/photon/fonts/photon-entypo.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terasum/medict/138f5198ef0034909f9872ce580bb4fddf31fca9/frontend/src/style/photon/fonts/photon-entypo.woff -------------------------------------------------------------------------------- /frontend/src/style/photon/forms.scss: -------------------------------------------------------------------------------- 1 | // 2 | // Forms.css 3 | // Adapted from Bootstrap's forms.less (https://github.com/twbs/bootstrap/blob/master/less/forms.less) 4 | // -------------------------------------------------- 5 | 6 | label { 7 | display: inline-block; 8 | font-size: $font-size-default; 9 | margin-bottom: 5px; 10 | white-space: nowrap; 11 | overflow: hidden; 12 | text-overflow: ellipsis; 13 | } 14 | 15 | input[type="search"] { 16 | box-sizing: border-box; 17 | } 18 | 19 | input[type="radio"], 20 | input[type="checkbox"] { 21 | margin: 4px 0 0; 22 | line-height: normal; 23 | } 24 | 25 | .form-control { 26 | display: inline-block; 27 | width: 100%; 28 | min-height: 25px; 29 | padding: $padding-less $padding; 30 | font-size: $font-size-default; 31 | line-height: $line-height-default; 32 | background-color: $chrome-color; 33 | border: 1px solid $border-color; 34 | border-radius: $default-border-radius; 35 | outline: none; 36 | 37 | &:focus { 38 | border-color: $focus-input-color; 39 | box-shadow: 3px 3px 0 $focus-input-color, 40 | -3px -3px 0 $focus-input-color, 41 | -3px 3px 0 $focus-input-color, 42 | 3px -3px 0 $focus-input-color; 43 | } 44 | } 45 | 46 | // Reset height for `textarea`s 47 | textarea { 48 | height: auto; 49 | } 50 | 51 | // Form groups 52 | // 53 | // Designed to help with the organization and spacing of vertical forms. For 54 | // horizontal forms, use the predefined grid classes. 55 | 56 | .form-group { 57 | margin-bottom: 10px; 58 | } 59 | 60 | // Checkboxes and radios 61 | // 62 | // Indent the labels to position radios/checkboxes as hanging controls. 63 | 64 | .radio, 65 | .checkbox { 66 | position: relative; 67 | display: block; 68 | margin-top: 10px; 69 | margin-bottom: 10px; 70 | 71 | label { 72 | padding-left: 20px; 73 | margin-bottom: 0; 74 | font-weight: normal; 75 | } 76 | } 77 | 78 | .radio input[type="radio"], 79 | .radio-inline input[type="radio"], 80 | .checkbox input[type="checkbox"], 81 | .checkbox-inline input[type="checkbox"] { 82 | position: absolute; 83 | margin-left: -20px; 84 | margin-top: 4px; 85 | } 86 | 87 | // Form actions 88 | .form-actions .btn { 89 | margin-right: 10px; 90 | 91 | &:last-child { 92 | margin-right: 0; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /frontend/src/style/photon/grid.scss: -------------------------------------------------------------------------------- 1 | // 2 | // The Grid.css 3 | // -------------------------------------------------- 4 | 5 | .pane-group { 6 | position: absolute; 7 | top: 0; 8 | right: 0; 9 | bottom: 0; 10 | left: 0; 11 | display: flex; 12 | } 13 | 14 | .pane { 15 | position: relative; 16 | overflow-y: auto; 17 | flex: 1; 18 | border-left: 1px solid $border-color; 19 | 20 | &:first-child { 21 | border-left: 0; 22 | } 23 | } 24 | 25 | .pane-sm { 26 | max-width: 220px; 27 | min-width: 150px; 28 | } 29 | 30 | .pane-mini { 31 | width: 80px; 32 | flex: none; 33 | } 34 | 35 | .pane-one-fourth { 36 | width: 25%; 37 | flex: none; 38 | } 39 | 40 | .pane-one-third { 41 | width: 33.3%; 42 | } 43 | -------------------------------------------------------------------------------- /frontend/src/style/photon/images.scss: -------------------------------------------------------------------------------- 1 | // 2 | // Images.scss 3 | // -------------------------------------------------- 4 | 5 | img { 6 | -webkit-user-drag: text; 7 | } 8 | 9 | .img-circle { 10 | border-radius: 50%; 11 | } 12 | 13 | .img-rounded { 14 | border-radius: $default-border-radius; 15 | } 16 | -------------------------------------------------------------------------------- /frontend/src/style/photon/lists.scss: -------------------------------------------------------------------------------- 1 | // 2 | // Lists.scss 3 | // -------------------------------------------------- 4 | 5 | // List groups 6 | // These are to be used when shows list items that contain 7 | // more substanstial amounts of information. (headings, images, text, etc.) 8 | 9 | .list-group { 10 | width: 100%; 11 | list-style: none; 12 | margin: 0; 13 | padding: 0; 14 | 15 | 16 | * { 17 | margin: 0; 18 | white-space: nowrap; 19 | overflow: hidden; 20 | text-overflow: ellipsis; 21 | } 22 | } 23 | 24 | .list-group-item { 25 | padding: 10px; 26 | font-size: 12px; 27 | color: #414142; 28 | border-top: 1px solid $border-color; 29 | 30 | &:first-child { 31 | border-top: 0; 32 | } 33 | 34 | &.active, 35 | // `.selected` is deprecated. Use `.active` instead. 36 | &.selected { 37 | color: #fff; 38 | background-color: $active-color; 39 | } 40 | } 41 | 42 | .list-group-header { 43 | padding: 10px; 44 | } 45 | 46 | // Media objects in lists 47 | .media-object { 48 | margin-top: 3px; 49 | } 50 | 51 | .media-object.pull-left { 52 | margin-right: 10px 53 | } 54 | 55 | .media-object.pull-right { 56 | margin-left: 10px 57 | } 58 | 59 | .media-body { 60 | overflow: hidden; 61 | } 62 | -------------------------------------------------------------------------------- /frontend/src/style/photon/navs.scss: -------------------------------------------------------------------------------- 1 | // 2 | // Navs.scss 3 | // -------------------------------------------------- 4 | 5 | .nav-group { 6 | font-size: 14px; 7 | } 8 | 9 | .nav-group-item { 10 | padding: 2px 10px 2px 25px; 11 | display: block; 12 | color: $gray-color; 13 | text-decoration: none; 14 | white-space: nowrap; 15 | overflow: hidden; 16 | text-overflow: ellipsis; 17 | 18 | &:active, 19 | &.active { 20 | background-color: #dcdfe1; 21 | } 22 | 23 | .icon { 24 | width: 19px; // Prevents a one pixel cutoff 25 | height: 18px; 26 | float: left; 27 | color: #737475; 28 | margin-top: -3px; 29 | margin-right: 7px; 30 | font-size: 18px; 31 | text-align: center; 32 | } 33 | } 34 | 35 | .nav-group-title { 36 | margin: 0; 37 | padding: 10px 10px 2px; 38 | font-size: 12px; 39 | font-weight: 500; 40 | color: lighten($gray-color, 20%); 41 | } 42 | -------------------------------------------------------------------------------- /frontend/src/style/photon/photon.scss: -------------------------------------------------------------------------------- 1 | // Variables 2 | @import "variables.scss"; 3 | 4 | // Mixins 5 | @import "mixins.scss"; 6 | 7 | // Normalize, Base, & Utilities CSS 8 | @import "normalize.scss"; 9 | @import "base.scss"; 10 | @import "utilities.scss"; 11 | 12 | // Components 13 | @import "buttons.scss"; 14 | @import "button-groups.scss"; 15 | @import "bars.scss"; 16 | @import "forms.scss"; 17 | @import "grid.scss"; 18 | @import "images.scss"; 19 | @import "lists.scss"; 20 | @import "navs.scss"; 21 | @import "icons.scss"; 22 | @import "tables.scss"; 23 | @import "tabs.scss"; 24 | -------------------------------------------------------------------------------- /frontend/src/style/photon/tables.scss: -------------------------------------------------------------------------------- 1 | // 2 | // Navs.scss 3 | // -------------------------------------------------- 4 | 5 | table { 6 | width: 100%; 7 | border: 0; 8 | border-collapse: separate; 9 | font-size: 12px; 10 | text-align: left; 11 | } 12 | 13 | thead { 14 | background-color: #f5f5f4; 15 | } 16 | 17 | tbody { 18 | background-color: #fff; 19 | } 20 | 21 | .table-striped tr:nth-child(even) { 22 | background-color: #f5f5f4; 23 | } 24 | 25 | tr:active, 26 | .table-striped tr:active:nth-child(even) { 27 | color: #fff; 28 | background-color: $active-color; 29 | } 30 | 31 | thead tr:active { 32 | color: $gray-color; 33 | background-color: #f5f5f4; 34 | } 35 | 36 | th { 37 | font-weight: normal; 38 | border-right: 1px solid $border-color; 39 | border-bottom: 1px solid $border-color; 40 | } 41 | 42 | th, 43 | td { 44 | padding: 2px 15px; 45 | white-space: nowrap; 46 | overflow: hidden; 47 | text-overflow: ellipsis; 48 | 49 | &:last-child { 50 | border-right: 0; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /frontend/src/style/photon/tabs.scss: -------------------------------------------------------------------------------- 1 | // Tabs 2 | 3 | .tab-group { 4 | margin-top: -1px; 5 | display: flex; 6 | border-top: 1px solid #989698; 7 | border-bottom: 1px solid #989698; 8 | } 9 | 10 | .tab-item { 11 | position: relative; 12 | flex: 1; 13 | padding: 3px; 14 | font-size: 12px; 15 | text-align: center; 16 | border-left: 1px solid #989698; 17 | @include linear-gradient(#b8b6b8, #b0aeb0); 18 | 19 | &:first-child { 20 | border-left: 0; 21 | } 22 | 23 | &.active { 24 | @include linear-gradient(#d4d2d4, #cccacc); 25 | } 26 | 27 | .icon-close-tab { 28 | position: absolute; 29 | top: 50%; 30 | left: 5px; 31 | width: 15px; 32 | height: 15px; 33 | font-size: 15px; 34 | line-height: 15px; 35 | text-align: center; 36 | color: #666; 37 | opacity: 0; 38 | transition: opacity .1s linear, background-color .1s linear; 39 | border-radius: 3px; 40 | transform: translateY(-50%); 41 | z-index: 10; 42 | } 43 | 44 | &:after { 45 | position: absolute; 46 | top: 0; 47 | right: 0; 48 | bottom: 0; 49 | left: 0; 50 | content: ""; 51 | background-color: rgba(0,0,0,.08); 52 | opacity: 0; 53 | transition: opacity .1s linear; 54 | z-index: 1; 55 | } 56 | 57 | // Okay, I know... this is nuts but... 58 | &:hover:not(.active):after { 59 | opacity: 1; 60 | } 61 | 62 | &:hover .icon-close-tab { 63 | opacity: 1; 64 | } 65 | 66 | .icon-close-tab:hover { 67 | background-color: rgba(0,0,0,.08); 68 | } 69 | } 70 | 71 | .tab-item-fixed { 72 | flex: none; 73 | padding: 3px 10px; 74 | } 75 | -------------------------------------------------------------------------------- /frontend/src/style/photon/utilities.scss: -------------------------------------------------------------------------------- 1 | // 2 | // Utilities styles 3 | // -------------------------------------------------- 4 | 5 | // Utility classes 6 | .selectable-text { 7 | cursor: text; 8 | -webkit-user-select: text; 9 | } 10 | 11 | // Text alignment 12 | .text-center { 13 | text-align: center; 14 | } 15 | 16 | .text-right { 17 | text-align: right; 18 | } 19 | 20 | .text-left { 21 | text-align: left; 22 | } 23 | 24 | // Floats 25 | .pull-left { 26 | float: left; 27 | } 28 | 29 | .pull-right { 30 | float: right; 31 | } 32 | 33 | // Padding 34 | .padded { 35 | padding: $padding; 36 | } 37 | 38 | .padded-less { 39 | padding: $padding-less; 40 | } 41 | 42 | .padded-more { 43 | padding: $padding-more; 44 | } 45 | 46 | // Vertical Padding 47 | .padded-vertically { 48 | padding-top: $padding; 49 | padding-bottom: $padding; 50 | } 51 | 52 | .padded-vertically-less { 53 | padding-top: $padding-less; 54 | padding-bottom: $padding-less; 55 | } 56 | 57 | .padded-vertically-more { 58 | padding-top: $padding-more; 59 | padding-bottom: $padding-more; 60 | } 61 | 62 | // Horizontal Padding 63 | .padded-horizontally { 64 | padding-right: $padding; 65 | padding-left: $padding; 66 | } 67 | 68 | .padded-horizontally-less { 69 | padding-right: $padding-less; 70 | padding-left: $padding-less; 71 | } 72 | 73 | .padded-horizontally-more { 74 | padding-right: $padding-more; 75 | padding-left: $padding-more; 76 | } 77 | 78 | // Padding top 79 | .padded-top { 80 | padding-top: $padding; 81 | } 82 | 83 | .padded-top-less { 84 | padding-top: $padding-less; 85 | } 86 | 87 | .padded-top-more { 88 | padding-top: $padding-more; 89 | } 90 | 91 | // Padding bottom 92 | .padded-bottom { 93 | padding-bottom: $padding; 94 | } 95 | 96 | .padded-bottom-less { 97 | padding-bottom: $padding-less; 98 | } 99 | 100 | .padded-bottom-more { 101 | padding-bottom: $padding-more; 102 | } 103 | 104 | // Set the background-color to set a sidebar back a bit. 105 | .sidebar { 106 | background-color: #f5f5f4; 107 | } 108 | 109 | // Allow the window to be dragged around the desktop by any element in the application. 110 | .draggable { 111 | -webkit-app-region: drag; 112 | } 113 | 114 | // Clearfix 115 | .clearfix { 116 | @include clearfix(); 117 | } 118 | -------------------------------------------------------------------------------- /frontend/src/style/photon/variables.scss: -------------------------------------------------------------------------------- 1 | // 2 | // Variables 3 | // -------------------------------------------------- 4 | 5 | // Type 6 | // -------------------------------------------------- 7 | 8 | // Try to use the system's font on whatever platform the user is on. 9 | $font-family-default: system, -apple-system, ".SFNSDisplay-Regular", "Helvetica Neue", Helvetica, "Segoe UI", sans-serif !default; 10 | $font-size-default: 13px !default; 11 | $font-weight: 500 !default; 12 | $font-weight-bold: 700 !default; 13 | $font-weight-light: 300 !default; 14 | $line-height-default: 1.6 !default; 15 | 16 | 17 | // Colors 18 | // -------------------------------------------------- 19 | 20 | // Main colors 21 | $primary-color: #3b99fc !default; 22 | $chrome-color: #fff !default; 23 | 24 | // Copy 25 | $gray-color: #333 !default; 26 | 27 | // Borders 28 | $border-color: #ddd !default; 29 | $dark-border-color: #c2c0c2 !default; 30 | $darker-bottom-border-color: #a19fa1 !default; 31 | $toolbar-border-color: #939293 !default; 32 | 33 | // Action colors 34 | $default-color: #fff !default; 35 | $positive-color: #34c84a !default; 36 | $negative-color: #fc605b !default; 37 | $warning-color: #fdbc40 !default; 38 | 39 | // Shades 40 | $dark-color: #57acf5 !default; 41 | 42 | // Focus and active colors 43 | $active-color: #116cd6; 44 | $focus-input-color: lighten($primary-color, 10%) !default; 45 | 46 | // Other 47 | // -------------------------------------------------- 48 | 49 | // Border radius 50 | $default-border-radius: 4px; 51 | 52 | // Padding 53 | $padding: 10px; 54 | $padding-mini: 3px; 55 | $padding-less: 5px; 56 | $padding-more: 20px; 57 | -------------------------------------------------------------------------------- /frontend/src/style/renderer.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright (C) 2023 Quan Chen 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | html { 20 | height:100%; 21 | width: 100%; 22 | overflow: hidden; 23 | background-color: transparent; 24 | } 25 | body { 26 | font-family: Avenir,-apple-system,BlinkMacSystemFont,'Segoe UI', 'Hiragino Sans GB','Microsoft YaHei', 'PingFang SC','Helvetica Neue',Helvetica,Arial,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol',sans-serif; 27 | margin: auto; 28 | width: 100%; 29 | height:100%; 30 | overflow: hidden; 31 | overscroll-behavior: none; 32 | background-color: transparent; 33 | backdrop-filter: blur(5px); 34 | } 35 | 36 | #app { 37 | height:100%; 38 | width: 100%; 39 | padding: 0; 40 | margin: 0; 41 | } 42 | 43 | -------------------------------------------------------------------------------- /frontend/src/style/variables.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright (C) 2023 Quan Chen 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | $fake-title-bar-height: 26px; 20 | $layout-header-height: 60px; 21 | $layout-footer-height: 20px; 22 | $layout-left-sidebar-width: 160px; 23 | $layout-right-toolbar-width: 60px; 24 | $layout-sidebar-logo-height: 60px; 25 | 26 | 27 | $theme-logo-font-color: #505050; 28 | 29 | // background-color: #fbfbfb; 30 | /* background-color: #f6f6f6; */ 31 | // background-image: linear-gradient(135deg, #325dff, #529eff); 32 | // $theme-top-header-background-color: #d84042; 33 | 34 | $theme-top-header-background-color: #f4f5f6; 35 | 36 | // background-color: #325eff60; 37 | 38 | $theme-function-box-font-color: #666; 39 | 40 | // $theme-function-box-hover-bg-color: #c73639; 41 | // $theme-function-box-hover-font-color: #505050; 42 | 43 | $theme-function-box-hover-bg-color: #858585d6; 44 | $theme-function-box-hover-font-color: #fff; 45 | 46 | 47 | 48 | // background-color: #e1e1e1; 49 | // background-color: #325effa6; 50 | $theme-function-box-active-color: #bd3134; -------------------------------------------------------------------------------- /frontend/src/view/debug/DebugEditDict.vue: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/src/view/main/MainFooter.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 26 | 27 | 42 | 43 | 62 | -------------------------------------------------------------------------------- /frontend/src/view/setting/SettingSoftware.vue: -------------------------------------------------------------------------------- 1 | 28 | 35 | 36 | 60 | -------------------------------------------------------------------------------- /frontend/src/view/setting/SettingTheme.vue: -------------------------------------------------------------------------------- 1 | 13 | 20 | 21 | 45 | -------------------------------------------------------------------------------- /frontend/src/view/setting/SettingUpdate.vue: -------------------------------------------------------------------------------- 1 | 22 | 56 | 57 | 82 | -------------------------------------------------------------------------------- /frontend/src/vue-shim.d.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Copyright (C) 2023 Quan Chen 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | declare module 'vue-friendly-iframe' 20 | 21 | declare module '*.md' { 22 | import type { ComponentOptions } from 'vue' 23 | const Component: ComponentOptions 24 | export default Component 25 | } 26 | -------------------------------------------------------------------------------- /frontend/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": "./", 4 | "paths": { 5 | "@/*": ["src/*"], 6 | "$/*": ["wails/*"] 7 | }, 8 | "lib": [ "dom","es2015", "es2017" ] 9 | 10 | }, 11 | "include": [ 12 | "src", 13 | "wailsjs" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /frontend/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite'; 2 | import vue from '@vitejs/plugin-vue'; 3 | import alias from '@rollup/plugin-alias'; 4 | 5 | import markdown from 'vite-plugin-md'; 6 | import Inspect from 'vite-plugin-inspect'; 7 | import { resolve } from 'path'; 8 | 9 | const root = resolve(__dirname); 10 | 11 | // https://vitejs.dev/config/ 12 | export default defineConfig({ 13 | publicDir: 'assets', 14 | plugins: [ 15 | alias(), 16 | vue({ 17 | include: [/\.vue$/, /\.md$/], // <-- 18 | 19 | }), 20 | markdown(), 21 | Inspect() 22 | ], 23 | resolve: { 24 | alias: { 25 | "@": resolve(root, "src"), 26 | "$": resolve(root, "wailsjs"), 27 | 'vue': 'vue/dist/vue.esm-bundler.js' 28 | }, 29 | }, 30 | server: { 31 | host: '0.0.0.0', 32 | port: 5173, 33 | open: false, 34 | cors: true, 35 | }, 36 | build: { 37 | outDir: 'dist', 38 | }, 39 | }); 40 | -------------------------------------------------------------------------------- /frontend/wailsjs/go/main/App.d.ts: -------------------------------------------------------------------------------- 1 | // Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL 2 | // This file is automatically generated. DO NOT EDIT 3 | import {model} from '../models'; 4 | 5 | export function BaseDictDir():Promise; 6 | 7 | export function Dispatch(arg1:string,arg2:{[key: string]: any}):Promise; 8 | 9 | export function OpenFinder(arg1:string):Promise; 10 | 11 | export function ResourceServerAddr():Promise; 12 | -------------------------------------------------------------------------------- /frontend/wailsjs/go/main/App.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | // Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL 3 | // This file is automatically generated. DO NOT EDIT 4 | 5 | export function BaseDictDir() { 6 | return window['go']['main']['App']['BaseDictDir'](); 7 | } 8 | 9 | export function Dispatch(arg1, arg2) { 10 | return window['go']['main']['App']['Dispatch'](arg1, arg2); 11 | } 12 | 13 | export function OpenFinder(arg1) { 14 | return window['go']['main']['App']['OpenFinder'](arg1); 15 | } 16 | 17 | export function ResourceServerAddr() { 18 | return window['go']['main']['App']['ResourceServerAddr'](); 19 | } 20 | -------------------------------------------------------------------------------- /frontend/wailsjs/go/models.ts: -------------------------------------------------------------------------------- 1 | export namespace model { 2 | 3 | export class Resp { 4 | data: any; 5 | err: string; 6 | code: number; 7 | 8 | static createFrom(source: any = {}) { 9 | return new Resp(source); 10 | } 11 | 12 | constructor(source: any = {}) { 13 | if ('string' === typeof source) source = JSON.parse(source); 14 | this.data = source["data"]; 15 | this.err = source["err"]; 16 | this.code = source["code"]; 17 | } 18 | } 19 | 20 | } 21 | 22 | -------------------------------------------------------------------------------- /frontend/wailsjs/runtime/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@wailsapp/runtime", 3 | "version": "2.0.0", 4 | "description": "Wails Javascript runtime library", 5 | "main": "runtime.js", 6 | "types": "runtime.d.ts", 7 | "scripts": { 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/wailsapp/wails.git" 12 | }, 13 | "keywords": [ 14 | "Wails", 15 | "Javascript", 16 | "Go" 17 | ], 18 | "author": "Lea Anthony ", 19 | "license": "MIT", 20 | "bugs": { 21 | "url": "https://github.com/wailsapp/wails/issues" 22 | }, 23 | "homepage": "https://github.com/wailsapp/wails#readme" 24 | } 25 | -------------------------------------------------------------------------------- /internal/config/config_test.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2023 Quan Chen 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | package config 18 | 19 | import ( 20 | "github.com/stretchr/testify/assert" 21 | "testing" 22 | ) 23 | 24 | func TestReadConfig(t *testing.T) { 25 | cfg, err := ReadConfig("./testdata/test.toml") 26 | assert.Nil(t, err) 27 | assert.Equal(t, cfg.BaseDictDir, "testdir") 28 | } 29 | -------------------------------------------------------------------------------- /internal/config/config_tmpl_darwin.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2023 Quan Chen 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | package config 18 | 19 | const ConfigTmpl = `BaseDictDir="$APPCONFDIR/dicts" 20 | ` 21 | -------------------------------------------------------------------------------- /internal/config/config_tmpl_linux.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2023 Quan Chen 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | package config 18 | 19 | const ConfigTmpl = `BaseDictDir="$HOME/dicts" 20 | ` 21 | -------------------------------------------------------------------------------- /internal/config/config_tmpl_windows.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2023 Quan Chen 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | package config 18 | 19 | const ConfigTmpl = `BaseDictDir="$APPCONFDIR\\dicts" 20 | ` 21 | -------------------------------------------------------------------------------- /internal/config/preset_dict.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import "embed" 4 | 5 | // preset/ 6 | var defaultDictIfo embed.FS 7 | -------------------------------------------------------------------------------- /internal/config/testdata/test.toml: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2023 Quan Chen 3 | # 4 | # This program is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # (at your option) any later version. 8 | # 9 | # This program is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with this program. If not, see . 16 | 17 | BaseDictDir="testdir" 18 | StaticServerPort=1234 19 | APIServerPort=8080 -------------------------------------------------------------------------------- /internal/entry/app_loader.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2023 Quan Chen 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | package entry 18 | 19 | import ( 20 | "errors" 21 | "fmt" 22 | "os" 23 | "path/filepath" 24 | 25 | "github.com/terasum/medict/internal/config" 26 | "github.com/terasum/medict/internal/utils" 27 | ) 28 | 29 | var cfg *config.Config 30 | 31 | func defaultConfigPath() (string, error) { 32 | // should raise error 33 | appConfigDir, err := utils.AppConfigDir() 34 | if err != nil { 35 | return "", err 36 | } 37 | fmt.Printf("[medict-init]: default config dir: %s\n", appConfigDir) 38 | 39 | configFile := filepath.Join(appConfigDir, "medict.toml") 40 | if _, err = os.Stat(configFile); errors.Is(err, os.ErrNotExist) { 41 | err = os.WriteFile(configFile, []byte(config.ConfigTmpl), 0644) 42 | if err != nil { 43 | return "", err 44 | } 45 | } 46 | 47 | fmt.Printf("[medict-init]: default config file: %s\n", configFile) 48 | return configFile, nil 49 | } 50 | 51 | func loadConfig() (*config.Config, error) { 52 | var err error 53 | var configPath = "" 54 | if cfg != nil { 55 | return cfg, nil 56 | } 57 | 58 | configPath, err = defaultConfigPath() 59 | if err != nil { 60 | return nil, err 61 | } 62 | 63 | cfg, err = config.ReadConfig(configPath) 64 | if err != nil { 65 | return nil, err 66 | } 67 | fmt.Printf("[medict-init]: config dicts dir: %s\n", cfg.BaseDictDir) 68 | return cfg, nil 69 | } 70 | 71 | func LoadApp() (*config.Config, error) { 72 | conf, err := loadConfig() 73 | if err != nil { 74 | return nil, err 75 | } 76 | conf.BaseDictDir = conf.EnsureDictsDir() 77 | 78 | err = WritePresetDictionary(conf.BaseDictDir) 79 | if err != nil { 80 | return nil, err 81 | } 82 | 83 | return conf, nil 84 | } 85 | -------------------------------------------------------------------------------- /internal/entry/app_loader_test.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2023 Quan Chen 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | package entry 18 | 19 | import ( 20 | "github.com/terasum/medict/pkg/service" 21 | "testing" 22 | ) 23 | 24 | func TestDefaultConfig(t *testing.T) { 25 | config, err := LoadApp() 26 | if err != nil { 27 | t.Fatal(err) 28 | } 29 | t.Logf(config.ConfigPath) 30 | t.Logf(config.BaseDictDir) 31 | t.Logf(config.ConfigStruct.BaseDictDir) 32 | } 33 | 34 | func TestEnsureConfigDir(t *testing.T) { 35 | config, err := LoadApp() 36 | if err != nil { 37 | t.Fatal(err) 38 | } 39 | t.Logf(config.ConfigPath) 40 | t.Logf(config.BaseDictDir) 41 | t.Logf(config.ConfigStruct.BaseDictDir) 42 | t.Logf(config.EnsureDictsDir()) 43 | } 44 | 45 | func TestLoadApp(t *testing.T) { 46 | conf, err := LoadApp() 47 | if err != nil { 48 | t.Fatal(err) 49 | } 50 | 51 | dir := conf.EnsureDictsDir() 52 | t.Logf(dir) 53 | 54 | svc, err := service.NewDictService(conf) 55 | if err != nil { 56 | t.Fatal(err) 57 | } 58 | 59 | dicts := svc.Dicts() 60 | 61 | for _, dict := range dicts { 62 | t.Logf("dict name: %s", dict.Name) 63 | 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /internal/entry/app_preset.go: -------------------------------------------------------------------------------- 1 | package entry 2 | 3 | import ( 4 | _ "embed" 5 | "os" 6 | "path/filepath" 7 | 8 | "github.com/terasum/medict/internal/utils" 9 | ) 10 | 11 | //go:embed preset/cc-cedict/cc-cedict.mdx 12 | var PresetMdictMdxFile []byte 13 | 14 | //go:embed preset/cc-cedict/cc-cedict.mdd 15 | var PresetMdictMddFile []byte 16 | 17 | //go:embed preset/cc-cedict/cc-cedict.css 18 | var PresetMdictCSSFile []byte 19 | 20 | //go:embed preset/cc-cedict/cover.png 21 | var PresetMdictCoverImg []byte 22 | 23 | func WritePresetDictionary(baseDictDir string) error { 24 | fullpath := filepath.Join(baseDictDir, "cc-cedict") 25 | if !utils.FileExists(fullpath) { 26 | if err := os.MkdirAll(fullpath, 0755); err != nil { 27 | return err 28 | } 29 | } 30 | 31 | mdxfilePath := filepath.Join(fullpath, "cc-cedict.mdx") 32 | if !utils.FileExists(mdxfilePath) { 33 | err := os.WriteFile(mdxfilePath, PresetMdictMdxFile, 0644) 34 | if err != nil { 35 | return err 36 | } 37 | } 38 | 39 | mddfilePath := filepath.Join(fullpath, "cc-cedict.mdd") 40 | if !utils.FileExists(mddfilePath) { 41 | err := os.WriteFile(mddfilePath, PresetMdictMddFile, 0644) 42 | if err != nil { 43 | return err 44 | } 45 | } 46 | 47 | cssfilePath := filepath.Join(fullpath, "cc-cedict.css") 48 | if !utils.FileExists(cssfilePath) { 49 | err := os.WriteFile(cssfilePath, PresetMdictCSSFile, 0644) 50 | if err != nil { 51 | return err 52 | } 53 | } 54 | 55 | coverfilePath := filepath.Join(fullpath, "cover.png") 56 | if !utils.FileExists(coverfilePath) { 57 | err := os.WriteFile(coverfilePath, PresetMdictCoverImg, 0644) 58 | if err != nil { 59 | return err 60 | } 61 | } 62 | 63 | return nil 64 | } 65 | -------------------------------------------------------------------------------- /internal/entry/app_preset_test.go: -------------------------------------------------------------------------------- 1 | package entry 2 | 3 | import ( 4 | _ "embed" 5 | "testing" 6 | ) 7 | 8 | func TestWritePresetDictionary(t *testing.T) { 9 | err := WritePresetDictionary("testdata/out") 10 | if err != nil { 11 | t.Fatal(err) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /internal/entry/preset/cc-cedict/cc-cedict.mdd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terasum/medict/138f5198ef0034909f9872ce580bb4fddf31fca9/internal/entry/preset/cc-cedict/cc-cedict.mdd -------------------------------------------------------------------------------- /internal/entry/preset/cc-cedict/cc-cedict.mdx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terasum/medict/138f5198ef0034909f9872ce580bb4fddf31fca9/internal/entry/preset/cc-cedict/cc-cedict.mdx -------------------------------------------------------------------------------- /internal/entry/preset/cc-cedict/cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terasum/medict/138f5198ef0034909f9872ce580bb4fddf31fca9/internal/entry/preset/cc-cedict/cover.png -------------------------------------------------------------------------------- /internal/entry/preset/dictd-elements/cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terasum/medict/138f5198ef0034909f9872ce580bb4fddf31fca9/internal/entry/preset/dictd-elements/cover.png -------------------------------------------------------------------------------- /internal/entry/preset/dictd-elements/dictd-elements.dict.dz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terasum/medict/138f5198ef0034909f9872ce580bb4fddf31fca9/internal/entry/preset/dictd-elements/dictd-elements.dict.dz -------------------------------------------------------------------------------- /internal/entry/preset/dictd-elements/dictd-elements.idx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terasum/medict/138f5198ef0034909f9872ce580bb4fddf31fca9/internal/entry/preset/dictd-elements/dictd-elements.idx -------------------------------------------------------------------------------- /internal/entry/preset/dictd-elements/dictd-elements.ifo: -------------------------------------------------------------------------------- 1 | StarDict's dict ifo file 2 | version=2.4.2 3 | wordcount=127 4 | idxfilesize=2147 5 | bookname=dictd_www.dict.org_elements 6 | date=2003.05.13 7 | sametypesequence=m 8 | -------------------------------------------------------------------------------- /internal/libs/bktree/.gitignore: -------------------------------------------------------------------------------- 1 | pprof/ 2 | -------------------------------------------------------------------------------- /internal/libs/bktree/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 Naomichi Agata 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /internal/libs/bktree/README.md: -------------------------------------------------------------------------------- 1 | ## bktree 2 | 3 | This is an implementation of [BK-tree](https://en.wikipedia.org/wiki/BK-tree) for golang. 4 | BK-tree is a tree data structure for similarity search in a metric space. 5 | Using BK-tree, you can search neighbors of a data from the metric space efficiently. 6 | 7 | ### Performance 8 | 9 | Search similar values from 1,000,000 data. 10 | Data is 64 bits integer, and distance function is hamming distance. 11 | (see `bktree_test.go` for detail) 12 | 13 | ``` 14 | BenchmarkSearch_ExactForLargeTree-2 1000000 3540 ns/op 15 | BenchmarkSearch_Tolerance1ForLargeTree-2 30000 85227 ns/op 16 | BenchmarkSearch_Tolerance2ForLargeTree-2 3000 907897 ns/op 17 | BenchmarkSearch_Tolerance4ForLargeTree-2 200 17273811 ns/op 18 | BenchmarkSearch_Tolerance8ForLargeTree-2 10 234244862 ns/op 19 | BenchmarkSearch_Tolerance32ForLargeTree-2 3 722881937 ns/op 20 | 21 | BenchmarkLinearSearchForLargeSet-2 10 281977270 ns/op 22 | ``` 23 | 24 | If the tolerance is small enough, BK-tree is much faster than naive linear search. 25 | 26 | 27 | ### Example 28 | 29 | see `_example/` direcotry. 30 | 31 | ### Install 32 | 33 | ``` 34 | $ go get github.com/agatan/bktree 35 | ``` 36 | 37 | ### License 38 | 39 | MIT 40 | 41 | -------------------------------------------------------------------------------- /internal/libs/bktree/_example/hamming/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/agatan/bktree" 7 | ) 8 | 9 | type hashValue uint16 10 | 11 | // Distance calculates hamming distance. 12 | func (h hashValue) Distance(e bktree.Entry) int { 13 | a := uint16(h) 14 | b := uint16(e.(hashValue)) 15 | 16 | d := 0 17 | var k uint16 = 1 18 | for i := 0; i < 16; i++ { 19 | if a&k != b&k { 20 | d++ 21 | } 22 | k <<= 1 23 | } 24 | return d 25 | } 26 | 27 | func main() { 28 | var tree bktree.BKTree 29 | // add 0x0000 to 0xffff to the tree. 30 | for i := 0; i < 0xffff; i++ { 31 | tree.Add(hashValue(i)) 32 | } 33 | 34 | // search neighbors of 0x00000000 whose distances are less than or equal to 1. 35 | results := tree.Search(hashValue(0), 1) 36 | for _, result := range results { 37 | fmt.Printf("%016b (distance: %d)\n", result.Entry.(hashValue), result.Distance) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /internal/libs/bktree/_example/levenshtein/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/terasum/medict/internal/libs/bktree" 6 | 7 | levenshtein "github.com/creasty/go-levenshtein" 8 | ) 9 | 10 | type word string 11 | 12 | // Distance calculates hamming distance. 13 | func (x word) Distance(e bktree.Entry) int { 14 | a := string(x) 15 | b := string(e.(word)) 16 | 17 | return levenshtein.Distance(a, b) 18 | } 19 | 20 | func main() { 21 | var tree bktree.BKTree 22 | // add words 23 | words := []string{"apple", "banana", "orange", "peach", "bean", "tomato", "egg", "pineapple"} 24 | for _, w := range words { 25 | tree.Add(word(w)) 26 | } 27 | 28 | // spell check 29 | results := tree.Search(word("peacn"), 2, 10) 30 | fmt.Println("Input is peacn. Did you mean:") 31 | for _, result := range results { 32 | fmt.Printf("\t%s (distance: %d)\n", result.Entry.(word), result.Distance) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /internal/libs/bktree/bktree.go: -------------------------------------------------------------------------------- 1 | package bktree 2 | 3 | type BKTree struct { 4 | root *node 5 | } 6 | 7 | type node struct { 8 | entry Entry 9 | children []struct { 10 | distance int 11 | node *node 12 | } 13 | } 14 | 15 | func (n *node) addChild(e Entry) { 16 | newnode := &node{entry: e} 17 | loop: 18 | d := n.entry.Distance(e) 19 | for _, c := range n.children { 20 | if c.distance == d { 21 | n = c.node 22 | goto loop 23 | } 24 | } 25 | n.children = append(n.children, struct { 26 | distance int 27 | node *node 28 | }{d, newnode}) 29 | } 30 | 31 | type Entry interface { 32 | Distance(Entry) int 33 | } 34 | 35 | func (bk *BKTree) Add(entry Entry) { 36 | if bk.root == nil { 37 | bk.root = &node{ 38 | entry: entry, 39 | } 40 | return 41 | } 42 | bk.root.addChild(entry) 43 | } 44 | 45 | type Result struct { 46 | Distance int 47 | Entry Entry 48 | } 49 | 50 | func (bk *BKTree) Search(needle Entry, tolerance int, limit int) []*Result { 51 | results := make([]*Result, 0) 52 | if bk.root == nil { 53 | return results 54 | } 55 | candidates := []*node{bk.root} 56 | count := 0 57 | for len(candidates) != 0 { 58 | c := candidates[len(candidates)-1] 59 | candidates = candidates[:len(candidates)-1] 60 | d := c.entry.Distance(needle) 61 | if d <= tolerance { 62 | results = append(results, &Result{ 63 | Distance: d, 64 | Entry: c.entry, 65 | }) 66 | count += 1 67 | if count >= limit { 68 | return results 69 | } 70 | 71 | } 72 | 73 | low, high := d-tolerance, d+tolerance 74 | for _, c := range c.children { 75 | if low <= c.distance && c.distance <= high { 76 | candidates = append(candidates, c.node) 77 | } 78 | } 79 | } 80 | return results 81 | } 82 | -------------------------------------------------------------------------------- /internal/libs/go-adaptive-radix-tree/.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "" # See documentation for possible values 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "monthly" 12 | -------------------------------------------------------------------------------- /internal/libs/go-adaptive-radix-tree/.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | 6 | # Folders 7 | _obj 8 | _test 9 | 10 | # Architecture specific extensions/prefixes 11 | *.[568vq] 12 | [568vq].out 13 | 14 | *.cgo1.go 15 | *.cgo2.c 16 | _cgo_defun.c 17 | _cgo_gotypes.go 18 | _cgo_export.* 19 | 20 | _testmain.go 21 | 22 | *.exe 23 | *.test 24 | *.prof 25 | -------------------------------------------------------------------------------- /internal/libs/go-adaptive-radix-tree/.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | sudo: false 3 | 4 | go: 5 | - "1.13" 6 | - "1.14" 7 | - tip 8 | 9 | install: 10 | - make bootstrap 11 | 12 | before_script: 13 | - go vet ./... 14 | 15 | script: 16 | - make 17 | - make test-cover-builder 18 | - $GOPATH/bin/goveralls -service=travis-ci -coverprofile=/tmp/art_coverage.out 19 | -------------------------------------------------------------------------------- /internal/libs/go-adaptive-radix-tree/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Pavel Larkin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /internal/libs/go-adaptive-radix-tree/consts.go: -------------------------------------------------------------------------------- 1 | package art 2 | 3 | // node constraints 4 | const ( 5 | node4Min = 2 6 | node4Max = 4 7 | 8 | node16Min = node4Max + 1 9 | node16Max = 16 10 | 11 | node48Min = node16Max + 1 12 | node48Max = 48 13 | 14 | node256Min = node48Max + 1 15 | node256Max = 256 16 | ) 17 | 18 | const ( 19 | // MaxPrefixLen is maximum prefix length for internal nodes. 20 | MaxPrefixLen = 10 21 | ) 22 | -------------------------------------------------------------------------------- /internal/libs/go-adaptive-radix-tree/doc.go: -------------------------------------------------------------------------------- 1 | // Package art implements an Adapative Radix Tree(ART) in pure Go. 2 | // Note that this implementation is not thread-safe but it could be really easy to implement. 3 | // 4 | // The design of ART is based on "The Adaptive Radix Tree: ARTful Indexing for Main-Memory Databases" [1]. 5 | // 6 | // Usage 7 | // 8 | // package main 9 | // 10 | // import ( 11 | // "fmt" 12 | // "github.com/plar/go-adaptive-radix-tree" 13 | // ) 14 | // 15 | // func main() { 16 | // 17 | // tree := art.New() 18 | // 19 | // tree.Insert(art.Key("Hi, I'm Key"), "Nice to meet you, I'm Value") 20 | // value, found := tree.Search(art.Key("Hi, I'm Key")) 21 | // if found { 22 | // fmt.Printf("Search value=%v\n", value) 23 | // } 24 | // 25 | // tree.ForEach(func(node art.Node) bool { 26 | // fmt.Printf("Callback value=%v\n", node.Value()) 27 | // return true 28 | // } 29 | // 30 | // for it := tree.Iterator(); it.HasNext(); { 31 | // value, _ := it.Next() 32 | // fmt.Printf("Iterator value=%v\n", value.Value()) 33 | // } 34 | // } 35 | // 36 | // // Output: 37 | // // Search value=Nice to meet you, I'm Value 38 | // // Callback value=Nice to meet you, I'm Value 39 | // // Iterator value=Nice to meet you, I'm Value 40 | // 41 | // 42 | // Also the current implementation was inspired by [2] and [3] 43 | // 44 | // [1] http://db.in.tum.de/~leis/papers/ART.pdf (Specification) 45 | // 46 | // [2] https://github.com/armon/libart (C99 implementation) 47 | // 48 | // [3] https://github.com/kellydunn/go-art (other Go implementation) 49 | package art 50 | -------------------------------------------------------------------------------- /internal/libs/go-adaptive-radix-tree/examples/tree.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | art "github.com/terasum/medict/internal/libs/go-adaptive-radix-tree" 7 | ) 8 | 9 | func DumpTree() { 10 | tree := art.New() 11 | terms := []string{"A", "a", "aa"} 12 | for _, term := range terms { 13 | tree.Insert(art.Key(term), term) 14 | } 15 | fmt.Println(tree) 16 | } 17 | 18 | func SimpleTree() { 19 | tree := art.New() 20 | 21 | tree.Insert(art.Key("Hi, I'm Key"), "Nice to meet you, I'm Value") 22 | value, found := tree.Search(art.Key("Hi, I'm Key")) 23 | if found { 24 | fmt.Printf("Search value=%v\n", value) 25 | } 26 | 27 | tree.ForEach(func(node art.Node) bool { 28 | fmt.Printf("Callback value=%v\n", node.Value()) 29 | return true 30 | }) 31 | 32 | for it := tree.Iterator(); it.HasNext(); { 33 | value, _ := it.Next() 34 | fmt.Printf("Iterator value=%v\n", value.Value()) 35 | } 36 | } 37 | 38 | func main() { 39 | DumpTree() 40 | SimpleTree() 41 | } 42 | -------------------------------------------------------------------------------- /internal/libs/go-adaptive-radix-tree/factory.go: -------------------------------------------------------------------------------- 1 | package art 2 | 3 | import ( 4 | "unsafe" 5 | ) 6 | 7 | type nodeFactory interface { 8 | newNode4() *artNode 9 | newNode16() *artNode 10 | newNode48() *artNode 11 | newNode256() *artNode 12 | newLeaf(key Key, value interface{}) *artNode 13 | } 14 | 15 | // make sure that objFactory implements all methods of nodeFactory interface 16 | var _ nodeFactory = &objFactory{} 17 | 18 | var factory = newObjFactory() 19 | 20 | func newTree() *tree { 21 | return &tree{} 22 | } 23 | 24 | type objFactory struct{} 25 | 26 | func newObjFactory() nodeFactory { 27 | return &objFactory{} 28 | } 29 | 30 | // Simple obj factory implementation 31 | func (f *objFactory) newNode4() *artNode { 32 | return &artNode{kind: Node4, ref: unsafe.Pointer(new(node4))} 33 | } 34 | 35 | func (f *objFactory) newNode16() *artNode { 36 | return &artNode{kind: Node16, ref: unsafe.Pointer(&node16{})} 37 | } 38 | 39 | func (f *objFactory) newNode48() *artNode { 40 | return &artNode{kind: Node48, ref: unsafe.Pointer(&node48{})} 41 | } 42 | 43 | func (f *objFactory) newNode256() *artNode { 44 | return &artNode{kind: Node256, ref: unsafe.Pointer(&node256{})} 45 | } 46 | 47 | func (f *objFactory) newLeaf(key Key, value interface{}) *artNode { 48 | clonedKey := make(Key, len(key)) 49 | copy(clonedKey, key) 50 | return &artNode{ 51 | kind: Leaf, 52 | ref: unsafe.Pointer(&leaf{key: clonedKey, value: value}), 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /internal/libs/go-adaptive-radix-tree/makefile: -------------------------------------------------------------------------------- 1 | EXTERNAL_TOOLS=\ 2 | golang.org/x/tools/cmd/cover \ 3 | golang.org/x/tools/cmd/vet \ 4 | github.com/mattn/goveralls \ 5 | github.com/stretchr/testify/assert 6 | 7 | 8 | all: all-tests 9 | @echo "*** Done!" 10 | 11 | get: 12 | @echo "*** Resolve dependencies..." 13 | @go get -v . 14 | 15 | all-tests: 16 | @echo "*** Run tests..." 17 | @go test . 18 | 19 | benchmark: 20 | @echo "*** Run benchmarks..." 21 | @go test -v -benchmem -bench=. -run=^a 22 | 23 | test-race: 24 | @echo "*** Run tests with race condition..." 25 | @go test --race -v . 26 | 27 | test-cover-builder: 28 | @go test -covermode=count -coverprofile=/tmp/art.out . 29 | 30 | @rm -f /tmp/art_coverage.out 31 | @echo "mode: count" > /tmp/art_coverage.out 32 | @cat /tmp/art.out | tail -n +2 >> /tmp/art_coverage.out 33 | @rm /tmp/art.out 34 | 35 | test-cover: test-cover-builder 36 | @go tool cover -html=/tmp/art_coverage.out 37 | 38 | build: 39 | @echo "*** Build project..." 40 | @go build -v . 41 | 42 | build-asm: 43 | @go build -a -work -v -gcflags="-S -B -C" . 44 | 45 | build-race: 46 | @echo "*** Build project with race condition..." 47 | @go build --race -v . 48 | 49 | bootstrap: 50 | @for tool in $(EXTERNAL_TOOLS) ; do \ 51 | echo "Installing $$tool" ; \ 52 | go get $$tool; \ 53 | done 54 | -------------------------------------------------------------------------------- /internal/libs/go-adaptive-radix-tree/utils.go: -------------------------------------------------------------------------------- 1 | package art 2 | 3 | func min(a, b uint32) uint32 { 4 | if a < b { 5 | return a 6 | } 7 | return b 8 | } 9 | -------------------------------------------------------------------------------- /internal/libs/go-mdict/.gitignore: -------------------------------------------------------------------------------- 1 | /testdata/out/ 2 | /testdata/dict/ 3 | /testdata/bugdict/ -------------------------------------------------------------------------------- /internal/libs/go-mdict/mdict_accessor.go: -------------------------------------------------------------------------------- 1 | package go_mdict 2 | 3 | import "encoding/json" 4 | 5 | type MdictAccessor struct { 6 | Filepath string `json:"filepath"` 7 | IsRecordEncrypted bool `json:"is_record_encrypted"` 8 | IsMDD bool `json:"is_mdd"` 9 | IsUTF16 bool `json:"is_utf_16"` 10 | } 11 | 12 | func NewAccessor(mdict *Mdict) *MdictAccessor { 13 | return &MdictAccessor{ 14 | Filepath: mdict.filePath, 15 | IsRecordEncrypted: mdict.meta.encryptType == EncryptRecordEnc, 16 | IsMDD: mdict.fileType == MdictTypeMdd, 17 | IsUTF16: mdict.meta.encoding == EncodingUtf16, 18 | } 19 | } 20 | 21 | func NewAccessorFromJson(data []byte) (*MdictAccessor, error) { 22 | mdi := new(MdictAccessor) 23 | err := json.Unmarshal(data, mdi) 24 | return mdi, err 25 | } 26 | 27 | func (mdi *MdictAccessor) Serialize() ([]byte, error) { 28 | return json.Marshal(mdi) 29 | } 30 | 31 | func (mdi *MdictAccessor) RetrieveDefByIndex(index *MDictKeywordIndex) ([]byte, error) { 32 | return locateDefByKWIndex(index, mdi.Filepath, mdi.IsRecordEncrypted, mdi.IsMDD, mdi.IsUTF16) 33 | } 34 | -------------------------------------------------------------------------------- /internal/libs/go-mdict/mdict_oale9_test.go: -------------------------------------------------------------------------------- 1 | package go_mdict 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestOALE9(t *testing.T) { 8 | dict, err := New("testdata/mdx/testdict.mdx") 9 | if err != nil { 10 | t.Error(err) 11 | } 12 | 13 | err = dict.BuildIndex() 14 | if err != nil { 15 | t.Fatal(err) 16 | } 17 | t.Logf("Digest:\n-----------------------------\n%s\n", dict.Digest()) 18 | 19 | keywordEntries, err := dict.GetKeyWordEntries() 20 | if err != nil { 21 | t.Fatal(err) 22 | } 23 | for idx, entry := range keywordEntries { 24 | if idx > 10 { 25 | break 26 | } 27 | t.Logf("\n\n-----------\n\n") 28 | t.Logf("keyword: %s", entry.KeyWord) 29 | index, err := dict.KeywordEntryToIndex(entry) 30 | if err != nil { 31 | t.Fatal(err) 32 | } 33 | t.Logf("index: %+v", index) 34 | 35 | def, err := dict.LocateByKeywordIndex(index) 36 | if err != nil { 37 | t.Fatal(err) 38 | } 39 | t.Logf("def: %s", def) 40 | 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /internal/libs/go-mdict/mdict_record_range_tree.go: -------------------------------------------------------------------------------- 1 | package go_mdict 2 | 3 | type RecordBlockRangeTreeNode struct { 4 | startRange int64 5 | endRange int64 6 | data *MdictRecordBlockInfoListItem 7 | left *RecordBlockRangeTreeNode 8 | right *RecordBlockRangeTreeNode 9 | } 10 | 11 | func BuildRangeTree(list []*MdictRecordBlockInfoListItem, root *RecordBlockRangeTreeNode) { 12 | if len(list) == 0 { 13 | return 14 | } 15 | 16 | if len(list) == 1 { 17 | root.data = list[0] 18 | root.startRange = list[0].deCompressAccumulatorOffset 19 | root.endRange = list[0].deCompressAccumulatorOffset + list[0].deCompressSize 20 | return 21 | } 22 | 23 | if len(list) == 2 { 24 | root.startRange = list[0].deCompressAccumulatorOffset 25 | root.endRange = list[1].deCompressAccumulatorOffset + list[1].deCompressSize 26 | root.left = new(RecordBlockRangeTreeNode) 27 | BuildRangeTree(list[:1], root.left) 28 | root.right = new(RecordBlockRangeTreeNode) 29 | BuildRangeTree(list[1:], root.right) 30 | return 31 | } 32 | 33 | root.startRange = list[0].deCompressAccumulatorOffset 34 | root.endRange = list[len(list)-1].deCompressAccumulatorOffset + list[len(list)-1].deCompressSize 35 | 36 | mid := (0 + len(list) - 1) / 2 37 | if mid > 0 { 38 | root.left = new(RecordBlockRangeTreeNode) 39 | BuildRangeTree(list[0:mid], root.left) 40 | } 41 | 42 | if mid < len(list) { 43 | root.right = new(RecordBlockRangeTreeNode) 44 | BuildRangeTree(list[mid:], root.right) 45 | } 46 | 47 | } 48 | 49 | func QueryRangeData(root *RecordBlockRangeTreeNode, queryRange int64) *MdictRecordBlockInfoListItem { 50 | if root == nil { 51 | return nil 52 | } 53 | 54 | if root.startRange > queryRange || root.endRange < queryRange { 55 | return nil 56 | } else { 57 | if root.data != nil { 58 | return root.data 59 | } 60 | 61 | if root.left != nil && root.left.endRange > queryRange { 62 | return QueryRangeData(root.left, queryRange) 63 | } 64 | 65 | if root.right != nil && root.right.startRange <= queryRange { 66 | return QueryRangeData(root.right, queryRange) 67 | } 68 | return nil 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /internal/libs/go-mdict/xml_dictionary.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2023 Quan Chen 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | package go_mdict 18 | 19 | import ( 20 | "encoding/xml" 21 | "strings" 22 | ) 23 | 24 | // Dictionary was generated 2023-09-11 11:07:50 by https://xml-to-go.github.io/ in Ukraine. 25 | type Dictionary struct { 26 | XMLName xml.Name `xml:"Dictionary"` 27 | Text string `xml:"chardata"` 28 | GeneratedByEngineVersion string `xml:"GeneratedByEngineVersion,attr"` 29 | RequiredEngineVersion string `xml:"RequiredEngineVersion,attr"` 30 | Encrypted string `xml:"Encrypted,attr"` 31 | Encoding string `xml:"IsUTF16,attr"` 32 | Format string `xml:"Format,attr"` 33 | Stripkey string `xml:"Stripkey,attr"` 34 | CreationDate string `xml:"creationDate,attr"` 35 | Compact string `xml:"Compact,attr"` 36 | Compat string `xml:"Compat,attr"` 37 | KeyCaseSensitive string `xml:"KeyCaseSensitive,attr"` 38 | Description string `xml:"Description,attr"` 39 | Title string `xml:"Title,attr"` 40 | DataSourceFormat string `xml:"DataSourceFormat,attr"` 41 | StyleSheet string `xml:"StyleSheet,attr"` 42 | Left2Right string `xml:"Left2Right,attr"` 43 | RegisterBy string `xml:"RegisterBy,attr"` 44 | } 45 | 46 | func parseXMLHeader(xmldata string) (*Dictionary, error) { 47 | dic := &Dictionary{} 48 | err := xml.Unmarshal([]byte(strings.TrimSpace(xmldata)), dic) 49 | if err != nil { 50 | return nil, err 51 | } 52 | return dic, nil 53 | } 54 | -------------------------------------------------------------------------------- /internal/libs/go-patricia/.gitignore: -------------------------------------------------------------------------------- 1 | # Swap files. 2 | *.swp 3 | 4 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 5 | *.o 6 | *.a 7 | *.so 8 | 9 | # Folders 10 | _obj 11 | _test 12 | 13 | # Architecture specific extensions/prefixes 14 | *.[568vq] 15 | [568vq].out 16 | 17 | *.cgo1.go 18 | *.cgo2.c 19 | _cgo_defun.c 20 | _cgo_gotypes.go 21 | _cgo_export.* 22 | 23 | _testmain.go 24 | 25 | *.exe 26 | -------------------------------------------------------------------------------- /internal/libs/go-patricia/AUTHORS: -------------------------------------------------------------------------------- 1 | This is the complete list of go-patricia copyright holders: 2 | 3 | Ondřej Kupka 4 | -------------------------------------------------------------------------------- /internal/libs/go-patricia/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 The AUTHORS 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /internal/libs/go-stardict/.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | 6 | # Folders 7 | _obj 8 | _test 9 | 10 | # Architecture specific extensions/prefixes 11 | *.[568vq] 12 | [568vq].out 13 | 14 | *.cgo1.go 15 | *.cgo2.c 16 | _cgo_defun.c 17 | _cgo_gotypes.go 18 | _cgo_export.* 19 | 20 | _testmain.go 21 | 22 | *.exe 23 | *.test 24 | *.prof 25 | -------------------------------------------------------------------------------- /internal/libs/go-stardict/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Vitaly Dyatlov 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /internal/libs/go-stardict/README.md: -------------------------------------------------------------------------------- 1 | GO STARDICT 2 | ======= 3 | 4 | To download and install this package run: 5 | 6 | `go get github.com/dyatlov/gostardict/stardict` 7 | 8 | Source docs: http://godoc.org/github.com/dyatlov/gostardict/stardict 9 | 10 | Disclaimer 11 | --- 12 | The code is currently undocumented, and is certainly **not idiomatic Go**. Pull requests are welcome! 13 | 14 | Samples 15 | --- 16 | Sample code can be found in [`gostardict/samples`](https://github.com/dyatlov/gostardict/tree/master/samples). 17 | 18 | Project Overview 19 | --- 20 | The project was started as an attempt to read stardict dictionaries in language learning webservice and grew into a tool supporting several dictionary formats. 21 | 22 | Current limitations: 23 | 24 | * Whole dictionary and index are fully loaded into memory for fast random access 25 | * DictZip format is not supported, it is processed as a simple GZip format (means that no random blocks access is supported as in DictZip) 26 | * Syn files are not processed 27 | * There's no recovering from errors (means that dictionaries should be well formed) 28 | 29 | Not tested but should be working in theory (I didn't find dictionaries with those properties in place): 30 | 31 | * 64bit offsets 32 | * multi typed dictionary fields 33 | 34 | 35 | Dictionary Functions 36 | --- 37 | `func NewDictionary(path string, name string) (*Dictionary, error)` - returns `gostardict.Dictionary` struct. `path` - path to dictionary files, `name` - name of dictionary to parse 38 | 39 | `func (d Dictionary) GetBookName() string` - returns dictionary' book name (from ifo file) 40 | 41 | `func (d Dictionary) GetWordCount() uint64` - returns dictionary' word count (from ifo file) 42 | 43 | Additional links 44 | --- 45 | * Stardict format: https://code.google.com/p/babiloo/wiki/StarDict_format 46 | * Dictionaries: http://abloz.com/huzheng/stardict-dic/ 47 | 48 | Work Opportunities 49 | --- 50 | If you need a Golang developer feel free to contact with me :) 51 | -------------------------------------------------------------------------------- /internal/libs/go-stardict/stardict/dict.go: -------------------------------------------------------------------------------- 1 | package stardict 2 | 3 | import ( 4 | "compress/gzip" 5 | "io" 6 | "io/ioutil" 7 | "os" 8 | "strings" 9 | ) 10 | 11 | // RawDict implements in-memory dictionary 12 | type RawDict struct { 13 | buffer []byte 14 | } 15 | 16 | // GetSequence returns data at the given offset 17 | func (d *RawDict) GetSequence(offset uint64, size uint64) []byte { 18 | return d.buffer[offset:(offset + size)] 19 | } 20 | 21 | // readDict reads dictionary into memory 22 | func readDict(filename string, info *RawInfo) (dict *RawDict, err error) { 23 | reader, err := os.Open(filename) 24 | if err != nil { 25 | return 26 | } 27 | defer reader.Close() 28 | 29 | var r io.Reader 30 | 31 | if strings.HasSuffix(filename, ".dz") { // if file is compressed then read it from archive 32 | r, err = gzip.NewReader(reader) 33 | } else { 34 | r = reader 35 | } 36 | 37 | if err != nil { 38 | return 39 | } 40 | 41 | buffer, err := ioutil.ReadAll(r) 42 | 43 | if err != nil { 44 | return 45 | } 46 | 47 | dict = new(RawDict) 48 | dict.buffer = buffer 49 | 50 | return 51 | } 52 | -------------------------------------------------------------------------------- /internal/libs/go-stardict/stardict/ifo.go: -------------------------------------------------------------------------------- 1 | package stardict 2 | 3 | import ( 4 | "bufio" 5 | "errors" 6 | "io" 7 | "os" 8 | "strings" 9 | ) 10 | 11 | // RawInfo contains dictionary options 12 | type RawInfo struct { 13 | Version string 14 | Is64 bool 15 | Options map[string]string 16 | } 17 | 18 | func decodeOption(str string) (key string, value string, err error) { 19 | a := strings.Split(str, "=") 20 | 21 | if len(a) < 2 { 22 | return "", "", errors.New("Invalid file format: " + str) 23 | } 24 | 25 | return a[0], a[1], nil 26 | } 27 | 28 | // readInfo reads ifo file and collects dictionary options 29 | func readInfo(filename string) (info *RawInfo, err error) { 30 | reader, err := os.Open(filename) 31 | if err != nil { 32 | return 33 | } 34 | 35 | defer reader.Close() 36 | 37 | r := bufio.NewReader(reader) 38 | 39 | _, err = r.ReadString('\n') 40 | 41 | if err != nil { 42 | return 43 | } 44 | 45 | version, err := r.ReadString('\n') 46 | 47 | if err != nil { 48 | return 49 | } 50 | 51 | kn, kv, err := decodeOption(version[:len(version)-1]) 52 | 53 | if err != nil { 54 | return 55 | } 56 | 57 | if kn != "version" { 58 | err = errors.New("version missing (should be on second line)") 59 | return 60 | } 61 | 62 | if kv != "2.4.2" && kv != "3.0.0" && kv != "2.4.2\r" && kv != "3.0.0\r" { // \r : fix the problem on windows 63 | err = errors.New("stardict version should be either 2.4.2 or 3.0.0") 64 | return 65 | } 66 | 67 | info = new(RawInfo) 68 | 69 | info.Version = kv 70 | 71 | info.Options = make(map[string]string) 72 | 73 | for { 74 | option, err := r.ReadString('\n') 75 | 76 | if err != nil && err != io.EOF { 77 | return info, err 78 | } 79 | 80 | if err == io.EOF && len(option) == 0 { 81 | break 82 | } 83 | 84 | kn, kv, err = decodeOption(option[:len(option)-1]) 85 | 86 | if err != nil { 87 | return info, err 88 | } 89 | 90 | info.Options[kn] = kv 91 | 92 | if err == io.EOF { 93 | break 94 | } 95 | } 96 | 97 | if val, ok := info.Options["idxoffsetbits"]; ok { 98 | if val == "64" { 99 | info.Is64 = true 100 | } 101 | } else { 102 | info.Is64 = false 103 | } 104 | 105 | return 106 | } 107 | -------------------------------------------------------------------------------- /internal/libs/go-stardict/stardict/stardict_test.go: -------------------------------------------------------------------------------- 1 | package stardict 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestReadDict(t *testing.T) { 8 | // init dictionary with path to dictionary files and name of dictionary 9 | dict, err := NewStarDict(&Option{ 10 | DictDzFilePath: "testdata/stardict/eedic.pdb/eedic.pdb.dict.dz", 11 | DictFilePath: "", 12 | IdxFilePath: "testdata/stardict/eedic.pdb/eedic.pdb.idx", 13 | IfoFilePath: "testdata/stardict/eedic.pdb/eedic.pdb.ifo", 14 | }) 15 | if err != nil { 16 | t.Fatal(err) 17 | } 18 | 19 | err = dict.BuildIndex() 20 | if err != nil { 21 | t.Fatal(err) 22 | } 23 | 24 | for _, k := range dict.KeyList() { 25 | t.Logf("key: %s", k) 26 | } 27 | 28 | def := dict.Lookup("oxygen") // get translations 29 | t.Logf("def:\n %s", def) 30 | 31 | } 32 | -------------------------------------------------------------------------------- /internal/libs/go-stardict/stardict/testdata/stardict/eedic.pdb/eedic.pdb.dict.dz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terasum/medict/138f5198ef0034909f9872ce580bb4fddf31fca9/internal/libs/go-stardict/stardict/testdata/stardict/eedic.pdb/eedic.pdb.dict.dz -------------------------------------------------------------------------------- /internal/libs/go-stardict/stardict/testdata/stardict/eedic.pdb/eedic.pdb.idx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terasum/medict/138f5198ef0034909f9872ce580bb4fddf31fca9/internal/libs/go-stardict/stardict/testdata/stardict/eedic.pdb/eedic.pdb.idx -------------------------------------------------------------------------------- /internal/libs/go-stardict/stardict/testdata/stardict/eedic.pdb/eedic.pdb.ifo: -------------------------------------------------------------------------------- 1 | StarDict's dict ifo file 2 | version=2.4.2 3 | wordcount=22776 4 | idxfilesize=372359 5 | bookname=eedic 6 | sametypesequence=m 7 | -------------------------------------------------------------------------------- /internal/libs/go-stardict/stardict/testdata/stardict/elements-2.4.2/elements.dict.dz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terasum/medict/138f5198ef0034909f9872ce580bb4fddf31fca9/internal/libs/go-stardict/stardict/testdata/stardict/elements-2.4.2/elements.dict.dz -------------------------------------------------------------------------------- /internal/libs/go-stardict/stardict/testdata/stardict/elements-2.4.2/elements.idx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terasum/medict/138f5198ef0034909f9872ce580bb4fddf31fca9/internal/libs/go-stardict/stardict/testdata/stardict/elements-2.4.2/elements.idx -------------------------------------------------------------------------------- /internal/libs/go-stardict/stardict/testdata/stardict/elements-2.4.2/elements.ifo: -------------------------------------------------------------------------------- 1 | StarDict's dict ifo file 2 | version=2.4.2 3 | wordcount=127 4 | idxfilesize=2147 5 | bookname=dictd_www.dict.org_elements 6 | date=2003.05.13 7 | sametypesequence=m 8 | -------------------------------------------------------------------------------- /internal/static/consts.go: -------------------------------------------------------------------------------- 1 | package static 2 | 3 | const ( 4 | ContentTypeBinary = "application/octet-stream" 5 | ContentTypeForm = "application/x-www-form-urlencoded" 6 | ContentTypeJSON = "application/json" 7 | ContentTypeHTML = "text/html; charset=utf-8" 8 | ContentTypeText = "text/plain; charset=utf-8" 9 | ) 10 | 11 | const ContentRootUrl = "/__mdict" 12 | 13 | const WordQueryMagicPath = "/__tcidem_query" 14 | -------------------------------------------------------------------------------- /internal/static/handler/content_pipeline_test.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2023 Quan Chen 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | package handler 18 | 19 | import "testing" 20 | 21 | func TestConvertDictHtml(t *testing.T) { 22 | //handleContent("1", `123`) 23 | } 24 | -------------------------------------------------------------------------------- /internal/static/handler/handler.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2023 Quan Chen 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | package handler 18 | 19 | type Handler interface { 20 | Replace(dictId string, entry string, resource []byte) (string, []byte) 21 | Match(dictId string, key string) bool 22 | } 23 | -------------------------------------------------------------------------------- /internal/static/handler/handler_font.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2023 Quan Chen 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | package handler 18 | 19 | import ( 20 | "regexp" 21 | "strings" 22 | ) 23 | 24 | var _ Handler = &HandlerFont{} 25 | 26 | var FONT_REG *regexp.Regexp 27 | 28 | func init() { 29 | var err error 30 | FONT_REG, err = regexp.Compile(`url\([\"|\'](\S+\.(ttf|otf|woff|woff2))[\"|\']\)`) 31 | if err != nil { 32 | panic(err) 33 | } 34 | } 35 | 36 | type HandlerFont struct { 37 | } 38 | 39 | func (r *HandlerFont) Match(dictId string, key string) bool { 40 | log.Infof("handle font matching %s:%s", dictId, key) 41 | if key == "" || dictId == "" { 42 | return false 43 | } 44 | for _, suff := range []string{"css", "scss"} { 45 | if strings.HasSuffix(key, suff) { 46 | return true 47 | } 48 | } 49 | return false 50 | } 51 | 52 | func (r *HandlerFont) ReplaceRaw(dictId string, templ string, content string) string { 53 | return content 54 | } 55 | 56 | func (r *HandlerFont) Replace(dictId string, keyWord string, resource []byte) (string, []byte) { 57 | 58 | if resource == nil { 59 | return keyWord, resource 60 | } 61 | 62 | newHtml := string(resource) 63 | matchedGroup := FONT_REG.FindAllStringSubmatch(newHtml, -1) 64 | for _, matched := range matchedGroup { 65 | if len(matched) != 3 { 66 | continue 67 | } 68 | oldStr := matched[1] 69 | newStr := oldStr + "?dict_id=" + dictId + "&d=0" 70 | newHtml = strings.ReplaceAll(newHtml, oldStr, newStr) 71 | } 72 | 73 | return keyWord, []byte(newHtml) 74 | } 75 | -------------------------------------------------------------------------------- /internal/static/handler/handler_font_test.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2023 Quan Chen 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | package handler 18 | 19 | import ( 20 | "testing" 21 | ) 22 | 23 | func TestReplacerFont_Replace(t *testing.T) { 24 | // fonts := &HandlerFont{} 25 | // _, html := fonts.Replace("1723", nil, TestHTML) 26 | // t.Log(html) 27 | } 28 | -------------------------------------------------------------------------------- /internal/static/handler/replacer.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2023 Quan Chen 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | package handler 18 | 19 | import ( 20 | "github.com/op/go-logging" 21 | "github.com/terasum/medict/pkg/model" 22 | ) 23 | 24 | var log = logging.MustGetLogger("default") 25 | 26 | type Replacer interface { 27 | Replace(dictId string, entry *model.MdictKeyWordIndex, htmlContent string) (*model.MdictKeyWordIndex, string) 28 | } 29 | -------------------------------------------------------------------------------- /internal/static/handler/replacer_css.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2023 Quan Chen 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | package handler 18 | 19 | import ( 20 | "github.com/terasum/medict/pkg/model" 21 | "regexp" 22 | "strings" 23 | ) 24 | 25 | var _ Replacer = &ReplacerCss{} 26 | 27 | var CSS_REG *regexp.Regexp 28 | 29 | func init() { 30 | var err error 31 | CSS_REG, err = regexp.Compile(`href=\"(\S+\.css)\"`) 32 | if err != nil { 33 | panic(err) 34 | } 35 | } 36 | 37 | type ReplacerCss struct { 38 | mdict *model.DictionaryItem 39 | } 40 | 41 | func (r ReplacerCss) SetDictContext(item *model.DictionaryItem) { 42 | r.mdict = item 43 | } 44 | 45 | func (r *ReplacerCss) Replace(dictId string, entry *model.MdictKeyWordIndex, html string) (*model.MdictKeyWordIndex, string) { 46 | 47 | if html == "" || dictId == "" { 48 | return entry, html 49 | } 50 | 51 | newhtml := html 52 | matchedGroup := CSS_REG.FindAllStringSubmatch(html, -1) 53 | for _, matched := range matchedGroup { 54 | if len(matched) != 2 { 55 | continue 56 | } 57 | oldStr := matched[1] 58 | newStr := oldStr + "?dict_id=" + dictId + "&d=0" 59 | newhtml = strings.ReplaceAll(newhtml, oldStr, newStr) 60 | } 61 | 62 | return entry, newhtml 63 | } 64 | -------------------------------------------------------------------------------- /internal/static/handler/replacer_css_test.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2023 Quan Chen 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | package handler 18 | 19 | import "testing" 20 | 21 | func TestReplacerCss_Replace(t *testing.T) { 22 | css := &ReplacerCss{} 23 | css.Replace("1236", nil, TestHTML) 24 | } 25 | -------------------------------------------------------------------------------- /internal/static/handler/replacer_entry.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2023 Quan Chen 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | package handler 18 | 19 | import ( 20 | "fmt" 21 | "regexp" 22 | "strings" 23 | 24 | "github.com/terasum/medict/pkg/model" 25 | ) 26 | 27 | var _ Replacer = &ReplacerEntry{} 28 | 29 | var ENTRY_REG *regexp.Regexp 30 | 31 | func init() { 32 | var err error 33 | ENTRY_REG, err = regexp.Compile(`href=\"entry://([\w#_ -]+)\"`) 34 | if err != nil { 35 | panic(err) 36 | } 37 | } 38 | 39 | type ReplacerEntry struct { 40 | } 41 | 42 | func (r *ReplacerEntry) Replace(dictId string, entry *model.MdictKeyWordIndex, html string) (*model.MdictKeyWordIndex, string) { 43 | 44 | if html == "" || dictId == "" { 45 | return entry, html 46 | } 47 | 48 | newhtml := html 49 | matchedGroup := ENTRY_REG.FindAllStringSubmatch(html, -1) 50 | for _, matched := range matchedGroup { 51 | if len(matched) != 2 { 52 | continue 53 | } 54 | oldStr := matched[0] 55 | oldWord := strings.TrimRight(matched[0], "\"") 56 | oldWord = strings.TrimPrefix(oldWord, "href=\"entry://") 57 | 58 | newStr := fmt.Sprintf("href=\"javascript:__medict_entry_jump('%s', '%s');\"", oldWord, dictId) 59 | fmt.Printf("old %s => new %s\n", oldStr, newStr) 60 | 61 | newhtml = strings.ReplaceAll(newhtml, oldStr, newStr) 62 | } 63 | 64 | return entry, newhtml 65 | } 66 | -------------------------------------------------------------------------------- /internal/static/handler/replacer_entry_test.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2023 Quan Chen 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | package handler 18 | 19 | import ( 20 | "testing" 21 | ) 22 | 23 | func TestReplacerEntry_Replace(t *testing.T) { 24 | entry := &ReplacerEntry{} 25 | _, html := entry.Replace("X182310003", nil, TESTENTRYHTML) 26 | t.Logf(html) 27 | } 28 | -------------------------------------------------------------------------------- /internal/static/handler/replacer_image.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2023 Quan Chen 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | package handler 18 | 19 | import ( 20 | "github.com/terasum/medict/pkg/model" 21 | "regexp" 22 | "strings" 23 | ) 24 | 25 | var _ Replacer = &ReplacerImage{} 26 | 27 | var imageReg *regexp.Regexp 28 | 29 | func init() { 30 | var err error 31 | imageReg, err = regexp.Compile(`src=["|'](\S+\.(png|jpg|gif|jpeg|svg))["|']`) 32 | if err != nil { 33 | panic(err) 34 | } 35 | } 36 | 37 | type ReplacerImage struct { 38 | } 39 | 40 | func (r *ReplacerImage) Replace(dictId string, entry *model.MdictKeyWordIndex, html string) (*model.MdictKeyWordIndex, string) { 41 | if html == "" || dictId == "" { 42 | return entry, html 43 | } 44 | cache := make(map[string]bool) 45 | 46 | newHtml := html 47 | matchedGroup := imageReg.FindAllStringSubmatch(html, -1) 48 | for _, matched := range matchedGroup { 49 | if len(matched) != 3 { 50 | continue 51 | } 52 | imgstr := matched[1] 53 | if _, ok := cache[imgstr]; ok { 54 | continue 55 | } else { 56 | cache[imgstr] = true 57 | newStr := imgstr + "?dict_id=" + dictId + "&d=0" 58 | newHtml = strings.ReplaceAll(newHtml, imgstr, newStr) 59 | } 60 | } 61 | 62 | return entry, newHtml 63 | } 64 | -------------------------------------------------------------------------------- /internal/static/handler/replacer_image_test.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2023 Quan Chen 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | package handler 18 | 19 | import ( 20 | "testing" 21 | ) 22 | 23 | func TestReplacerImage_Replace(t *testing.T) { 24 | image := &ReplacerImage{} 25 | _, html := image.Replace("1723", nil, TestHTML) 26 | t.Logf(html) 27 | } 28 | -------------------------------------------------------------------------------- /internal/static/handler/replacer_ini.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2023 Quan Chen 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | package handler 18 | -------------------------------------------------------------------------------- /internal/static/handler/replacer_javascript.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2023 Quan Chen 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | package handler 18 | 19 | import ( 20 | "github.com/terasum/medict/pkg/model" 21 | "regexp" 22 | "strings" 23 | ) 24 | 25 | var _ Replacer = &ReplacerJs{} 26 | 27 | var JS_REG *regexp.Regexp 28 | 29 | func init() { 30 | var err error 31 | JS_REG, err = regexp.Compile(`src=\"(\S+\.js)\"`) 32 | if err != nil { 33 | panic(err) 34 | } 35 | } 36 | 37 | type ReplacerJs struct { 38 | mdict *model.DictionaryItem 39 | } 40 | 41 | func (r *ReplacerJs) SetDictContext(item *model.DictionaryItem) { 42 | r.mdict = item 43 | } 44 | 45 | func (r *ReplacerJs) Replace(dictId string, entry *model.MdictKeyWordIndex, html string) (*model.MdictKeyWordIndex, string) { 46 | if html == "" || dictId == "" { 47 | return entry, html 48 | } 49 | 50 | newhtml := html 51 | matchedGroup := JS_REG.FindAllStringSubmatch(html, -1) 52 | for _, matched := range matchedGroup { 53 | if len(matched) != 2 { 54 | continue 55 | } 56 | oldStr := matched[1] 57 | newStr := oldStr + "?dict_id=" + dictId + "&d=0" 58 | newhtml = strings.ReplaceAll(newhtml, oldStr, newStr) 59 | } 60 | 61 | return entry, newhtml 62 | } 63 | -------------------------------------------------------------------------------- /internal/static/handler/replacer_javascript_test.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2023 Quan Chen 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | package handler 18 | 19 | import ( 20 | "testing" 21 | ) 22 | 23 | func TestReplacerJs_Replace(t *testing.T) { 24 | js := &ReplacerJs{} 25 | _, html := js.Replace("1283", nil, TestHTML) 26 | t.Logf(html) 27 | } 28 | -------------------------------------------------------------------------------- /internal/static/handler/replacer_link.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2023 Quan Chen 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | package handler 18 | -------------------------------------------------------------------------------- /internal/static/handler/replacer_sound.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2023 Quan Chen 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | package handler 18 | 19 | import ( 20 | "fmt" 21 | "github.com/terasum/medict/pkg/model" 22 | "regexp" 23 | "strings" 24 | ) 25 | 26 | var _ Replacer = &ReplacerSound{} 27 | 28 | var SOUND_REG *regexp.Regexp 29 | 30 | func init() { 31 | var err error 32 | // pɑːnd 33 | SOUND_REG, err = regexp.Compile(`href=[\"|'](sound://\S+\.mp3)[\"|']`) 34 | if err != nil { 35 | panic(err) 36 | } 37 | } 38 | 39 | type ReplacerSound struct { 40 | } 41 | 42 | func (r *ReplacerSound) Replace(dictId string, entry *model.MdictKeyWordIndex, html string) (*model.MdictKeyWordIndex, string) { 43 | 44 | if html == "" || dictId == "" { 45 | return entry, html 46 | } 47 | 48 | newhtml := html 49 | matchedGroup := SOUND_REG.FindAllStringSubmatch(html, -1) 50 | for _, matched := range matchedGroup { 51 | if len(matched) != 2 { 52 | continue 53 | } 54 | oldStr := matched[1] 55 | // sound://us/pond__us_1.mp3?dict_id=1236&d=0 56 | oldStr = strings.TrimPrefix(oldStr, "sound://") 57 | soundURL := fmt.Sprintf(`%s?dict_id=%s&d=0`, oldStr, dictId) 58 | newStr := fmt.Sprintf("javascript:__medict_play_sound('%s')", soundURL) 59 | newhtml = strings.ReplaceAll(newhtml, "sound://"+oldStr, newStr) 60 | } 61 | 62 | return entry, newhtml 63 | } 64 | -------------------------------------------------------------------------------- /internal/static/handler/replacer_sound_test.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2023 Quan Chen 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | package handler 18 | 19 | import "testing" 20 | 21 | func TestReplacerSound_Replace(t *testing.T) { 22 | sound := &ReplacerSound{} 23 | _, html := sound.Replace("1236", nil, TestHTML) 24 | t.Logf(html) 25 | 26 | } 27 | -------------------------------------------------------------------------------- /internal/static/tmpl/dict_desc_templ.go: -------------------------------------------------------------------------------- 1 | package tmpl 2 | 3 | const DictDescTempl = ` 4 | 5 | 6 |
7 | 8 |
%s
9 |
%s
10 |
11 | 12 | 13 | ` 14 | -------------------------------------------------------------------------------- /internal/utils/encoding_util.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "fmt" 5 | "strconv" 6 | "unicode" 7 | ) 8 | 9 | func StrToUnicode(str string) string { 10 | DD := []rune(str) //需要分割的字符串内容,将它转为字符,然后取长度。 11 | finallStr := "" 12 | for i := 0; i < len(DD); i++ { 13 | if unicode.Is(unicode.Scripts["Han"], DD[i]) { 14 | textQuoted := strconv.QuoteToASCII(string(DD[i])) 15 | finallStr += textQuoted[1 : len(textQuoted)-1] 16 | } else { 17 | h := fmt.Sprintf("%x", DD[i]) 18 | finallStr += "\\u" + isFullFour(h) 19 | } 20 | } 21 | return finallStr 22 | } 23 | 24 | func isFullFour(str string) string { 25 | if len(str) == 1 { 26 | str = "000" + str 27 | } else if len(str) == 2 { 28 | str = "00" + str 29 | } else if len(str) == 3 { 30 | str = "0" + str 31 | } 32 | return str 33 | } 34 | -------------------------------------------------------------------------------- /internal/utils/encoding_util_test.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestStrToUnicode(t *testing.T) { 8 | uncodeStr := StrToUnicode("十大户¥@!#%……&……*()——+《》、,。、;‘、配【】") 9 | t.Logf(uncodeStr) 10 | uncodeStr = StrToUnicode("國語詞典") 11 | t.Logf(uncodeStr) 12 | } 13 | -------------------------------------------------------------------------------- /internal/utils/hashutil.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2023 Quan Chen 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | package utils 18 | 19 | import ( 20 | "crypto/md5" 21 | "encoding/hex" 22 | ) 23 | 24 | func MD5Hash(text string) string { 25 | hash := md5.Sum([]byte(text)) 26 | return hex.EncodeToString(hash[:]) 27 | } 28 | -------------------------------------------------------------------------------- /internal/utils/pathhome_darwin.go: -------------------------------------------------------------------------------- 1 | //go:build darwin 2 | 3 | package utils 4 | 5 | import ( 6 | "fmt" 7 | "os" 8 | "path/filepath" 9 | "strings" 10 | 11 | "github.com/kirsle/configdir" 12 | ) 13 | 14 | func ReplaceHome(origin string) (string, error) { 15 | configPath, err := HomeDir() 16 | if err != nil { 17 | return "", err 18 | } 19 | 20 | origin = strings.ReplaceAll(origin, "$HOME", configPath) 21 | return origin, nil 22 | } 23 | 24 | func HomeDir() (string, error) { 25 | home, err := os.UserHomeDir() 26 | if err != nil { 27 | return "", fmt.Errorf("userhomedir err: %s", err.Error()) 28 | } 29 | configPath := filepath.Join(home, ".medict") 30 | 31 | err = configdir.MakePath(configPath) 32 | if err != nil { 33 | return "", fmt.Errorf("base home dir mkall failed, %s", err.Error()) 34 | } 35 | 36 | return configPath, nil 37 | } 38 | 39 | func AppConfigDir() (string, error) { 40 | // $APPDIR/medict/medict.db 41 | confp := configdir.LocalConfig("medict") 42 | if !(FileExists(confp)) { 43 | err := configdir.MakePath(confp) 44 | if err != nil { 45 | return "", fmt.Errorf("app config dir mkall failed, %s", err.Error()) 46 | } 47 | } 48 | // fmt.Printf("[medict-init]: AppConfigDir %s\n", confp) 49 | return confp, nil 50 | } 51 | -------------------------------------------------------------------------------- /internal/utils/pathhome_linux.go: -------------------------------------------------------------------------------- 1 | //go:build linux 2 | 3 | package utils 4 | 5 | import ( 6 | "os" 7 | "strings" 8 | 9 | "github.com/kirsle/configdir" 10 | ) 11 | 12 | func ReplaceHome(origin string) (string, error) { 13 | home, err := os.UserHomeDir() 14 | if err != nil { 15 | return origin, err 16 | } 17 | 18 | origin = strings.ReplaceAll(origin, "$HOME", home) 19 | return origin, nil 20 | } 21 | 22 | func HomeDir() (string, error) { 23 | configPath := configdir.LocalConfig("medict") 24 | err := configdir.MakePath(configPath) // Ensure it exists. 25 | if err != nil { 26 | return "", err 27 | } 28 | return configPath, nil 29 | } 30 | 31 | func AppConfigDir() (string, error) { 32 | return HomeDir() 33 | } 34 | -------------------------------------------------------------------------------- /internal/utils/pathhome_windows.go: -------------------------------------------------------------------------------- 1 | //go:build windows 2 | // +build windows 3 | 4 | package utils 5 | 6 | import ( 7 | "os" 8 | "strings" 9 | 10 | "github.com/kirsle/configdir" 11 | ) 12 | 13 | func ReplaceHome(origin string) (string, error) { 14 | home, err := os.UserHomeDir() 15 | if err != nil { 16 | return origin, err 17 | } 18 | 19 | origin = strings.ReplaceAll(origin, "$HOME", home) 20 | return origin, nil 21 | } 22 | 23 | func HomeDir() (string, error) { 24 | configPath := configdir.LocalConfig("medict") 25 | err := configdir.MakePath(configPath) // Ensure it exists. 26 | if err != nil { 27 | return "", err 28 | } 29 | return configPath, nil 30 | } 31 | 32 | func AppConfigDir() (string, error) { 33 | return HomeDir() 34 | } 35 | -------------------------------------------------------------------------------- /internal/utils/pathutil.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2023 Quan Chen 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | package utils 18 | 19 | import ( 20 | "os" 21 | "path/filepath" 22 | "strings" 23 | ) 24 | 25 | func FileBaseDir(fpath string) string { 26 | return filepath.Dir(fpath) 27 | } 28 | 29 | func FileAbs(fpath string) string { 30 | fp, err := filepath.Abs(fpath) 31 | if err != nil { 32 | return fpath 33 | } 34 | return fp 35 | } 36 | 37 | func FileName(fpath string) string { 38 | _, file := filepath.Split(fpath) 39 | return file 40 | } 41 | 42 | func FileNameWithoutExt(fpath string) string { 43 | rawpath := FileName(fpath) 44 | rawpaths := strings.Split(rawpath, ".") 45 | return rawpaths[0] 46 | } 47 | 48 | func FileExists(fpath string) bool { 49 | if _, err := os.Stat(fpath); err == nil { 50 | return true 51 | } 52 | return false 53 | 54 | } 55 | 56 | func FileRemove(fpath string) error { 57 | if FileExists(fpath) && fpath != "/" { 58 | return os.RemoveAll(fpath) 59 | } 60 | return nil 61 | } 62 | -------------------------------------------------------------------------------- /pkg/apis/dicts_handler.go: -------------------------------------------------------------------------------- 1 | package apis 2 | 3 | import ( 4 | "errors" 5 | "github.com/terasum/medict/pkg/model" 6 | ) 7 | 8 | // GetAllDicts 9 | func (dc *DictsController) GetAllDicts(args map[string]interface{}) *model.Resp { 10 | dicts := dc.ds.Dicts() 11 | return model.BuildSuccess(dicts) 12 | } 13 | 14 | // InitDicts 初始化词典 15 | func (dc *DictsController) InitDicts(args map[string]interface{}) *model.Resp { 16 | err := dc.ds.InitDicts() 17 | if err != nil { 18 | return model.BuildError(err, model.InnerSysErrCode) 19 | } 20 | return model.BuildSuccess(nil) 21 | } 22 | 23 | // buildIndex 24 | func (dc *DictsController) BuildIndexByDictId(args map[string]interface{}) *model.Resp { 25 | if id, ok := args["dictid"]; !ok { 26 | return model.BuildError(errors.New("build index failed, dictid is empty"), model.InnerSysErrCode) 27 | } else { 28 | log.Infof("[wails] building dictionary index, dict id is %s", id) 29 | dict := dc.ds.GetDictById(id.(string)) 30 | if err := dict.MainDict.BuildIndex(); err != nil { 31 | log.Infof("[wails] building dictionary index, dictionary path is %s", dict.MainDict.Name()) 32 | log.Infof("[wails] building dictionary index failed, err %s", err.Error()) 33 | return model.BuildError(err, model.InnerSysErrCode) 34 | } else { 35 | log.Infof("[wails] building dictionary index success, id: %s", dict.MainDict.Name()) 36 | return model.BuildSuccess(dict.MainDict.Name()) 37 | } 38 | } 39 | } 40 | 41 | // SearchWord 42 | func (dc *DictsController) SearchWord(args map[string]interface{}) *model.Resp { 43 | dictId, ok := args["dict_id"] 44 | if !ok { 45 | return model.BuildError(errors.New("dict_id not found"), model.BadParamErrCode) 46 | } 47 | 48 | word, ok := args["word"] 49 | if !ok { 50 | return model.BuildError(errors.New("dict_id not found"), model.BadParamErrCode) 51 | } 52 | 53 | entries, err := dc.ds.Search(dictId.(string), word.(string)) 54 | if err != nil { 55 | return model.BuildError(err, model.InnerSysErrCode) 56 | } 57 | return model.BuildSuccess(entries) 58 | } 59 | -------------------------------------------------------------------------------- /pkg/apis/server_api.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2023 Quan Chen 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | package apis 18 | 19 | import ( 20 | "github.com/terasum/medict/internal/config" 21 | "net" 22 | ) 23 | 24 | type StaticServerAPI struct { 25 | APIServerAddr net.Addr 26 | } 27 | 28 | func NewStaticServerAPI(conf *config.Config) *StaticServerAPI { 29 | return &StaticServerAPI{} 30 | } 31 | 32 | func (serverApi *StaticServerAPI) StaticServerApiBaseURL() string { 33 | if serverApi.APIServerAddr == nil { 34 | return "" 35 | } 36 | return serverApi.APIServerAddr.String() 37 | } 38 | -------------------------------------------------------------------------------- /pkg/model/decoder.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2023 Quan Chen 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | package model 18 | 19 | import ( 20 | "bytes" 21 | "encoding/hex" 22 | "fmt" 23 | "unicode/utf16" 24 | "unicode/utf8" 25 | ) 26 | 27 | func DecodeHex(str string) ([]byte, error) { 28 | return hex.DecodeString(str) 29 | } 30 | 31 | func DecodeUTF16(b []byte) (string, error) { 32 | 33 | if len(b)%2 != 0 { 34 | return "", fmt.Errorf("must have even length byte slice") 35 | } 36 | 37 | u16s := make([]uint16, 1) 38 | 39 | ret := &bytes.Buffer{} 40 | 41 | b8buf := make([]byte, 4) 42 | 43 | lb := len(b) 44 | for i := 0; i < lb; i += 2 { 45 | u16s[0] = uint16(b[i]) + (uint16(b[i+1]) << 8) 46 | r := utf16.Decode(u16s) 47 | n := utf8.EncodeRune(b8buf, r[0]) 48 | ret.Write(b8buf[:n]) 49 | } 50 | 51 | return ret.String(), nil 52 | } 53 | -------------------------------------------------------------------------------- /pkg/model/dict_interface.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type DictType string 4 | type ImgType string 5 | 6 | const DictTypeMdict DictType = "Mdict" 7 | const DictTypeStarDict DictType = "StarDict" 8 | const ImgTypeJPG ImgType = "jpg" 9 | const ImgTypePNG ImgType = "png" 10 | 11 | type GeneralDictionary interface { 12 | // BuildIndex 构建索引 13 | BuildIndex() error 14 | // DictType 返回词典类型, 目前仅支持 mdict 和 stardict 15 | DictType() DictType 16 | // Description 返回词典描述 17 | Description() *PlainDictionaryInfo 18 | // Name 返回词典名称(主要是为了解决mdict的外部资源问题) 19 | Name() string 20 | // Lookup 直接输入 keyword 遍历词典搜索 21 | Lookup(keyword string) ([]byte, error) 22 | // LookupResource 搜索词典资源,包括 css/js/图片/字体等, 仅限制支持在词典所在文件夹 23 | LookupResource(keyword string) ([]byte, error) 24 | // Locate 使用索引定位词条,并返回 html 释义 25 | Locate(entry *KeyQueryIndex) ([]byte, error) 26 | // Search 返回近似词条索引列表,用于后续 Locate 27 | Search(keyword string) ([]*KeyQueryIndex, error) 28 | } 29 | -------------------------------------------------------------------------------- /pkg/model/response.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2023 Quan Chen 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | package model 18 | 19 | const ( 20 | SuccessErrCode = 200 21 | InnerSysErrCode = 500 22 | BadParamErrCode = 401 23 | BadReqCode = 400 24 | UnknownErrorCode = 999 25 | ) 26 | 27 | type Resp struct { 28 | Data interface{} `json:"data"` 29 | Err string `json:"err"` 30 | Code int `json:"code"` 31 | } 32 | 33 | func BuildSuccess(data interface{}) *Resp { 34 | return &Resp{ 35 | Data: data, 36 | Err: "success", 37 | Code: SuccessErrCode, 38 | } 39 | } 40 | 41 | func BuildRawError(err string, code int) *Resp { 42 | return &Resp{ 43 | Data: nil, 44 | Err: err, 45 | Code: code, 46 | } 47 | } 48 | 49 | func BuildError(err error, code int) *Resp { 50 | return &Resp{ 51 | Data: nil, 52 | Err: err.Error(), 53 | Code: code, 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /pkg/service/.gitignore: -------------------------------------------------------------------------------- 1 | /testdata -------------------------------------------------------------------------------- /pkg/service/dicts_service_test.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2023 Quan Chen 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | package service 18 | 19 | import ( 20 | "testing" 21 | 22 | "github.com/stretchr/testify/assert" 23 | "github.com/terasum/medict/internal/config" 24 | ) 25 | 26 | func TestDictService_Dicts(t *testing.T) { 27 | ds, err := NewDictService(&config.Config{ 28 | ConfigStruct: &config.ConfigStruct{ 29 | BaseDictDir: "./testdata/dicts", 30 | }, 31 | }) 32 | assert.Nil(t, err) 33 | dicts := ds.Dicts() 34 | assert.Equal(t, 1, len(dicts)) 35 | t.Logf("%#v", dicts[0]) 36 | 37 | } 38 | 39 | func TestDictService_Dicts2(t *testing.T) { 40 | ds, err := NewDictService(&config.Config{ 41 | ConfigStruct: &config.ConfigStruct{ 42 | BaseDictDir: "./testdata/dicts", 43 | }, 44 | }) 45 | assert.Nil(t, err) 46 | dicts := ds.Dicts() 47 | assert.Equal(t, 2, len(dicts)) 48 | t.Logf("%#v", dicts[0]) 49 | } 50 | -------------------------------------------------------------------------------- /pkg/service/log.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import "github.com/op/go-logging" 4 | 5 | var log = logging.MustGetLogger("default") 6 | -------------------------------------------------------------------------------- /pkg/service/mdict/leveldb-repo/log.go: -------------------------------------------------------------------------------- 1 | package leveldb_repo 2 | 3 | import ( 4 | "github.com/op/go-logging" 5 | ) 6 | 7 | var log = logging.MustGetLogger("default") 8 | -------------------------------------------------------------------------------- /pkg/service/mdict/log.go: -------------------------------------------------------------------------------- 1 | package mdict 2 | 3 | import "github.com/op/go-logging" 4 | 5 | var log = logging.MustGetLogger("default") 6 | -------------------------------------------------------------------------------- /pkg/service/mdict/mdict-idxer/indexer.go: -------------------------------------------------------------------------------- 1 | package mdict_idxer 2 | 3 | import "github.com/terasum/medict/pkg/model" 4 | 5 | type Indexer interface { 6 | Lookup(keyword string) (*model.MdictKeyWordIndex, error) 7 | SetMeta(key, value string) error 8 | GetMeta(key string) (value string, err error) 9 | AddRecord(record *model.MdictKeyWordIndex) error 10 | Search(keyword string) ([]*model.MdictKeyWordIndex, error) 11 | } 12 | -------------------------------------------------------------------------------- /pkg/service/mdict/mdict-idxer/leveldb_indexer_test.go: -------------------------------------------------------------------------------- 1 | package mdict_idxer 2 | 3 | import ( 4 | "github.com/terasum/medict/pkg/model" 5 | "testing" 6 | ) 7 | 8 | func TestLookup(t *testing.T) { 9 | 10 | idxer, err := NewIndexer("./testdata/testleveldb") 11 | if err != nil { 12 | t.Fatal(err) 13 | } 14 | err = idxer.AddRecord(&model.MdictKeyWordIndex{ 15 | ID: 0, 16 | KeyWord: "hell"}) 17 | if err != nil { 18 | t.Fatal(err) 19 | } 20 | err = idxer.AddRecord(&model.MdictKeyWordIndex{ 21 | ID: 0, 22 | KeyWord: "hello"}) 23 | if err != nil { 24 | t.Fatal(err) 25 | } 26 | err = idxer.AddRecord(&model.MdictKeyWordIndex{ 27 | ID: 0, 28 | KeyWord: "helium"}) 29 | if err != nil { 30 | t.Fatal(err) 31 | } 32 | 33 | list, err := idxer.Search("hell") 34 | if err != nil { 35 | t.Fatal(err) 36 | } 37 | for _, w := range list { 38 | t.Logf("search word: %s", w.KeyWord) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /pkg/service/mdict/mdict-idxer/log.go: -------------------------------------------------------------------------------- 1 | package mdict_idxer 2 | 3 | import ( 4 | "github.com/op/go-logging" 5 | "time" 6 | ) 7 | 8 | var log = logging.MustGetLogger("default") 9 | 10 | func logstart(method string, args interface{}) time.Time { 11 | log.Infof("%s|STR|: %v", method, args) 12 | return time.Now() 13 | } 14 | 15 | func logend(method string, startTime time.Time, err error) { 16 | log.Infof("%s|END|%s|E:%v", method, time.Now().Sub(startTime).String(), err) 17 | } 18 | -------------------------------------------------------------------------------- /pkg/service/mdict/mdict-idxer/sqlite_indexer_test.go: -------------------------------------------------------------------------------- 1 | package mdict_idxer 2 | 3 | import ( 4 | "github.com/terasum/medict/pkg/model" 5 | "testing" 6 | ) 7 | 8 | func TestIndexEngine_AddRecord(t *testing.T) { 9 | indexFilePath := "./testdata/testidx.meidx" 10 | 11 | engine, err := NewIdxer(indexFilePath) 12 | if err != nil { 13 | t.Fatal(err) 14 | } 15 | 16 | err = engine.SetMeta("id", "1234") 17 | if err != nil { 18 | t.Fatal(err) 19 | } 20 | 21 | value, err := engine.GetMeta("id") 22 | if err != nil { 23 | t.Fatal(err) 24 | } 25 | t.Logf("value id : %s", value) 26 | 27 | record := &model.MdictKeyWordIndex{ 28 | ID: 0, 29 | KeyWord: "$100, £50, etc. a throw", 30 | RecordLocateStartOffset: 0, 31 | RecordLocateEndOffset: 1077, 32 | IsUTF16: 0, 33 | IsRecordEncrypt: 0, 34 | RecordBlockDataStartOffset: 833968, 35 | RecordBlockDataCompressSize: 10119, 36 | RecordBlockDataDeCompressSize: 65004, 37 | KeyWordDataStartOffset: 0, 38 | KeyWordDataEndOffset: 1077, 39 | } 40 | 41 | if err = engine.AddRecord(record); err != nil { 42 | t.Errorf("AddRecord() error = %v", err) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /pkg/service/mdict/mdict-idxer/testdata/.gitignore: -------------------------------------------------------------------------------- 1 | testidx.meidx -------------------------------------------------------------------------------- /pkg/service/mdict/mdict-idxer/testdata/testleveldb/000026.ldb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terasum/medict/138f5198ef0034909f9872ce580bb4fddf31fca9/pkg/service/mdict/mdict-idxer/testdata/testleveldb/000026.ldb -------------------------------------------------------------------------------- /pkg/service/mdict/mdict-idxer/testdata/testleveldb/000027.ldb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terasum/medict/138f5198ef0034909f9872ce580bb4fddf31fca9/pkg/service/mdict/mdict-idxer/testdata/testleveldb/000027.ldb -------------------------------------------------------------------------------- /pkg/service/mdict/mdict-idxer/testdata/testleveldb/000030.ldb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terasum/medict/138f5198ef0034909f9872ce580bb4fddf31fca9/pkg/service/mdict/mdict-idxer/testdata/testleveldb/000030.ldb -------------------------------------------------------------------------------- /pkg/service/mdict/mdict-idxer/testdata/testleveldb/CURRENT: -------------------------------------------------------------------------------- 1 | MANIFEST-000032 2 | -------------------------------------------------------------------------------- /pkg/service/mdict/mdict-idxer/testdata/testleveldb/CURRENT.bak: -------------------------------------------------------------------------------- 1 | MANIFEST-000029 2 | -------------------------------------------------------------------------------- /pkg/service/mdict/mdict-idxer/testdata/testleveldb/LOCK: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terasum/medict/138f5198ef0034909f9872ce580bb4fddf31fca9/pkg/service/mdict/mdict-idxer/testdata/testleveldb/LOCK -------------------------------------------------------------------------------- /pkg/service/mdict/mdict-idxer/testdata/testleveldb/MANIFEST-000032: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terasum/medict/138f5198ef0034909f9872ce580bb4fddf31fca9/pkg/service/mdict/mdict-idxer/testdata/testleveldb/MANIFEST-000032 -------------------------------------------------------------------------------- /pkg/service/mdict/mdict_holder_test.go: -------------------------------------------------------------------------------- 1 | package mdict 2 | 3 | import ( 4 | "github.com/terasum/medict/pkg/model" 5 | "testing" 6 | ) 7 | 8 | func TestMdictHolder_BuildIndex(t *testing.T) { 9 | holder, err := newMdictHolder("./testdata/mdx/testdict.mdx") 10 | if err != nil { 11 | t.Fatal(err) 12 | } 13 | 14 | err = holder.BuildIndex() 15 | if err != nil { 16 | t.Fatal(err) 17 | } 18 | 19 | data, err := holder.Locate(&model.KeyQueryIndex{ 20 | IndexType: "mdx", 21 | MdictKeyWordIndex: &model.MdictKeyWordIndex{ 22 | ID: 0, 23 | KeyWord: "accessorized", 24 | RecordLocateStartOffset: 735416, 25 | RecordLocateEndOffset: 735438, 26 | IsUTF16: 0, 27 | IsRecordEncrypt: 0, 28 | IsMDD: 0, 29 | RecordBlockDataStartOffset: 920434, 30 | RecordBlockDataCompressSize: 8573, 31 | RecordBlockDataDeCompressSize: 64463, 32 | KeyWordDataStartOffset: 35367, 33 | KeyWordDataEndOffset: 35389, 34 | }, 35 | }) 36 | if err != nil { 37 | t.Fatal(err) 38 | } 39 | 40 | t.Logf("data: %s", data) 41 | } 42 | -------------------------------------------------------------------------------- /pkg/service/mdict/mdict_svc_test.go: -------------------------------------------------------------------------------- 1 | package mdict 2 | 3 | import ( 4 | "encoding/json" 5 | "github.com/stretchr/testify/assert" 6 | "github.com/terasum/medict/pkg/model" 7 | "testing" 8 | ) 9 | 10 | func TestMdict_Name(t *testing.T) { 11 | mdict := &mdictSvcImpl{} 12 | t.Logf("name is %s", mdict.Name()) 13 | assert.Equal(t, "test", mdict.Name()) 14 | } 15 | 16 | func TestCreateSqliteIndex(t *testing.T) { 17 | 18 | mdict, err := NewMdictSvc(&model.DirItem{ 19 | BaseDir: "testdata", 20 | CurrentDir: "testdata/mdict", 21 | IsValid: true, 22 | DictType: model.DictTypeMdict, 23 | CoverImgPath: "", 24 | CoverImgType: "", 25 | ConfigPath: "", 26 | LicensePath: "", 27 | MdictMdxFileName: "testdict", 28 | MdictMdxAbsPath: "testdata/mdict/testdict.mdx", 29 | MdictMddAbsPath: []string{"testdata/mdict/testdict.mdd"}, 30 | StarDictDzAbsPath: "", 31 | StarDictAbsPath: "", 32 | StarDictIdxAbsPath: "", 33 | StarDictIfoAbsPath: "", 34 | }) 35 | 36 | if err != nil { 37 | t.Fatal(err) 38 | } 39 | t.Logf(mdict.Name()) 40 | err = mdict.BuildIndex() 41 | if err != nil { 42 | t.Fatal(err) 43 | } 44 | 45 | records, err := mdict.Search("hello") 46 | if err != nil { 47 | t.Fatal(err) 48 | } 49 | for _, record := range records { 50 | data, _ := json.Marshal(record) 51 | t.Logf("%s", data) 52 | def, err := mdict.Locate(record) 53 | t.Logf("def: %s, err: %v", def, err) 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /pkg/service/stardict/stardict_test.go: -------------------------------------------------------------------------------- 1 | package stardict 2 | 3 | import ( 4 | "encoding/json" 5 | "github.com/terasum/medict/pkg/model" 6 | "github.com/terasum/medict/pkg/service" 7 | "testing" 8 | ) 9 | 10 | func TestStarDict_Lookup(t *testing.T) { 11 | dict, err := service.NewByDirItem(&model.DirItem{ 12 | BaseDir: "", 13 | CurrentDir: "", 14 | IsValid: false, 15 | DictType: model.DictTypeStarDict, 16 | CoverImgPath: "", 17 | CoverImgType: "", 18 | ConfigPath: "", 19 | LicensePath: "", 20 | MdictMdxFileName: "", 21 | MdictMdxAbsPath: "", 22 | MdictMddAbsPath: nil, 23 | StarDictDzAbsPath: "testdata/stardict/eedic.pdb.dict.dz", 24 | StarDictAbsPath: "testdata/stardict/eedic.pdb.dict", 25 | StarDictIdxAbsPath: "testdata/stardict/eedic.pdb.idx", 26 | StarDictIfoAbsPath: "testdata/stardict/eedic.pdb.ifo", 27 | }) 28 | 29 | if err != nil { 30 | t.Fatal(err) 31 | } 32 | err = dict.MainDict.BuildIndex() 33 | if err != nil { 34 | t.Fatal(err) 35 | } 36 | t.Logf("%+v", dict.ToPlain()) 37 | t.Logf("%+v", dict.Name) 38 | words, err := dict.MainDict.Search("impair") 39 | if err != nil { 40 | t.Fatal(err) 41 | } 42 | data, err := json.MarshalIndent(words, "", " ") 43 | t.Logf("words: %s", data) 44 | } 45 | -------------------------------------------------------------------------------- /pkg/service/support/filewalker_test.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2023 Quan Chen 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | package support 18 | 19 | import ( 20 | "encoding/json" 21 | "github.com/stretchr/testify/assert" 22 | "github.com/terasum/medict/pkg/model" 23 | "path/filepath" 24 | "testing" 25 | ) 26 | 27 | func TestWalkDir(t *testing.T) { 28 | result, err := WalkDir("./testdata/dicts") 29 | t.Logf("result: %+v", result) 30 | assert.Nil(t, err) 31 | assert.Equal(t, 3, len(result)) 32 | 33 | expectPath, _ := filepath.Abs("testdata/dicts/ccedit/ccedit.idx") 34 | assert.Equal(t, expectPath, result[0].StarDictIdxAbsPath) 35 | assert.Equal(t, model.DictTypeStarDict, result[0].DictType) 36 | 37 | expectPath2, _ := filepath.Abs("testdata/dicts/mdict-type/test.mdx") 38 | assert.Equal(t, expectPath2, result[1].MdictMdxAbsPath) 39 | assert.Equal(t, model.ImgTypeJPG, result[1].CoverImgType) 40 | license, _ := filepath.Abs("testdata/dicts/mdict-type/dict.license") 41 | assert.Equal(t, license, result[1].LicensePath) 42 | 43 | expectPath3, _ := filepath.Abs("testdata/dicts/oale3/test.mdx") 44 | assert.Equal(t, expectPath3, result[2].MdictMdxAbsPath) 45 | assert.Equal(t, model.ImgTypePNG, result[2].CoverImgType) 46 | license2, _ := filepath.Abs("testdata/dicts/oale3/dict.license") 47 | assert.Equal(t, license2, result[2].LicensePath) 48 | 49 | data, err := json.MarshalIndent(result, "", " ") 50 | if err != nil { 51 | t.Fatal(err) 52 | } 53 | t.Logf(string(data)) 54 | } 55 | -------------------------------------------------------------------------------- /pkg/service/support/testdata/dicts/ccedit/ccedit.dz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terasum/medict/138f5198ef0034909f9872ce580bb4fddf31fca9/pkg/service/support/testdata/dicts/ccedit/ccedit.dz -------------------------------------------------------------------------------- /pkg/service/support/testdata/dicts/ccedit/ccedit.idx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terasum/medict/138f5198ef0034909f9872ce580bb4fddf31fca9/pkg/service/support/testdata/dicts/ccedit/ccedit.idx -------------------------------------------------------------------------------- /pkg/service/support/testdata/dicts/ccedit/ccedit.ifo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terasum/medict/138f5198ef0034909f9872ce580bb4fddf31fca9/pkg/service/support/testdata/dicts/ccedit/ccedit.ifo -------------------------------------------------------------------------------- /pkg/service/support/testdata/dicts/mdict-type/dict.license: -------------------------------------------------------------------------------- 1 | xxxx license -------------------------------------------------------------------------------- /pkg/service/support/testdata/dicts/mdict-type/mdict.toml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terasum/medict/138f5198ef0034909f9872ce580bb4fddf31fca9/pkg/service/support/testdata/dicts/mdict-type/mdict.toml -------------------------------------------------------------------------------- /pkg/service/support/testdata/dicts/mdict-type/test.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terasum/medict/138f5198ef0034909f9872ce580bb4fddf31fca9/pkg/service/support/testdata/dicts/mdict-type/test.jpg -------------------------------------------------------------------------------- /pkg/service/support/testdata/dicts/mdict-type/test.mdd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terasum/medict/138f5198ef0034909f9872ce580bb4fddf31fca9/pkg/service/support/testdata/dicts/mdict-type/test.mdd -------------------------------------------------------------------------------- /pkg/service/support/testdata/dicts/mdict-type/test.mdx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terasum/medict/138f5198ef0034909f9872ce580bb4fddf31fca9/pkg/service/support/testdata/dicts/mdict-type/test.mdx -------------------------------------------------------------------------------- /pkg/service/support/testdata/dicts/oale3/assets/test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terasum/medict/138f5198ef0034909f9872ce580bb4fddf31fca9/pkg/service/support/testdata/dicts/oale3/assets/test.png -------------------------------------------------------------------------------- /pkg/service/support/testdata/dicts/oale3/dict.license: -------------------------------------------------------------------------------- 1 | xxxx license -------------------------------------------------------------------------------- /pkg/service/support/testdata/dicts/oale3/fonts/test.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terasum/medict/138f5198ef0034909f9872ce580bb4fddf31fca9/pkg/service/support/testdata/dicts/oale3/fonts/test.ttf -------------------------------------------------------------------------------- /pkg/service/support/testdata/dicts/oale3/test.mdd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terasum/medict/138f5198ef0034909f9872ce580bb4fddf31fca9/pkg/service/support/testdata/dicts/oale3/test.mdd -------------------------------------------------------------------------------- /pkg/service/support/testdata/dicts/oale3/test.mdx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terasum/medict/138f5198ef0034909f9872ce580bb4fddf31fca9/pkg/service/support/testdata/dicts/oale3/test.mdx -------------------------------------------------------------------------------- /pkg/service/support/testdata/dicts/oale3/test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terasum/medict/138f5198ef0034909f9872ce580bb4fddf31fca9/pkg/service/support/testdata/dicts/oale3/test.png -------------------------------------------------------------------------------- /pkg/service/support/testdata/dicts/startdict-type/stardict.toml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terasum/medict/138f5198ef0034909f9872ce580bb4fddf31fca9/pkg/service/support/testdata/dicts/startdict-type/stardict.toml -------------------------------------------------------------------------------- /pkg/service/testdata/stardict/cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terasum/medict/138f5198ef0034909f9872ce580bb4fddf31fca9/pkg/service/testdata/stardict/cover.png -------------------------------------------------------------------------------- /pkg/service/testdata/stardict/eedic.pdb.dict.dz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terasum/medict/138f5198ef0034909f9872ce580bb4fddf31fca9/pkg/service/testdata/stardict/eedic.pdb.dict.dz -------------------------------------------------------------------------------- /pkg/service/testdata/stardict/eedic.pdb.idx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terasum/medict/138f5198ef0034909f9872ce580bb4fddf31fca9/pkg/service/testdata/stardict/eedic.pdb.idx -------------------------------------------------------------------------------- /pkg/service/testdata/stardict/eedic.pdb.ifo: -------------------------------------------------------------------------------- 1 | StarDict's dict ifo file 2 | version=2.4.2 3 | wordcount=22776 4 | idxfilesize=372359 5 | bookname=eedic 6 | sametypesequence=m 7 | -------------------------------------------------------------------------------- /wails.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Medict", 3 | "outputfilename": "Medict", 4 | "frontend:install": "pnpm install", 5 | "frontend:build": "pnpm run build", 6 | "frontend:dev:watcher": "pnpm run dev", 7 | "frontend:dev:serverUrl": "auto", 8 | "author": { 9 | "name": "Quan Chen", 10 | "email": "chenquan_act@163.com" 11 | } 12 | } 13 | --------------------------------------------------------------------------------