-
Notifications
You must be signed in to change notification settings - Fork 131
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
beba93f
commit ae938f7
Showing
4,115 changed files
with
10,906 additions
and
13,857,130 deletions.
The diff you're trying to view is too large. We only load the first 3000 changed files.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,7 @@ | ||
node_modules | ||
database/*.db | ||
database/*.db | ||
.output/ | ||
.vercel/ | ||
.vinxi/ | ||
libraries/ | ||
exported/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,86 +1,51 @@ | ||
# maimemo-export | ||
|
||
> 中文含义并非导出自墨墨背单词,而是使用 [ECDICT](https://github.com/skywind3000/ECDICT-ultimate) 的数据,无法做到与墨墨背单词一致。 | ||
用于导出墨墨背单词的词库,并生成适用于 List 背单词,不背单词,欧陆词典等的自定义词库 | ||
|
||
## Usage | ||
|
||
> 必须使用 Android 手机,并且必须 Root,小白勿试。release 中有已经导出好的词库,可以直接下载使用。 | ||
#### Install | ||
|
||
> 需要安装 [bun](https://bun.sh/) | ||
```shell | ||
git clone https://github.com/ourongxing/maimemo-export.git | ||
cd maimemo-export | ||
pnpm i | ||
``` | ||
|
||
#### Get Database | ||
|
||
1. 下载词典数据库,[点击下载](ecdict-ultimate-sqlite.zip),解压得到 `ultimate.db`,放入 `database` 文件夹中(没有就自己新建)。 | ||
2. 获取手机上的数据库文件,连接好手机,打开 USB 调试,命令行输入 | ||
```shell | ||
pnpm adb | ||
``` | ||
#### Option | ||
```ts | ||
// src/index.ts | ||
const exportThesaurus = async ( | ||
// 词库名 | ||
books: string[], | ||
// MaimemoDB 为本地词库,NotePad 为云词库 | ||
db: MaimemoDB | NotePad, | ||
option?: ExportOpt | ||
) => { | ||
``` | ||
```shell | ||
pnpm adb | ||
``` | ||
|
||
```ts | ||
type ExportOpt = { | ||
// 导出文件类型 | ||
types?: ("txt" | "csv" | "list")[] // default: ["txt","csv","list"] | ||
// 导出路径 | ||
dir?: string // ./thesaurus | ||
// 1.词库中仅背过的单词 2.仅没背的单词 3. false 为全部 | ||
memorized?: // default: false | ||
| { | ||
type: "memorized" | "unmemorized" | ||
data: string[] | ||
} | ||
| string[] | ||
| false | ||
// 1.仅单词 2.仅短语 3. true 为单词,false 为全部 | ||
word?: "word" | "phrase" | boolean // default: false | ||
// 覆盖已有文件 | ||
override?: boolean // default: false | ||
bookOpt?: BookOption | ||
} | ||
``` | ||
```ts | ||
type BookOption = { | ||
// 1. 首字母 2. 书上默认顺序 | ||
order?: "initials" | "book" // default: "book" | ||
// 顺序反转 | ||
reverse?: boolean // default: false | ||
} | ||
``` | ||
#### Export | ||
|
||
```shell | ||
pnpm dev | ||
``` | ||
|
||
## Download | ||
|
||
仓库内已经导出墨墨背单词所有本地词库,包括联网更新的词库,不包括云词库,多达上千种词库,可以在仓库中选择需要的下载([下载单个文件的方法](https://blog.csdn.net/u010801439/article/details/81478592))。 | ||
|
||
- csv:带有中文含义,可导入 List 背单词。 | ||
- list:带有 List 分组,可导入欧陆词典。 | ||
- txt:仅单词,可导入不背单词。 | ||
|
||
## Acknowledgements | ||
|
||
1. 导出方法来自于 [怎么把墨墨背单词里的词库导出来? - 你说什么的回答](https://www.zhihu.com/question/392654371/answer/1345899232) | ||
2. 词典来自于 [skywind3000/ECDICT-ultimate](https://github.com/skywind3000/ECDICT-ultimate) | ||
3. 词库来自于 [墨墨背单词](https://www.maimemo.com/) | ||
|
||
## License | ||
|
||
MIT © ourongxing |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
import { createApp } from "vinxi" | ||
import reactRefresh from "@vitejs/plugin-react" | ||
import tsconfigPaths from "vite-tsconfig-paths" | ||
import UnoCSS from "unocss/vite" | ||
import AutoImport from "unplugin-auto-import/vite" | ||
|
||
const plugins = [ | ||
tsconfigPaths(), | ||
UnoCSS(), | ||
reactRefresh(), | ||
AutoImport({ | ||
include: [ | ||
/\.[tj]sx$/, | ||
], | ||
imports: [{ | ||
clsx: [ | ||
["default", "c"], | ||
], | ||
}], | ||
}), | ||
] | ||
|
||
export default createApp({ | ||
server: { | ||
preset: "node", | ||
experimental: { | ||
websocket: true, | ||
}, | ||
}, | ||
routers: [ | ||
{ | ||
type: "static", | ||
name: "public", | ||
dir: "./public", | ||
}, | ||
{ | ||
name: "websocket", | ||
type: "http", | ||
handler: "./ws.ts", | ||
target: "server", | ||
base: "/_ws", | ||
plugins: () => plugins, | ||
}, | ||
{ | ||
type: "http", | ||
name: "trpc", | ||
base: "/trpc", | ||
handler: "./trpcServer.ts", | ||
target: "server", | ||
plugins: () => plugins, | ||
}, | ||
{ | ||
type: "spa", | ||
name: "client", | ||
handler: "./index.html", | ||
target: "browser", | ||
plugins: () => plugins, | ||
}, | ||
], | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import { ReactQueryDevtools } from "@tanstack/react-query-devtools" | ||
import { Title } from "./components/Title" | ||
import { StatusBar } from "./components/StatusBar" | ||
import { NavBar } from "./components/NavBar" | ||
import { Options } from "./components/Options" | ||
import { ShowInfo } from "./components/ShowInfo" | ||
import { WordTable } from "~/components/WordTable" | ||
|
||
import "./styles/globals.css" | ||
import "virtual:uno.css" | ||
import "@unocss/reset/tailwind.css" | ||
|
||
// 所有页面都有的 | ||
export function App() { | ||
return ( | ||
<div className="max-w-screen-lg mx-auto"> | ||
<div id="main" className="flex flex-col h-100vh px4 py6 lg:py10 gap4"> | ||
<Title /> | ||
<StatusBar /> | ||
<NavBar /> | ||
<div className="grid grid-cols-5 border-base border rounded"> | ||
<div className="col-span-3 border-base border-r"> | ||
<WordTable /> | ||
</div> | ||
<div className="col-span-2 flex flex-col"> | ||
<Options /> | ||
<ShowInfo /> | ||
</div> | ||
</div> | ||
</div> | ||
<ReactQueryDevtools position="right" /> | ||
</div> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
import type { PrimitiveAtom } from "jotai" | ||
import { atom } from "jotai" | ||
import type { ExportOptions, ExportState, PreviewLib } from "@/types" | ||
|
||
function atomWithLocalStorage<T>(key: string, initialValue: T): PrimitiveAtom<T> { | ||
const getInitialValue = () => { | ||
const item = localStorage.getItem(key) | ||
if (item !== null) | ||
return JSON.parse(item) | ||
|
||
return initialValue | ||
} | ||
const baseAtom = atom(getInitialValue()) | ||
const derivedAtom = atom( | ||
get => get(baseAtom), | ||
(get, set, update) => { | ||
const nextValue | ||
= typeof update === "function" ? update(get(baseAtom)) : update | ||
set(baseAtom, nextValue) | ||
localStorage.setItem(key, JSON.stringify(nextValue)) | ||
}, | ||
) | ||
return derivedAtom | ||
} | ||
|
||
export const initPreviewLib: PreviewLib = { | ||
name: "", | ||
id: 0, | ||
target: "word", | ||
type: "base", | ||
preview: false, | ||
} | ||
export const previewLibAtom = atom<PreviewLib>({ | ||
...initPreviewLib, | ||
}) | ||
|
||
export const exporterOptionsAtom = atomWithLocalStorage<ExportOptions>("options", { | ||
target: ["word", "list", "translation"], | ||
exculedMemorized: false, | ||
folderName: "", | ||
override: false, | ||
}) | ||
|
||
export const exportStateAtom = atom<ExportState>({ | ||
status: "idle", | ||
range: "all", | ||
logs: [], | ||
selected: [], | ||
}) | ||
|
||
export const databaseStatusAtom = atom({ | ||
maimemo_base: false, | ||
maimemo_cloud: false, | ||
ecdict: false, | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
import clsx from "clsx" | ||
import type { HTMLProps, InputHTMLAttributes } from "react" | ||
import { useEffect, useRef, useState } from "react" | ||
|
||
export function Switch({ ...props }: HTMLProps<HTMLInputElement>) { | ||
return ( | ||
<label className="relative inline-flex items-center cursor-pointer"> | ||
<input | ||
type="checkbox" | ||
checked={props.checked} | ||
className="sr-only peer" | ||
onChange={props.onChange} | ||
/> | ||
<div className={clsx("w-9 h-5 bg-primary bg-op-15 peer-focus:outline-none peer-focus:ring-0 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-4 after:w-4 after:transition-all peer-checked:bg-primary", props.className)} /> | ||
</label> | ||
) | ||
} | ||
|
||
export function Selector({ options, className, ...props }: { options: { value: string, label: string }[] } & HTMLProps<HTMLSelectElement>, | ||
) { | ||
return ( | ||
<select | ||
name="model" | ||
className={clsx(className, "w-full bg-slate bg-op-15 rounded appearance-none accent-slate text-center focus:(bg-op-20 ring-0 outline-none)")} | ||
{...props} | ||
> | ||
{ | ||
options.map(option => <option key={option.value} value={option.value}>{option.label}</option>) | ||
} | ||
</select> | ||
) | ||
} | ||
|
||
export function IndeterminateCheckbox({ | ||
indeterminate, | ||
className = "", | ||
...rest | ||
}: { indeterminate?: boolean } & HTMLProps<HTMLInputElement>) { | ||
const ref = useRef<HTMLInputElement>(null!) | ||
|
||
useEffect(() => { | ||
if (typeof indeterminate === "boolean") | ||
ref.current.indeterminate = !rest.checked && indeterminate | ||
}, [ref, indeterminate]) | ||
|
||
return ( | ||
<input | ||
type="checkbox" | ||
ref={ref} | ||
className={clsx(className, "cursor-pointer accent-primary-600")} | ||
{...rest} | ||
/> | ||
) | ||
} | ||
|
||
export function CheckBox({ options, ...props }: { options: { key: string, label: string, checked?: boolean }[] } & HTMLProps<HTMLInputElement>) { | ||
return ( | ||
<div> | ||
{ | ||
options.map(({ key, label, checked }) => ( | ||
<div key={key}> | ||
<input | ||
type="checkbox" | ||
id={key} | ||
checked={checked} | ||
{...props} | ||
/> | ||
<label className="ml-2" htmlFor={key}>{label}</label> | ||
</div> | ||
)) | ||
} | ||
</div> | ||
) | ||
} | ||
|
||
export function SettingItem({ ...props }: { | ||
children: React.ReactNode | ||
icon?: string | ||
label: string | ||
} & HTMLProps<HTMLDivElement>) { | ||
return ( | ||
<div className={clsx("flex items-center p1 justify-between hover:bg-slate hover:bg-op-10 rounded", props.className)}> | ||
<div className="flex items-center"> | ||
<button type="button" className={props.icon} /> | ||
<span className="">{props.label}</span> | ||
</div> | ||
{props.children} | ||
</div> | ||
) | ||
} | ||
|
||
export function DebouncedInput({ | ||
value: initialValue, | ||
onChange, | ||
debounce = 500, | ||
...props | ||
}: { | ||
value: string | number | ||
onChange: (value: string | number) => void | ||
debounce?: number | ||
} & Omit<InputHTMLAttributes<HTMLInputElement>, "onChange">) { | ||
const [value, setValue] = useState(initialValue) | ||
|
||
useEffect(() => { | ||
setValue(initialValue) | ||
}, [initialValue]) | ||
|
||
useEffect(() => { | ||
const timeout = setTimeout(() => { | ||
onChange(value) | ||
}, debounce) | ||
|
||
return () => clearTimeout(timeout) | ||
}, [value]) | ||
|
||
return ( | ||
<input {...props} value={value} onChange={e => setValue(e.target.value)} /> | ||
) | ||
} |
Oops, something went wrong.