export when downloading

This commit is contained in:
niuhuan 2021-10-25 19:27:38 +08:00
parent 78db409055
commit 7debe9269b
8 changed files with 204 additions and 18 deletions

View File

@ -1,12 +1,15 @@
package controller package controller
import ( import (
"bytes"
"fmt" "fmt"
"image"
"io/ioutil" "io/ioutil"
"os" "os"
"path"
"path/filepath" "path/filepath"
"pikapi/main/database/comic_center" "pikapi/main/database/comic_center"
utils2 "pikapi/main/utils" "pikapi/main/utils"
"time" "time"
) )
@ -225,6 +228,7 @@ func downloadSummaryDownload() {
} }
if over { if over {
// 如果所有章节下载完成则下载成功 // 如果所有章节下载完成则下载成功
downloadAndExportLogo(downloadingComic)
err = comic_center.DownloadSuccess(downloadingComic.ID) err = comic_center.DownloadSuccess(downloadingComic.ID)
if err != nil { if err != nil {
panic(err) panic(err)
@ -297,7 +301,7 @@ func downloadInitPicture() {
// 下载指定图片 // 下载指定图片
func downloadThePicture(picturePoint *comic_center.ComicDownloadPicture) error { func downloadThePicture(picturePoint *comic_center.ComicDownloadPicture) error {
// 为了不和页面前端浏览的数据冲突, 使用url做hash锁 // 为了不和页面前端浏览的数据冲突, 使用url做hash锁
lock := utils2.HashLock(fmt.Sprintf("%s$%s", picturePoint.FileServer, picturePoint.Path)) lock := utils.HashLock(fmt.Sprintf("%s$%s", picturePoint.FileServer, picturePoint.Path))
lock.Lock() lock.Lock()
defer lock.Unlock() defer lock.Unlock()
// 图片保存位置使用相对路径储存, 使用绝对路径操作 // 图片保存位置使用相对路径储存, 使用绝对路径操作
@ -315,12 +319,14 @@ func downloadThePicture(picturePoint *comic_center.ComicDownloadPicture) error {
// 将图片保存到文件 // 将图片保存到文件
dir := filepath.Dir(realPath) dir := filepath.Dir(realPath)
if _, err := os.Stat(dir); os.IsNotExist(err) { if _, err := os.Stat(dir); os.IsNotExist(err) {
os.Mkdir(dir, utils2.CreateDirMode) os.Mkdir(dir, utils.CreateDirMode)
} }
err = ioutil.WriteFile(downloadPath(picturePath), buff, utils2.CreateFileMode) err = ioutil.WriteFile(downloadPath(picturePath), buff, utils.CreateFileMode)
if err != nil { if err != nil {
return err return err
} }
// 下载时同时导出
downloadAndExport(downloadingComic, downloadingEp, picturePoint, buff, format)
// 存入数据库 // 存入数据库
return comic_center.PictureSuccess( return comic_center.PictureSuccess(
picturePoint.ComicId, picturePoint.ComicId,
@ -364,3 +370,92 @@ func downloadSummaryEp() {
// 去加载下一个EP // 去加载下一个EP
go downloadLoadEp() go downloadLoadEp()
} }
var downloadAndExportPath = ""
func downloadAndExport(
downloadingComic *comic_center.ComicDownload,
downloadingEp *comic_center.ComicDownloadEp,
downloadingPicture *comic_center.ComicDownloadPicture,
buff []byte,
format string,
) {
if downloadAndExportPath == "" {
return
}
if i, e := os.Stat(downloadAndExportPath); e == nil {
if i.IsDir() {
// 进入漫画目录
comicDir := path.Join(downloadAndExportPath, utils.ReasonableFileName(downloadingComic.Title))
i, e = os.Stat(comicDir)
if e != nil {
if os.IsNotExist(e) {
e = os.Mkdir(comicDir, utils.CreateDirMode)
} else {
return
}
}
if e != nil {
return
}
// 进入章节目录
epDir := path.Join(comicDir, utils.ReasonableFileName(fmt.Sprintf("%02d - ", downloadingEp.EpOrder)+downloadingEp.Title))
i, e = os.Stat(epDir)
if e != nil {
if os.IsNotExist(e) {
e = os.Mkdir(epDir, utils.CreateDirMode)
} else {
return
}
}
if e != nil {
return
}
// 写入文件
filePath := path.Join(epDir, fmt.Sprintf("%03d.%s", downloadingPicture.RankInEp, jFormat(format)))
ioutil.WriteFile(filePath, buff, utils.CreateFileMode)
}
}
}
func downloadAndExportLogo(
downloadingComic *comic_center.ComicDownload,
) {
if downloadAndExportPath == "" {
return
}
comicLogoPath := downloadPath(path.Join(downloadingComic.ID, "logo"))
if _, e := os.Stat(comicLogoPath); e == nil {
buff, e := ioutil.ReadFile(comicLogoPath)
if e == nil {
_, f, e := image.Decode(bytes.NewBuffer(buff))
if e == nil {
if i, e := os.Stat(downloadAndExportPath); e == nil {
if i.IsDir() {
// 进入漫画目录
comicDir := path.Join(downloadAndExportPath, utils.ReasonableFileName(downloadingComic.Title))
i, e = os.Stat(comicDir)
if e != nil {
if os.IsNotExist(e) {
e = os.Mkdir(comicDir, utils.CreateDirMode)
}
}
if e != nil {
return
}
// 写入文件
filePath := path.Join(comicDir, fmt.Sprintf("%s.%s", "logo", jFormat(f)))
ioutil.WriteFile(filePath, buff, utils.CreateFileMode)
}
}
}
}
}
}
func jFormat(format string) string {
if format == "jpeg" {
return "jpg"
}
return format
}

View File

@ -14,7 +14,6 @@ import (
"path" "path"
"pikapi/main/database/comic_center" "pikapi/main/database/comic_center"
"pikapi/main/utils" "pikapi/main/utils"
"strings"
"time" "time"
) )
@ -91,7 +90,7 @@ func exportComicDownload(params string) (filePath string, err error) {
err = errors.New("not download finish") err = errors.New("not download finish")
return return
} }
filePath = path.Join(dir, fmt.Sprintf("%s-%s.zip", reasonablePath(comic.Title), time.Now().Format("2006_01_02_15_04_05.999"))) filePath = path.Join(dir, fmt.Sprintf("%s-%s.zip", utils.ReasonableFileName(comic.Title), time.Now().Format("2006_01_02_15_04_05.999")))
println(fmt.Sprintf("ZIP : %s", filePath)) println(fmt.Sprintf("ZIP : %s", filePath))
fileStream, err := os.Create(filePath) fileStream, err := os.Create(filePath)
if err != nil { if err != nil {
@ -109,17 +108,6 @@ func exportComicDownload(params string) (filePath string, err error) {
return return
} }
func reasonablePath(title string) string {
title = strings.ReplaceAll(title, "\\", "_")
title = strings.ReplaceAll(title, "/", "_")
title = strings.ReplaceAll(title, "*", "_")
title = strings.ReplaceAll(title, "?", "_")
title = strings.ReplaceAll(title, "<", "_")
title = strings.ReplaceAll(title, ">", "_")
title = strings.ReplaceAll(title, "|", "_")
return title
}
func exportComicDownloadFetch(comicId string, onWriteFile func(path string, size int64) (io.Writer, error)) error { func exportComicDownloadFetch(comicId string, onWriteFile func(path string, size int64) (io.Writer, error)) error {
comic, err := comic_center.FindComicDownloadById(comicId) comic, err := comic_center.FindComicDownloadById(comicId)
if err != nil { if err != nil {
@ -384,7 +372,7 @@ func exportComicDownloadToJPG(params string) error {
if !comic.DownloadFinished { if !comic.DownloadFinished {
return errors.New("not download finish") return errors.New("not download finish")
} }
dirPath := path.Join(dir, fmt.Sprintf("%s-%s", reasonablePath(comic.Title), time.Now().Format("2006_01_02_15_04_05.999"))) dirPath := path.Join(dir, fmt.Sprintf("%s-%s", utils.ReasonableFileName(comic.Title), time.Now().Format("2006_01_02_15_04_05.999")))
println(fmt.Sprintf("DIR : %s", dirPath)) println(fmt.Sprintf("DIR : %s", dirPath))
err = os.Mkdir(dirPath, utils.CreateDirMode) err = os.Mkdir(dirPath, utils.CreateDirMode)
if err != nil { if err != nil {

View File

@ -29,6 +29,7 @@ func InitPlugin(_remoteDir string, _downloadDir string, _tmpDir string) {
downloadDir = _downloadDir downloadDir = _downloadDir
tmpDir = _tmpDir tmpDir = _tmpDir
comic_center.ResetAll() comic_center.ResetAll()
downloadAndExportPath = loadDownloadAndExportPath()
go downloadBackground() go downloadBackground()
downloadRunning = true downloadRunning = true
} }
@ -59,6 +60,19 @@ func loadProperty(params string) (string, error) {
return properties.LoadProperty(paramsStruct.Name, paramsStruct.DefaultValue) return properties.LoadProperty(paramsStruct.Name, paramsStruct.DefaultValue)
} }
func saveDownloadAndExportPath(value string) error {
err := properties.SaveProperty("downloadAndExportPath", value)
if err == nil {
downloadAndExportPath = value
}
return err
}
func loadDownloadAndExportPath() string {
p, _ := properties.LoadProperty("downloadAndExportPath", "")
return p
}
func setSwitchAddress(nSwitchAddress string) error { func setSwitchAddress(nSwitchAddress string) error {
err := properties.SaveSwitchAddress(nSwitchAddress) err := properties.SaveSwitchAddress(nSwitchAddress)
if err != nil { if err != nil {
@ -601,6 +615,10 @@ func FlatInvoke(method string, params string) (string, error) {
return "", convertImageToJPEG100(params) return "", convertImageToJPEG100(params)
case "specialDownloadTitle": case "specialDownloadTitle":
return specialDownloadTitle(params) return specialDownloadTitle(params)
case "loadDownloadAndExportPath":
return loadDownloadAndExportPath(), nil
case "saveDownloadAndExportPath":
return "", saveDownloadAndExportPath(params)
} }
return "", errors.New("method not found : " + method) return "", errors.New("method not found : " + method)
} }

View File

@ -2,6 +2,7 @@ package utils
import ( import (
"os" "os"
"strings"
) )
func Mkdir(dir string) { func Mkdir(dir string) {
@ -16,3 +17,14 @@ func Mkdir(dir string) {
} }
} }
} }
func ReasonableFileName(title string) string {
title = strings.ReplaceAll(title, "\\", "_")
title = strings.ReplaceAll(title, "/", "_")
title = strings.ReplaceAll(title, "*", "_")
title = strings.ReplaceAll(title, "?", "_")
title = strings.ReplaceAll(title, "<", "_")
title = strings.ReplaceAll(title, ">", "_")
title = strings.ReplaceAll(title, "|", "_")
return title
}

View File

@ -572,4 +572,13 @@ class Method {
return _channel.invokeMethod("migrate", {"path": path}); return _channel.invokeMethod("migrate", {"path": path});
} }
/// -
Future loadDownloadAndExportPath() {
return _flatInvoke("loadDownloadAndExportPath", "");
}
/// -
Future saveDownloadAndExportPath(String folder) {
return _flatInvoke("saveDownloadAndExportPath", folder);
}
} }

View File

@ -0,0 +1,60 @@
import 'dart:io';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:pikapi/basic/Common.dart';
import 'package:pikapi/basic/Cross.dart';
import '../Method.dart';
late String _downloadAndExportPath;
Future initDownloadAndExportPath() async {
_downloadAndExportPath = await method.loadDownloadAndExportPath();
}
Widget downloadAndExportPathSetting() {
if (Platform.isWindows ||
Platform.isMacOS ||
Platform.isAndroid ||
Platform.isLinux) {
return StatefulBuilder(
builder: (BuildContext context, void Function(void Function()) setState) {
return ListTile(
title: Text("下载的同时导出到文件系统"),
subtitle: Text(_downloadAndExportPath),
onTap: () async {
if (_downloadAndExportPath == "") {
bool b = await confirmDialog(
context,
"下载的同时导出到文件系统",
"您即将选择一个目录, 如果文件系统可写, 下载的同时会为您自动导出一份",
);
if (b) {
String? folder = await chooseFolder(context);
if (folder != null) {
await method.saveDownloadAndExportPath(folder);
_downloadAndExportPath = folder;
setState(() {});
}
}
} else {
bool b = await confirmDialog(
context,
"下载的同时导出到文件系统",
"您确定取消下载并导出的功能吗? 取消之后您可以再次点击设置",
);
if (b) {
var folder = "";
await method.saveDownloadAndExportPath(folder);
_downloadAndExportPath = folder;
setState(() {});
}
}
},
);
},
);
}
return Container();
}

View File

@ -5,6 +5,7 @@ import 'package:pikapi/basic/config/AutoClean.dart';
import 'package:pikapi/basic/config/AutoFullScreen.dart'; import 'package:pikapi/basic/config/AutoFullScreen.dart';
import 'package:pikapi/basic/config/ChooserRoot.dart'; import 'package:pikapi/basic/config/ChooserRoot.dart';
import 'package:pikapi/basic/config/ContentFailedReloadAction.dart'; import 'package:pikapi/basic/config/ContentFailedReloadAction.dart';
import 'package:pikapi/basic/config/DownloadAndExportPath.dart';
import 'package:pikapi/basic/config/FullScreenAction.dart'; import 'package:pikapi/basic/config/FullScreenAction.dart';
import 'package:pikapi/basic/config/FullScreenUI.dart'; import 'package:pikapi/basic/config/FullScreenUI.dart';
import 'package:pikapi/basic/config/KeyboardController.dart'; import 'package:pikapi/basic/config/KeyboardController.dart';
@ -61,6 +62,7 @@ class _InitScreenState extends State<InitScreen> {
await initAndroidDisplayMode(); await initAndroidDisplayMode();
await initChooserRoot(); await initChooserRoot();
await initTimeZone(); await initTimeZone();
await initDownloadAndExportPath();
// , token失效重新登录, 1 // , token失效重新登录, 1
if (await method.preLogin()) { if (await method.preLogin()) {
// token或username+password有效则直接进入登录好的界面 // token或username+password有效则直接进入登录好的界面

View File

@ -8,6 +8,7 @@ import 'package:pikapi/basic/config/AutoClean.dart';
import 'package:pikapi/basic/config/AutoFullScreen.dart'; import 'package:pikapi/basic/config/AutoFullScreen.dart';
import 'package:pikapi/basic/config/ChooserRoot.dart'; import 'package:pikapi/basic/config/ChooserRoot.dart';
import 'package:pikapi/basic/config/ContentFailedReloadAction.dart'; import 'package:pikapi/basic/config/ContentFailedReloadAction.dart';
import 'package:pikapi/basic/config/DownloadAndExportPath.dart';
import 'package:pikapi/basic/config/FullScreenAction.dart'; import 'package:pikapi/basic/config/FullScreenAction.dart';
import 'package:pikapi/basic/config/FullScreenUI.dart'; import 'package:pikapi/basic/config/FullScreenUI.dart';
import 'package:pikapi/basic/config/KeyboardController.dart'; import 'package:pikapi/basic/config/KeyboardController.dart';
@ -129,6 +130,7 @@ class _SettingsScreenState extends State<SettingsScreen> {
setState(() {}); setState(() {});
}, },
), ),
downloadAndExportPathSetting(),
fontSetting(), fontSetting(),
Divider(), Divider(),
migrate(), migrate(),