Skip to content

Commit

Permalink
fix(local): rewrite the image selection, fix #102 (#110)
Browse files Browse the repository at this point in the history
* chore(local): update docs

* chore: fix typo

* fix: , fix #102

* fix: fix bug

* chore: fix missing modifier

* chore: update issue template (#108)

* chore: update issue template

* chore: fix typo

* chore(core): fix type error (#111)

---------

Co-authored-by: Maiko Sinkyaet Tan <[email protected]>
  • Loading branch information
Lipraty and MaikoTan committed Oct 30, 2023
1 parent acc22d0 commit 22231d2
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 26 deletions.
51 changes: 36 additions & 15 deletions docs/zh-CN/plugins/local.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,29 @@

图源文件夹,支持多个不同的文件夹

#### languages
#### storage

- 类型: `string[]`
- 默认值: `['zh-CN', 'en']`
- 类型: `ENUM`
- 选项: `file | database`
- 默认值: `file`

图源支持的语言
图源存数据存储方式,`file` 为文件存储,`database` 为数据库存储

#### extension
#### reload

- 类型: `boolean`
- 默认值: `false`

是否在每次启动时重新扫描图源文件夹

#### languages

- 类型: `string[]`
- 默认值: `['.jpg', '.png', '.jpeg', '.gif']`
- 默认值: `['zh-CN']`

支持的图片扩展名
图源支持的语言

### 文件设置

#### scraper

Expand All @@ -45,6 +55,13 @@

文件元信息刮削器格式,详见 [刮削器](#刮削器)

#### extension

- 类型: `string[]`
- 默认值: `['.jpg', '.png', '.jpeg', '.gif']`

支持的图片扩展名,请注意扩展名前的 `.` 是必须的

## 刮削器

:::tip
Expand All @@ -55,41 +72,45 @@

### 使用

插件设置中 `scraper` 默认值可得出大致的使用方式
插件设置中 `scraper` 默认值可得出大致的使用方式:当 `scraper``{filename}-{tag}` 时,文件名为 `foo-[bar].jpg` 的图片将被刮削为 `{name: 'foo', tag: ['bar'], ...}`

### 标签
即:文件名为 `foo` 的图片,其拥有 `bar` 这个 tags。

### 语法

#### `#...#`

- 类型: `string`
- 默认值: `name`
- 示例: `#name#{fliename}-{tag}`

(仅在开头有效)指定刮削器的工作方式,目前支持以下几种方式:
> 该语法仅在 `scraper` 的第一个元素中有效,否则将被忽略
指定刮削器的工作方式,目前支持以下几种方式:

1. `name`: 文件名模式
2. `meta`(WIP): 文件元信息模式(开发中)
2. `meta`: 文件元信息模式(开发中)

#### `{filename}`

- 类型: `string`

> `{filename}` 被放置在最后时,`+` 将失效( `{foo}-{filename}+`
> `{filename}` 被放置在最后时,`+` 将失效(e.g. `{foo}-{filename}+`
文件名
指示文件名所在的位置,文件名将被刮削为 `name`,并作为图片的 `name` 属性

#### `{tag}`

- 类型: `string[]`

图片拥有的 tag
指示标签所在的位置,标签将被刮削为 `tag`,并作为图片的 `tags` 属性

#### `{nsfw}`(WIP)

- 类型: `boolean | 'furry' | 'guro' | 'shota' | 'bl'`
- 默认值: `nsfw=false`

限制级图片
指示图片是否为 nsfw,若为 `boolean` 类型,则直接将其作为 `nsfw` 属性,若为 `string` 类型,则将其作为 `nsfw` 属性的值

#### `+`

Expand Down
45 changes: 37 additions & 8 deletions packages/local/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ declare module 'koishi' {
}

class LocalImageSource extends ImageSource<LocalImageSource.Config> {
static override inject = {
required: ['booru'],
optional: ['database', 'cache']
}
languages = []
source = 'local'
private imageMap: LocalStorage.Type[] = []
Expand All @@ -26,7 +30,7 @@ class LocalImageSource extends ImageSource<LocalImageSource.Config> {
this.languages = config.languages
this.logger = ctx.logger('booru-local')

if (this.config.storage === 'database') this.ctx.using(['database'], async (ctx, options) => {
if (config.storage === 'database') ctx.using(['database'], async (ctx) => {
ctx.model.extend('booru_local', {
storeId: 'string',
storeName: 'text',
Expand All @@ -42,7 +46,7 @@ class LocalImageSource extends ImageSource<LocalImageSource.Config> {
this.imageMap = await ctx.database.get('booru_local', {})
})

if (this.config.storage === 'file') {
if (config.storage === 'file') {
const absMap = resolve(ctx.root.baseDir, LocalImageSource.DataDir, LocalImageSource.RootMap)
if (!existsSync(resolve(ctx.root.baseDir, LocalImageSource.DataDir)))
mkdirs(resolve(ctx.root.baseDir, LocalImageSource.DataDir))
Expand All @@ -61,7 +65,7 @@ class LocalImageSource extends ImageSource<LocalImageSource.Config> {
}

// TODO: cache storage
if (this.config.storage === 'cache') this.ctx.using(['cache'], () => { })
if (config.storage === 'cache') ctx.using(['cache'], () => { })

ctx.on('ready', async () => {
if (config.endpoint.length <= 0) return this.logger.warn('no folder yet')
Expand All @@ -72,6 +76,8 @@ class LocalImageSource extends ImageSource<LocalImageSource.Config> {
images: 0
}
this.logger.info('Initializing storages...')
// duplicate check
this.config.endpoint = [...new Set(this.config.endpoint)]
if (this.imageMap.length > 0) mapping = mapping.update(this.imageMap)
// mapping the folders to memory by loop
for await (let path of config.endpoint) {
Expand Down Expand Up @@ -102,11 +108,34 @@ class LocalImageSource extends ImageSource<LocalImageSource.Config> {

async get(query: ImageSource.Query): Promise<ImageSource.Result[]> {
if (this.imageMap.length < 1) return undefined
const map = this.imageMap.length === 1 ? this.imageMap[0] : Random.pick(this.imageMap)
if (query.tags.length > 0) {
map.images = map.images.filter(img => [...new Set([...img.tags, ...query.tags])].length > 0)
let pickPool = [];
// Flatten all maps
if (this.imageMap.length > 1) {
for (const storage of this.imageMap) {
if (query.tags.length > 0) {
// filter by tags
for (const image of storage.images) {
if (query.tags.every(tag => image.tags.includes(tag)))
pickPool.push(image)
}
} else {
// pick from all images
pickPool.push(...storage.images)
}
}
} else {
// pick from one image map
pickPool = this.imageMap.map((storage) => {
if (query.tags.length > 0) {
// filter by tags
return storage.images.filter((image) => query.tags.every(tag => image.tags.includes(tag)))
} else {
// pick from all images
return storage.images
}
}).flat()
}
const picker = Random.pick(map.images, query.count)
const picker = Random.pick(pickPool, query.count)
return picker.map(img => {
return {
url: pathToFileURL(img.path).href,
Expand Down Expand Up @@ -137,7 +166,7 @@ namespace LocalImageSource {
// TODO: Schema.path()?
endpoint: Schema.array(String).description('图源文件夹,支持多个不同的文件夹'),
storage: Schema.union<Mapping.Storage>(['file', 'database']).description('图源数据保存方式').default('file'),
reload: Schema.boolean().description('每次启动时重新加载所有图片').default(false),
reload: Schema.boolean().description('每次启动时重新构建图源数据').default(false),
languages: Schema.array(String).description('支持的语言').default(['zh-CN'])
}).description('图源设置'),
Schema.object({
Expand Down
6 changes: 3 additions & 3 deletions packages/local/src/scraper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ const element = {
tag: '(\\[.+\\])',
}

const nfsw = [true, false, 'furry', 'guro', 'shota', 'bl']
type Nfsw = boolean | 'furry' | 'guro' | 'shota' | 'bl'
const nsfw = [true, false, 'furry', 'guro', 'shota', 'bl']
type Nsfw = boolean | 'furry' | 'guro' | 'shota' | 'bl'

const format = {
filename: (name: string) => name,
tag: (tags: string) => tags.slice(1, -1).replace(',', ',').split(',').map(s => s.trim()),
nfsw: (tag: string) => nfsw.includes(tag.split('=')[1])
nsfw: (tag: string) => nsfw.includes(tag.split('=')[1])
}

const mapping = {
Expand Down

0 comments on commit 22231d2

Please sign in to comment.