Skip to content

Commit 2a80367

Browse files
authored
Merge pull request #196 from SchneeHertz/development
Development
2 parents d104cc6 + f711f50 commit 2a80367

File tree

10 files changed

+82
-47
lines changed

10 files changed

+82
-47
lines changed

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,16 @@ All notable changes to this project will be documented in this file. Dates are d
44

55
Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
66

7+
#### [v1.6.3](https://github.com/SchneeHertz/exhentai-manga-manager/compare/v1.6.2...v1.6.3)
8+
9+
> 26 October 2024
10+
11+
- Development [`#181`](https://github.com/SchneeHertz/exhentai-manga-manager/pull/181)
12+
- add ".ehviewer" metadata support #55 [`#174`](https://github.com/SchneeHertz/exhentai-manga-manager/pull/174)
13+
- add ".ehviewer" metadata support [`d631595`](https://github.com/SchneeHertz/exhentai-manga-manager/commit/d6315953aac051782a45a38e8fae05e70bf85db4)
14+
- update collection card css [`b855387`](https://github.com/SchneeHertz/exhentai-manga-manager/commit/b85538738e7ae7b24b9ba760d01470ca26dc142c)
15+
- Update index.js [`c67fcad`](https://github.com/SchneeHertz/exhentai-manga-manager/commit/c67fcad98008a268823f9631847760170e4f6551)
16+
717
#### [v1.6.2](https://github.com/SchneeHertz/exhentai-manga-manager/compare/v1.6.1...v1.6.2)
818

919
> 8 September 2024

index.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -664,10 +664,11 @@ ipcMain.handle('select-folder', async (event, title) => {
664664
}
665665
})
666666

667-
ipcMain.handle('select-file', async (event, title) => {
667+
ipcMain.handle('select-file', async (event, title, filters) => {
668668
const result = await dialog.showOpenDialog(mainWindow, {
669669
title,
670-
properties: ['openFile']
670+
properties: ['openFile'],
671+
filters
671672
})
672673
if (!result.canceled) {
673674
return result.filePaths[0]
@@ -727,7 +728,8 @@ ipcMain.handle('import-database', async (event, arg) => {
727728

728729
ipcMain.handle('import-sqlite', async (event, bookList) => {
729730
const result = await dialog.showOpenDialog(mainWindow, {
730-
properties: ['openFile']
731+
properties: ['openFile'],
732+
filters: [{ name: 'SQLite', extensions: ['sqlite'] }]
731733
})
732734
if (!result.canceled) {
733735
const db = await open({

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "exhentai-manga-manager",
33
"private": true,
4-
"version": "1.6.3",
4+
"version": "1.6.4",
55
"author": "SchneeHertz",
66
"description": "Tag-based management, reading manga downloaded from ExHentai",
77
"repository": {

src/App.vue

Lines changed: 36 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@
6767
<el-option :label="$t('m.artistDescend')" value="artistDescend"></el-option>
6868
<el-option :label="$t('m.titleAscend')" value="titleAscend"></el-option>
6969
<el-option :label="$t('m.titleDescend')" value="titleDescend"></el-option>
70+
<el-option :label="$t('m.pageAscend')" value="pageAscend"></el-option>
71+
<el-option :label="$t('m.pageDescend')" value="pageDescend"></el-option>
7072
</el-option-group>
7173
</el-select>
7274
</el-col>
@@ -131,7 +133,6 @@
131133
@contextmenu="onBookContextMenu($event, book)"
132134
/>
133135
<el-tag class="book-card-language" size="small"
134-
:effect="isChineseTranslatedManga(book) ? 'dark' : 'light'"
135136
:type="isChineseTranslatedManga(book) ? 'danger' : 'info'"
136137
@click="handleSearchString(`:count=${book.readCount}`)"
137138
>{{book.readCount}}</el-tag>
@@ -175,7 +176,6 @@
175176
<p class="book-title" :title="book.title">{{book.title}}</p>
176177
<img class="book-cover" :src="book.coverPath" @click="openCollection(book)"/>
177178
<el-tag class="book-card-language" size="small"
178-
:effect="isChineseTranslatedManga(book) ? 'dark' : 'light'"
179179
:type="isChineseTranslatedManga(book) ? 'danger' : 'info'"
180180
@click="handleSearchString(`:count=${book.readCount}`)"
181181
>{{book.readCount}}</el-tag>
@@ -360,7 +360,6 @@
360360
@contextmenu="onBookContextMenu($event, book)"
361361
/>
362362
<el-tag class="book-card-language" size="small"
363-
:effect="isChineseTranslatedManga(book) ? 'dark' : 'light'"
364363
:type="isChineseTranslatedManga(book) ? 'danger' : 'info'"
365364
@click="handleSearchString(`:count=${book.readCount}`)"
366365
>{{book.readCount}}</el-tag>
@@ -594,6 +593,7 @@
594593
:setting="setting"
595594
@message="printMessage"
596595
@resolve-search-result="resolveSearchResult"
596+
@service-available="setServiceAvailable"
597597
></SearchDialog>
598598
<Setting
599599
ref="SettingRef"
@@ -1309,12 +1309,15 @@ export default defineComponent({
13091309
if (type === 'hentag') {
13101310
book.url = url
13111311
this.getBookInfoFromHentag(book)
1312-
} else {
1312+
} else if (type === 'e-hentai') {
13131313
book.url = url
13141314
this.getBookInfoFromEh(book)
13151315
}
13161316
this.$refs.SearchDialogRef.dialogVisibleEhSearch = false
13171317
},
1318+
setServiceAvailable (value) {
1319+
this.serviceAvailable = value
1320+
},
13181321
async getBookInfoFromHentag (book) {
13191322
const data = await fetch(`https://hentag.com/public/api/vault/${book.url.slice(25)}`).then(res => res.json())
13201323
const tags = {}
@@ -1412,21 +1415,21 @@ export default defineComponent({
14121415
},
14131416
async resetMetadata (book) {
14141417
book.title = this.returnFileName(book)
1415-
book.title_jpn = ''
1416-
book.posted = 0
1417-
book.filecount = 0
1418-
book.rating = 0
1419-
book.filesize = 0
1420-
book.category = ''
1418+
book.title_jpn = null
1419+
book.posted = null
1420+
book.filecount = null
1421+
book.rating = null
1422+
book.filesize = null
1423+
book.category = null
14211424
book.tags = {}
14221425
book.status = 'non-tag'
1423-
book.url = ''
1426+
book.url = null
14241427
await this.saveBook(book)
14251428
},
14261429
getBookInfo (book) {
14271430
if (book.url.startsWith('https://hentag.com')) {
14281431
this.getBookInfoFromHentag(book)
1429-
} else {
1432+
} else if (book.url.includes('exhentai') || book.url.includes('e-hentai')) {
14301433
this.getBookInfoFromEh(book)
14311434
}
14321435
},
@@ -1572,6 +1575,14 @@ export default defineComponent({
15721575
this.displayBookList = bookList.toSorted((a, b) => this.getDisplayTitle(b).localeCompare(this.getDisplayTitle(a), undefined, {numeric: true, sensitivity: 'base'}))
15731576
this.chunkList()
15741577
break
1578+
case 'pageAscend':
1579+
this.displayBookList = bookList.toSorted(this.sortList('pageCount')).toReversed()
1580+
this.chunkList()
1581+
break
1582+
case 'pageDescend':
1583+
this.displayBookList = bookList.toSorted(this.sortList('pageCount'))
1584+
this.chunkList()
1585+
break
15751586
default:
15761587
this.displayBookList = this.bookList
15771588
this.chunkList()
@@ -1586,7 +1597,7 @@ export default defineComponent({
15861597
if (queryString) {
15871598
const keywords = [...queryString.matchAll(/\s+(?=(?:[^\'"]*[\'"][^\'"]*[\'"])*[^\'"]*$)/g)]
15881599
if (!_.isEmpty(keywords)) {
1589-
const nextKeyword = queryString.replace(/(~|-)?[\w\d一-龟]+:"[- ._\w\d一-龟]+"\$/g, '').trim()
1600+
const nextKeyword = queryString.replace(/(~|-)?[\w\d一-龟]+:"[- ._\(\)\w\d一-龟]+"\$/g, '').trim()
15901601
if (nextKeyword[0] === '-' || nextKeyword[0] === '~') {
15911602
result = _.filter(options, (str) => {
15921603
return _.includes(str.value.toLowerCase(), nextKeyword.slice(1).toLowerCase())
@@ -1624,11 +1635,11 @@ export default defineComponent({
16241635
},
16251636
handleInput (val) {
16261637
try {
1627-
if (/^[\w\d一-龟]+:"[- ._\w\d一-龟]+"\$$/.test(val) && this.searchString.trim() !== val.trim()) {
1638+
if (/^[\w\d一-龟]+:"[- ._\(\)\w\d一-龟]+"\$$/.test(val) && this.searchString.trim() !== val.trim()) {
16281639
const keywords = [...this.searchString.trim().matchAll(/\s+(?=(?:[^\'"]*[\'"][^\'"]*[\'"])*[^\'"]*$)/g)]
16291640
if (!_.isEmpty(keywords)) {
1630-
const keyword = this.searchString.replace(/(~|-)?[\w\d一-龟]+:"[- ._\w\d一-龟]+"\$/g, '').trim()
1631-
const matches = this.searchString.match(/(~|-)?[\w\d一-龟]+:"[- ._\w\d一-龟]+"\$/g)
1641+
const keyword = this.searchString.replace(/(~|-)?[\w\d一-龟]+:"[- ._\(\)\w\d一-龟]+"\$/g, '').trim()
1642+
const matches = this.searchString.match(/(~|-)?[\w\d一-龟]+:"[- ._\(\)\w\d一-龟]+"\$/g)
16321643
if (keyword[0] === '-') {
16331644
this.searchString = matches.concat([`-${val}`]).join(' ')
16341645
} else if (keyword[0] === '~') {
@@ -1828,8 +1839,12 @@ export default defineComponent({
18281839
this.folderTreeData = await ipcRenderer.invoke('get-folder-tree', bookList)
18291840
},
18301841
async selectFolderTreeNode (selectNode) {
1831-
const clickLibraryPath = this.setting.library + this.pathSep + selectNode.folderPath
1832-
this.bookList.map(book => book.folderHide = !book.filepath.startsWith(clickLibraryPath))
1842+
if (selectNode.folderPath) {
1843+
const clickLibraryPath = this.setting.library + this.pathSep + selectNode.folderPath + this.pathSep
1844+
this.bookList.map(book => book.folderHide = !book.filepath.startsWith(clickLibraryPath))
1845+
} else {
1846+
this.bookList.map(book => book.folderHide = false)
1847+
}
18331848
this.chunkList()
18341849
},
18351850
handleNodeExpand (nodeObject) {
@@ -1866,6 +1881,7 @@ export default defineComponent({
18661881
const mark = _.some(collectBook, 'mark')
18671882
const pageDiff = _.some(collectBook, 'pageDiff') ? true : undefined
18681883
const readCount = _.max(collectBook.map(book => book.readCount))
1884+
const pageCount = _.sum(collectBook.map(book => book.pageCount))
18691885
const tags = _.mergeWith({}, ...collectBook.map(book => book.tags), (obj, src) => {
18701886
if (_.isArray(obj) && _.isArray(src)) {
18711887
return [...new Set(obj.concat(src))]
@@ -1882,7 +1898,7 @@ export default defineComponent({
18821898
title: collection.title,
18831899
id: collection.id,
18841900
coverPath: collectBook?.[0]?.coverPath,
1885-
date, posted, rating, mtime, mark, tags, title_jpn, category, status, pageDiff, readCount,
1901+
date, posted, rating, mtime, mark, tags, title_jpn, category, status, pageDiff, readCount, pageCount,
18861902
list: collection.list,
18871903
filepath,
18881904
isCollection: true,
@@ -2090,7 +2106,7 @@ export default defineComponent({
20902106
resolveGroupTagSelected () {
20912107
const letter2cat = _.invert(this.cat2letter)
20922108
let tags = this.groupTagSelected.map(tag => {
2093-
const match = /([\w\d一-龟]+):"([- ._\w\d一-龟]+)"\$/.exec(tag)
2109+
const match = /([\w\d一-龟]+):"([- ._\(\)\w\d一-龟]+)"\$/.exec(tag)
20942110
if (match[1] && match[2]) {
20952111
return {
20962112
category: letter2cat[match[1]] ? letter2cat[match[1]] : match[1],

src/components/InternalViewer.vue

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@
1010
>
1111
<div class="drawer-viewer-body"
1212
ref="drawerViewerBody"
13-
@click="handleViewerAreaClick"
1413
>
1514
<div class="drawer-image-content"
1615
v-if="!showThumbnail"
1716
v-loading="viewerImageList.length === 0"
1817
element-loading-text="Loading"
1918
element-loading-background="transparent"
19+
@click="handleViewerAreaClick"
2020
>
2121
<div v-if="imageStyleType === 'scroll'">
2222
<div
@@ -36,7 +36,7 @@
3636
<div class="viewer-image-page" v-if="!setting.hidePageNumber">{{index + 1}} of {{viewerImageList.length}}</div>
3737
</div>
3838
</div>
39-
<div v-else-if="imageStyleType === 'single'">
39+
<div v-else-if="imageStyleType === 'single'" class="image-frame-outside">
4040
<div class="image-frame">
4141
<div class="viewer-image-frame" :style="returnImageStyle(viewerImageList[currentImageIndex])">
4242
<img
@@ -57,7 +57,7 @@
5757
/>
5858
</div>
5959
</div>
60-
<div v-else-if="imageStyleType === 'double'">
60+
<div v-else-if="imageStyleType === 'double'" class="image-frame-outside">
6161
<div class="image-frame">
6262
<div class="viewer-image-frame viewer-image-frame-double">
6363
<img
@@ -352,36 +352,36 @@ const returnImageStyle = (image) => {
352352
if (props.setting.hidePageNumber) {
353353
return returnImageStyleObject({height: innerHeight - 1})
354354
} else {
355-
// 28,30 is the height of .viewer-image-page
356-
return returnImageStyleObject({height: innerHeight - 30})
355+
// minus 36 for the height of .viewer-image-page
356+
return returnImageStyleObject({height: innerHeight - 36})
357357
}
358358
}
359359
case 'width': {
360-
// 18 is the width of scrollbar
360+
// minus 32 for the width of scrollbar
361361
if (image.width > image.height) {
362-
return returnImageStyleObject({width: innerWidth - 18})
362+
return returnImageStyleObject({width: innerWidth - 32})
363363
} else {
364-
return returnImageStyleObject({width: (innerWidth - 18) / 2})
364+
return returnImageStyleObject({width: (innerWidth - 32) / 2})
365365
}
366366
}
367367
case 'window': {
368368
if (image.width > image.height) {
369369
if (image.width / image.height > windowRatio) {
370-
return returnImageStyleObject({width: innerWidth - 18})
370+
return returnImageStyleObject({width: innerWidth - 32})
371371
} else {
372372
if (props.setting.hidePageNumber) {
373373
return returnImageStyleObject({height: innerHeight})
374374
} else {
375-
return returnImageStyleObject({height: innerHeight - 30})
375+
return returnImageStyleObject({height: innerHeight - 36})
376376
}
377377
}
378378
} else if (image.width * 2 / image.height > windowRatio) {
379-
return returnImageStyleObject({width: (innerWidth - 18) / 2 })
379+
return returnImageStyleObject({width: (innerWidth - 32) / 2 })
380380
} else {
381381
if (props.setting.hidePageNumber) {
382382
return returnImageStyleObject({height: innerHeight - 1})
383383
} else {
384-
return returnImageStyleObject({height: innerHeight - 30})
384+
return returnImageStyleObject({height: innerHeight - 36})
385385
}
386386
}
387387
}
@@ -393,20 +393,20 @@ const returnImageStyle = (image) => {
393393
if (props.setting.hidePageNumber) {
394394
return returnImageStyleObject({height: innerHeight})
395395
} else {
396-
return returnImageStyleObject({height: innerHeight - 30})
396+
return returnImageStyleObject({height: innerHeight - 36})
397397
}
398398
}
399399
case 'width': {
400-
return returnImageStyleObject({width: innerWidth - 18})
400+
return returnImageStyleObject({width: innerWidth - 32})
401401
}
402402
case 'window': {
403403
if (image.width / image.height > windowRatio) {
404-
return returnImageStyleObject({width: innerWidth - 18})
404+
return returnImageStyleObject({width: innerWidth - 32})
405405
} else {
406406
if (props.setting.hidePageNumber) {
407407
return returnImageStyleObject({height: innerHeight})
408408
} else {
409-
return returnImageStyleObject({height: innerHeight - 30})
409+
return returnImageStyleObject({height: innerHeight - 36})
410410
}
411411
}
412412
}
@@ -618,10 +618,10 @@ defineExpose({
618618
.drawer-viewer-body
619619
width: 100%
620620
height: 100%
621-
display: flex
622-
align-items: center
623-
justify-content: center
624-
621+
.image-frame-outside
622+
height: 100vh
623+
display: flex
624+
justify-content: center
625625
.viewer-close-button
626626
position: absolute
627627
top: 28px

src/components/SearchDialog.vue

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ import { Link } from '@element-plus/icons-vue'
5353
5454
const props = defineProps(['cookie', 'searchTypeList', 'setting'])
5555
56-
const emit = defineEmits(['message', 'resolveSearchResult'])
56+
const emit = defineEmits(['message', 'resolveSearchResult', 'serviceAvailable'])
5757
5858
const dialogVisibleEhSearch = ref(false)
5959
const searchResultLoading = ref(false)
@@ -180,6 +180,7 @@ const resolveEhentaiResult = (htmlString) => {
180180
} catch (e) {
181181
console.log(e)
182182
if (htmlString.includes('Your IP address has been')) {
183+
emit('serviceAvailable', false)
183184
emit('message', 'error', t('c.ipBanned'))
184185
} else {
185186
emit('message', 'error', t('c.getMetadataFailed'))

src/components/Setting.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -646,8 +646,8 @@ const exportDatabase = async () => {
646646
}
647647
648648
const importDatabase = async () => {
649-
const collectionListPath = await ipcRenderer.invoke('select-file', t('c.selectCollectionList'))
650-
const metadataSqlitePath = await ipcRenderer.invoke('select-file', t('c.selectMetadataSqlite'))
649+
const collectionListPath = await ipcRenderer.invoke('select-file', t('c.selectCollectionList'), [{name: 'JSON', extensions: ['json']}])
650+
const metadataSqlitePath = await ipcRenderer.invoke('select-file', t('c.selectMetadataSqlite'), [{name: 'SQLite', extensions: ['sqlite']}])
651651
await ipcRenderer.invoke('import-database', {collectionListPath, metadataSqlitePath})
652652
emit('message', 'success', t('c.importMessage'))
653653
}

src/locales/en-US.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
"artistDescend": "Artist Descend",
2323
"titleAscend": "Title Ascend",
2424
"titleDescend": "Title Descend",
25+
"pageAscend": "Page Ascend",
26+
"pageDescend": "Page Descend",
2527
"manageCollection": "Manage Collection",
2628
"addCollection": "Add Collection",
2729
"editCollection": "Edit Collection",

src/locales/zh-CN.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
"artistDescend": "作者倒序",
2323
"titleAscend": "标题正序",
2424
"titleDescend": "标题倒序",
25+
"pageAscend": "页数正序",
26+
"pageDescend": "页数倒序",
2527
"manageCollection": "管理合集",
2628
"addCollection": "新增合集",
2729
"editCollection": "编辑合集",

src/locales/zh-TW.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
"artistDescend": "作者降序",
2323
"titleAscend": "標題升序",
2424
"titleDescend": "標題降序",
25+
"pageAscend": "頁數升序",
26+
"pageDescend": "頁數降序",
2527
"manageCollection": "管理合集",
2628
"addCollection": "新增合集",
2729
"editCollection": "編輯合集",

0 commit comments

Comments
 (0)