diff --git a/.github/workflows/Release.yml b/.github/workflows/Release.yml index d80afae..75ae267 100644 --- a/.github/workflows/Release.yml +++ b/.github/workflows/Release.yml @@ -28,11 +28,18 @@ jobs: with: repository: ${{ github.event.inputs.repo }} ref: 'master' - - name: Checkout submodules - run: git submodule update --init --recursive - uses: actions/setup-go@v2 with: go-version: ${{ env.go_version }} + - name: Cache go modules + uses: actions/cache@v3 + with: + path: | + ~/.cache/go-build + ~/go/pkg/mod + key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-go- - name: Check release run: | cd ci @@ -75,6 +82,39 @@ jobs: with: go-version: ${{ env.go_version }} + - name: Cache go modules (Linux/Android) + if: matrix.config.target == 'android-arm32' || matrix.config.target == 'android-arm64' || matrix.config.target == 'android-x86_64' || matrix.config.target == 'linux' + uses: actions/cache@v3 + with: + path: | + ~/.cache/go-build + ~/go/pkg/mod + key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-go- + + - name: Cache go modules (macOS/ios) + if: matrix.config.target == 'macos' || matrix.config.target == 'ios' + uses: actions/cache@v3 + with: + path: | + ~/Library/Caches/go-build + ~/go/pkg/mod + key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-go- + + - name: Cache go modules (Windows) + if: matrix.config.target == 'windows' + uses: actions/cache@v3 + with: + path: | + ~\AppData\Local\go-build + ~\go\pkg\mod + key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-go- + - id: check_asset name: Check asset run: | @@ -88,6 +128,20 @@ jobs: channel: ${{ env.flutter_channel }} flutter-version: ${{ env.flutter_version }} + - name: Check core + uses: actions/checkout@v3 + with: + repository: 'niuhuan/pikapika-go-core' + token: ${{ secrets.GH_TOKEN }} + path: 'go' + + - name: Cache Flutter dependencies (Linux/Android) + if: steps.check_asset.outputs.skip_build != 'true' && ( matrix.config.target == 'android-arm32' || matrix.config.target == 'android-arm64' || matrix.config.target == 'android-x86_64' || matrix.config.target == 'linux' ) + uses: actions/cache@v3 + with: + path: /opt/hostedtoolcache/flutter + key: ${{ runner.os }}-flutter + - name: Setup java (Android) if: steps.check_asset.outputs.skip_build != 'true' && ( matrix.config.target == 'android-arm32' || matrix.config.target == 'android-arm64' || matrix.config.target == 'android-x86_64' ) uses: actions/setup-java@v3 diff --git a/go/.gitignore b/go/.gitignore deleted file mode 100644 index 596bcc6..0000000 --- a/go/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -build -.last_goflutter_check -.last_go-flutter_check -.last_go-flutter_check diff --git a/go/assets/icon.png b/go/assets/icon.png deleted file mode 100644 index f14bdd1..0000000 Binary files a/go/assets/icon.png and /dev/null differ diff --git a/go/cmd/init.go b/go/cmd/init.go deleted file mode 100644 index 97b27f8..0000000 --- a/go/cmd/init.go +++ /dev/null @@ -1,58 +0,0 @@ -package main - -import ( - "errors" - "os" - "os/exec" - "path" - path2 "path" - "path/filepath" - "pikapika/pikapika/config" - "runtime" - "strings" -) - -// 根据不通系统初始化数据的保存路径 -func init() { - applicationDir, err := os.UserHomeDir() - if err != nil { - panic(err) - } - switch runtime.GOOS { - case "windows": - // applicationDir = path.Join(applicationDir, "AppData", "Roaming") - file, err := exec.LookPath(os.Args[0]) - if err != nil { - panic(err) - } - path, err := filepath.Abs(file) - if err != nil { - panic(err) - } - i := strings.LastIndex(path, "/") - if i < 0 { - i = strings.LastIndex(path, "\\") - } - if i < 0 { - panic(errors.New(" can't find \"/\" or \"\\\"")) - } - applicationDir = path2.Join(path[0:i+1], "data") - case "darwin": - applicationDir = path.Join(applicationDir, "Library", "Application Support", "pikapika") - case "linux": - applicationDir = path.Join(applicationDir, ".pikapika") - default: - panic(errors.New("not supported system")) - } - if _, err = os.Stat(applicationDir); err != nil { - if os.IsNotExist(err) { - err = os.MkdirAll(applicationDir, os.FileMode(0700)) - if err != nil { - panic(err) - } - } else { - panic(err) - } - } - config.InitApplication(applicationDir) -} diff --git a/go/cmd/main.go b/go/cmd/main.go deleted file mode 100644 index 8ac25b5..0000000 --- a/go/cmd/main.go +++ /dev/null @@ -1,70 +0,0 @@ -package main - -import ( - "fmt" - "github.com/go-flutter-desktop/go-flutter" - "github.com/pkg/errors" - "image" - _ "image/gif" - _ "image/jpeg" - _ "image/png" - "os" - "path/filepath" - "pikapika/pikapika/database/properties" - "strconv" - "strings" -) - -// vmArguments may be set by hover at compile-time -var vmArguments string - -func main() { - // DO NOT EDIT, add options in options.go - mainOptions := []flutter.Option{ - flutter.OptionVMArguments(strings.Split(vmArguments, ";")), - flutter.WindowIcon(iconProvider), - } - // 窗口初始化大小的处理 - widthStr, _ := properties.LoadProperty("window_width", "600") - heightStr, _ := properties.LoadProperty("window_height", "900") - width, _ := strconv.Atoi(widthStr) - height, _ := strconv.Atoi(heightStr) - if width <= 0 { - width = 600 - } - if height <= 0 { - height = 900 - } - var runOptions []flutter.Option - runOptions = append(runOptions, flutter.WindowInitialDimensions(width, height)) - fullScreen, _ := properties.LoadBoolProperty("full_screen", false) - if fullScreen { - runOptions = append(runOptions, flutter.WindowMode(flutter.WindowModeMaximize)) - } - // ------ - err := flutter.Run(append(append(runOptions, options...), mainOptions...)...) - if err != nil { - fmt.Println(err) - os.Exit(1) - } -} - -func iconProvider() ([]image.Image, error) { - execPath, err := os.Executable() - if err != nil { - return nil, errors.Wrap(err, "failed to resolve executable path") - } - execPath, err = filepath.EvalSymlinks(execPath) - if err != nil { - return nil, errors.Wrap(err, "failed to eval symlinks for executable path") - } - imgFile, err := os.Open(filepath.Join(filepath.Dir(execPath), "assets", "icon.png")) - if err != nil { - return nil, errors.Wrap(err, "failed to open assets/icon.png") - } - img, _, err := image.Decode(imgFile) - if err != nil { - return nil, errors.Wrap(err, "failed to decode image") - } - return []image.Image{img}, nil -} diff --git a/go/cmd/options.go b/go/cmd/options.go deleted file mode 100644 index 1c605ef..0000000 --- a/go/cmd/options.go +++ /dev/null @@ -1,88 +0,0 @@ -package main - -import ( - "errors" - "github.com/go-flutter-desktop/go-flutter" - "github.com/go-flutter-desktop/go-flutter/plugin" - "github.com/go-flutter-desktop/plugins/url_launcher" - "github.com/go-gl/glfw/v3.3/glfw" - "github.com/miguelpruivo/flutter_file_picker/go" - "pikapika/pikapika" - "pikapika/pikapika/database/properties" - "strconv" - "sync" -) - -var options = []flutter.Option{ - flutter.AddPlugin(&PikapikaPlugin{}), - flutter.AddPlugin(&file_picker.FilePickerPlugin{}), - flutter.AddPlugin(&url_launcher.UrlLauncherPlugin{}), -} - -var eventMutex = sync.Mutex{} -var eventSink *plugin.EventSink - -type EventHandler struct { -} - -func (s *EventHandler) OnListen(arguments interface{}, sink *plugin.EventSink) { - eventMutex.Lock() - defer eventMutex.Unlock() - eventSink = sink -} - -func (s *EventHandler) OnCancel(arguments interface{}) { - eventMutex.Lock() - defer eventMutex.Unlock() - eventSink = nil -} - -const channelName = "method" - -type PikapikaPlugin struct { -} - -func (p *PikapikaPlugin) InitPlugin(messenger plugin.BinaryMessenger) error { - - channel := plugin.NewMethodChannel(messenger, channelName, plugin.StandardMethodCodec{}) - - channel.HandleFunc("flatInvoke", func(arguments interface{}) (interface{}, error) { - if argumentsMap, ok := arguments.(map[interface{}]interface{}); ok { - if method, ok := argumentsMap["method"].(string); ok { - if params, ok := argumentsMap["params"].(string); ok { - return pikapika.FlatInvoke(method, params) - } - } - } - return nil, errors.New("params error") - }) - - exporting := plugin.NewEventChannel(messenger, "flatEvent", plugin.StandardMethodCodec{}) - exporting.Handle(&EventHandler{}) - - pikapika.EventNotify = func(message string) { - eventMutex.Lock() - defer eventMutex.Unlock() - sink := eventSink - if sink != nil { - sink.Success(message) - } - } - - return nil // no error -} - -func (p *PikapikaPlugin) InitPluginGLFW(window *glfw.Window) error { - window.SetSizeCallback(func(w *glfw.Window, width int, height int) { - go func() { - properties.SaveProperty("window_width", strconv.Itoa(width)) - properties.SaveProperty("window_height", strconv.Itoa(height)) - }() - }) - window.SetMaximizeCallback(func(w *glfw.Window, iconified bool) { - go func() { - properties.SaveProperty("full_screen", strconv.FormatBool(iconified)) - }() - }) - return nil -} diff --git a/go/go.mod b/go/go.mod deleted file mode 100644 index e2a7248..0000000 --- a/go/go.mod +++ /dev/null @@ -1,21 +0,0 @@ -module pikapika - -go 1.16 - -require ( - github.com/PuerkitoBio/goquery v1.7.1 - github.com/go-flutter-desktop/go-flutter v0.43.0 - github.com/go-flutter-desktop/plugins/url_launcher v0.1.2 - github.com/go-gl/glfw/v3.3/glfw v0.0.0-20201108214237-06ea97f0c265 - github.com/miguelpruivo/flutter_file_picker/go v0.0.0-20210622152105-9f0a811028a0 - github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect - github.com/niuhuan/pica-go v0.0.0-20220415110443-b5c4a97b0103 - github.com/pkg/errors v0.9.1 - golang.org/x/image v0.0.0-20190802002840-cff245a6509b - golang.org/x/mobile v0.0.0-20220414153400-ce6a79cf6a13 // indirect - golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f // indirect - golang.org/x/sys v0.0.0-20220224120231-95c6836cb0e7 // indirect - golang.org/x/text v0.3.7 // indirect - gorm.io/driver/sqlite v1.1.4 - gorm.io/gorm v1.21.12 -) diff --git a/go/go.sum b/go/go.sum deleted file mode 100644 index 9dbc2de..0000000 --- a/go/go.sum +++ /dev/null @@ -1,127 +0,0 @@ -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/PuerkitoBio/goquery v1.7.1 h1:oE+T06D+1T7LNrn91B4aERsRIeCLJ/oPSa6xB9FPnz4= -github.com/PuerkitoBio/goquery v1.7.1/go.mod h1:XY0pP4kfraEmmV1O7Uf6XyjoslwsneBbgeDjLYuN8xY= -github.com/Xuanwo/go-locale v1.0.0 h1:oqC32Kyiu2XZq+fxtwEg0mWiv9WyDhyHu+sT5cDkgME= -github.com/Xuanwo/go-locale v1.0.0/go.mod h1:kB9tcLfr4Sp+ByIE9SE7vbUkXkGQqel2XH3EHpL0haA= -github.com/andybalholm/cascadia v1.2.0 h1:vuRCkM5Ozh/BfmsaTm26kbjm0mIOM3yS5Ek/F5h18aE= -github.com/andybalholm/cascadia v1.2.0/go.mod h1:YCyR8vOZT9aZ1CHEd8ap0gMVm2aFgxBp0T0eFw1RUQY= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/gen2brain/dlgs v0.0.0-20190708095831-3854608588f7 h1:qA8Mdjwrlv/r/aMqArqO0IMHUiy6ApdW4+8DtKr7PvA= -github.com/gen2brain/dlgs v0.0.0-20190708095831-3854608588f7/go.mod h1:/eFcjDXaU2THSOOqLxOPETIbHETnamk8FA/hMjhg/gU= -github.com/go-flutter-desktop/go-flutter v0.30.0/go.mod h1:NCryd/AqiRbYSd8pMzQldYkgH1tZIFGt2ToUghZcWGA= -github.com/go-flutter-desktop/go-flutter v0.43.0 h1:7tdUbGKmHwdsUnBfC/h7zAO3T67cAkKSCWi9ZDFg25A= -github.com/go-flutter-desktop/go-flutter v0.43.0/go.mod h1:GSCn6XOpB0cnYlK9/BdSwxi99t5YD1XEk0v4agI7SS4= -github.com/go-flutter-desktop/plugins/url_launcher v0.1.2 h1:oFiIJjotMQvF8rfKWVJrf+1/JgTXShEIsibkiXrQnUw= -github.com/go-flutter-desktop/plugins/url_launcher v0.1.2/go.mod h1:GYgRDaLDAJRYvaASQk8HEmI8YJurbZGW5VVDIMxwzBU= -github.com/go-gl/gl v0.0.0-20190320180904-bf2b1f2f34d7 h1:SCYMcCJ89LjRGwEa0tRluNRiMjZHalQZrVrvTbPh+qw= -github.com/go-gl/gl v0.0.0-20190320180904-bf2b1f2f34d7/go.mod h1:482civXOzJJCPzJ4ZOX/pwvXBWSnzD4OKMdH4ClKGbk= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1 h1:QbL/5oDUmRBzO9/Z7Seo6zf912W/a6Sr4Eu0G/3Jho0= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20201108214237-06ea97f0c265 h1:BcbKYUZo/TKPsiSh7LymK3p+TNAJJW3OfGO/21sBbiA= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20201108214237-06ea97f0c265/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gopherjs/gopherjs v0.0.0-20190915194858-d3ddacdb130f h1:TyqzGm2z1h3AGhjOoRYyeLcW4WlW81MDQkWa+rx/000= -github.com/gopherjs/gopherjs v0.0.0-20190915194858-d3ddacdb130f/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= -github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= -github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= -github.com/jinzhu/now v1.1.2 h1:eVKgfIdy9b6zbWBMgFpfDPoAMifwSZagU9HmEU6zgiI= -github.com/jinzhu/now v1.1.2/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= -github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= -github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= -github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= -github.com/mattn/go-sqlite3 v1.14.5 h1:1IdxlwTNazvbKJQSxoJ5/9ECbEeaTTyeU7sEAZ5KKTQ= -github.com/mattn/go-sqlite3 v1.14.5/go.mod h1:WVKg1VTActs4Qso6iwGbiFih2UIHo0ENGwNd0Lj+XmI= -github.com/miguelpruivo/flutter_file_picker/go v0.0.0-20210622152105-9f0a811028a0 h1:hXl9AMW20Php3xWlWZr2Acw50tqeblLgtLfLoRCACmA= -github.com/miguelpruivo/flutter_file_picker/go v0.0.0-20210622152105-9f0a811028a0/go.mod h1:csuW+TFyYKtiUwNvcvhcpyX4quPI7Pvv0SUogdqCW4I= -github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= -github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/niuhuan/pica-go v0.0.0-20220224154849-76bf750f8c4d h1:f3V6V1Y+5j/AvhsIGA6aQ/K2Ez1AeYbuCG9uI4fGC6M= -github.com/niuhuan/pica-go v0.0.0-20220224154849-76bf750f8c4d/go.mod h1:r76zBgH9AYkv0ptyEVoPUIdt33sT0Ts7xgcg742OZtw= -github.com/niuhuan/pica-go v0.0.0-20220415110443-b5c4a97b0103 h1:Qc40/rqbtY0fXAlPEzlfBdQk7wIHTjcTmejmBvdKeco= -github.com/niuhuan/pica-go v0.0.0-20220415110443-b5c4a97b0103/go.mod h1:r76zBgH9AYkv0ptyEVoPUIdt33sT0Ts7xgcg742OZtw= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= -github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4= -golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190802002840-cff245a6509b h1:+qEpEAPhDZ1o0x3tHzZTQDArnOixOzGD9HUJfcg0mb4= -golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20220224134551-8a0a1e50732f h1:G/wQ/Mbs60nXhRM80J4DOzy7FEIZjNprzOneArSgOl0= -golang.org/x/mobile v0.0.0-20220224134551-8a0a1e50732f/go.mod h1:pe2sM7Uk+2Su1y7u/6Z8KJ24D7lepUjFZbhFOrmDfuQ= -golang.org/x/mobile v0.0.0-20220307220422-55113b94f09c h1:9J0m/JcA5YXYbamDhF5I3T7cJnR7V75OCLnMCPb5gl4= -golang.org/x/mobile v0.0.0-20220307220422-55113b94f09c/go.mod h1:pe2sM7Uk+2Su1y7u/6Z8KJ24D7lepUjFZbhFOrmDfuQ= -golang.org/x/mobile v0.0.0-20220325161704-447654d348e3 h1:ZDL7hDvJEQEcHVkoZawKmRUgbqn1pOIzb8EinBh5csU= -golang.org/x/mobile v0.0.0-20220325161704-447654d348e3/go.mod h1:pe2sM7Uk+2Su1y7u/6Z8KJ24D7lepUjFZbhFOrmDfuQ= -golang.org/x/mobile v0.0.0-20220414153400-ce6a79cf6a13 h1:C4eR3yV9J3RkP8WKkcQzpcPyr/foOcUtxW72DvJEOlI= -golang.org/x/mobile v0.0.0-20220414153400-ce6a79cf6a13/go.mod h1:pe2sM7Uk+2Su1y7u/6Z8KJ24D7lepUjFZbhFOrmDfuQ= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= -golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f h1:OfiFi4JbukWwe3lzw+xunroH1mnC1e2Gy5cxNJApiSY= -golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200802091954-4b90ce9b60b3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220224120231-95c6836cb0e7 h1:BXxu8t6QN0G1uff4bzZzSkpsax8+ALqTGUtz08QrV00= -golang.org/x/sys v0.0.0-20220224120231-95c6836cb0e7/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.8-0.20211022200916-316ba0b74098 h1:YuekqPskqwCCPM79F1X5Dhv4ezTCj+Ki1oNwiafxkA0= -golang.org/x/tools v0.1.8-0.20211022200916-316ba0b74098/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gorm.io/driver/sqlite v1.1.4 h1:PDzwYE+sI6De2+mxAneV9Xs11+ZyKV6oxD3wDGkaNvM= -gorm.io/driver/sqlite v1.1.4/go.mod h1:mJCeTFr7+crvS+TRnWc5Z3UvwxUN1BGBLMrf5LA9DYw= -gorm.io/gorm v1.20.7/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw= -gorm.io/gorm v1.21.12 h1:3fQM0Eiz7jcJEhPggHEpoYnsGZqynMzverL77DV40RM= -gorm.io/gorm v1.21.12/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0= diff --git a/go/hover.yaml b/go/hover.yaml deleted file mode 100644 index 81c398e..0000000 --- a/go/hover.yaml +++ /dev/null @@ -1,9 +0,0 @@ -#application-name: "pikapi" # Uncomment to modify this value. -#executable-name: "pikapi" # Uncomment to modify this value. Only lowercase a-z, numbers, underscores and no spaces -#package-name: "pikapi" # Uncomment to modify this value. Only lowercase a-z, numbers and no underscores or spaces -organization-name: "niuhuan" -license: "" # MANDATORY: Fill in your SPDX license name: https://spdx.org/licenses -target: lib/main_desktop.dart -# opengl: "none" # Uncomment this line if you have trouble with your OpenGL driver (https://github.com/go-flutter-desktop/go-flutter/issues/272) -docker: false -engine-version: "" # change to a engine version commit diff --git a/go/mobile/lib/.keep b/go/mobile/lib/.keep deleted file mode 100644 index e69de29..0000000 diff --git a/go/mobile/mobile.go b/go/mobile/mobile.go deleted file mode 100644 index e357c9f..0000000 --- a/go/mobile/mobile.go +++ /dev/null @@ -1,22 +0,0 @@ -package mobile - -import ( - "pikapika/pikapika" - "pikapika/pikapika/config" -) - -func InitApplication(application string) { - config.InitApplication(application) -} - -func FlatInvoke(method string, params string) (string, error) { - return pikapika.FlatInvoke(method, params) -} - -func EventNotify(notify EventNotifyHandler) { - pikapika.EventNotify = notify.OnNotify -} - -type EventNotifyHandler interface { - OnNotify(message string) -} diff --git a/go/packaging/darwin-bundle/{{.applicationName}} {{.version}}.app/Contents/Info.plist.tmpl b/go/packaging/darwin-bundle/{{.applicationName}} {{.version}}.app/Contents/Info.plist.tmpl deleted file mode 100644 index e49ccf2..0000000 --- a/go/packaging/darwin-bundle/{{.applicationName}} {{.version}}.app/Contents/Info.plist.tmpl +++ /dev/null @@ -1,38 +0,0 @@ - - - - - CFBundleDevelopmentRegion - English - CFBundleExecutable - {{.executableName}} - CFBundleGetInfoString - {{.description}} - CFBundleIconFile - icon.icns - NSHighResolutionCapable - - CFBundleIdentifier - {{.organizationName}}.{{.packageName}} - CFBundleInfoDictionaryVersion - 6.0 - CFBundleLongVersionString - {{.version}} - CFBundleName - {{.applicationName}} - CFBundlePackageType - APPL - CFBundleShortVersionString - {{.version}} - CFBundleSignature - {{.organizationName}}.{{.packageName}} - CFBundleVersion - {{.version}} - CSResourcesFileMapped - - NSHumanReadableCopyright - - NSPrincipalClass - NSApplication - - diff --git a/go/packaging/linux-appimage/AppRun.tmpl b/go/packaging/linux-appimage/AppRun.tmpl deleted file mode 100644 index 9272c3d..0000000 --- a/go/packaging/linux-appimage/AppRun.tmpl +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -cd "$(dirname "$0")" -exec ./build/{{.executableName}} diff --git a/go/packaging/linux-appimage/{{.packageName}}.desktop.tmpl b/go/packaging/linux-appimage/{{.packageName}}.desktop.tmpl deleted file mode 100644 index cd17a38..0000000 --- a/go/packaging/linux-appimage/{{.packageName}}.desktop.tmpl +++ /dev/null @@ -1,9 +0,0 @@ -[Desktop Entry] -Version=1.0 -Type=Application -Terminal=false -Categories= -Comment={{.description}} -Name={{.applicationName}} -Icon={{.iconPath}} -Exec={{.executablePath}} diff --git a/go/pikapika/client.go b/go/pikapika/client.go deleted file mode 100644 index 681520e..0000000 --- a/go/pikapika/client.go +++ /dev/null @@ -1,617 +0,0 @@ -// 透传Client的功能并增加缓存 - -package pikapika - -import ( - "encoding/base64" - "encoding/json" - "fmt" - source "github.com/niuhuan/pica-go" - "golang.org/x/net/proxy" - "net" - "net/http" - "net/url" - "pikapika/pikapika/database/comic_center" - "pikapika/pikapika/database/network_cache" - "pikapika/pikapika/database/properties" - "regexp" - "time" -) - -import ( - "context" - "strconv" - "strings" -) - -func InitClient() { - client.Timeout = time.Second * 60 - switchAddress, _ = properties.LoadIntProperty("switchAddress", 1) - imageSwitchAddress, _ = properties.LoadIntProperty("imageSwitchAddress", 1) - proxy, _ := properties.LoadProxy() - changeProxyUrl(proxy) -} - -var client = source.Client{} -var dialer = &net.Dialer{ - Timeout: 30 * time.Second, - KeepAlive: 30 * time.Second, -} - -// SwitchAddress -var switchAddresses = map[int]string{ - 1: "172.67.7.24:443", - 2: "104.20.180.50:443", - 3: "172.67.208.169:443", -} - -var switchAddress = 1 -var switchAddressPattern, _ = regexp.Compile("^.+picacomic\\.com:\\d+$") - -func changeProxyUrl(urlStr string) bool { - if urlStr == "" { - client.Transport = &http.Transport{ - TLSHandshakeTimeout: time.Second * 10, - ExpectContinueTimeout: time.Second * 10, - ResponseHeaderTimeout: time.Second * 10, - IdleConnTimeout: time.Second * 10, - DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) { - if sAddr, ok := switchAddresses[switchAddress]; ok { - addr = sAddr - } - return dialer.DialContext(ctx, network, addr) - }, - } - imageHttpClient.Transport = &http.Transport{ - TLSHandshakeTimeout: time.Second * 10, - ExpectContinueTimeout: time.Second * 10, - ResponseHeaderTimeout: time.Second * 10, - IdleConnTimeout: time.Second * 10, - DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) { - return dialer.DialContext(ctx, network, addr) - }, - } - return false - } - client.Transport = &http.Transport{ - TLSHandshakeTimeout: time.Second * 10, - ExpectContinueTimeout: time.Second * 10, - ResponseHeaderTimeout: time.Second * 10, - IdleConnTimeout: time.Second * 10, - DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) { - proxyUrl, err := url.Parse(urlStr) - if err != nil { - return nil, err - } - proxy, err := proxy.FromURL(proxyUrl, proxy.Direct) - if err != nil { - return nil, err - } - if sAddr, ok := switchAddresses[switchAddress]; ok { - addr = sAddr - } - return proxy.Dial(network, addr) - }, - } - imageHttpClient.Transport = &http.Transport{ - TLSHandshakeTimeout: time.Second * 10, - ExpectContinueTimeout: time.Second * 10, - ResponseHeaderTimeout: time.Second * 10, - IdleConnTimeout: time.Second * 10, - DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) { - proxyUrl, err := url.Parse(urlStr) - if err != nil { - return nil, err - } - proxy, err := proxy.FromURL(proxyUrl, proxy.Direct) - if err != nil { - return nil, err - } - return proxy.Dial(network, addr) - }, - } - return true -} - -func userProfile() (string, error) { - return serialize(client.UserProfile()) -} - -func punchIn() (string, error) { - return serialize(client.PunchIn()) -} - -func categories() (string, error) { - key := "CATEGORIES" - expire := time.Hour * 3 - cache := network_cache.LoadCache(key, expire) - if cache != "" { - return cache, nil - } - categories, err := client.Categories() - if err != nil { - return "", err - } - buff, _ := json.Marshal(&categories) - cache = string(buff) - network_cache.SaveCache(key, cache) - return cache, nil -} - - -func collections(_ string) (string, error) { - key := "COLLECTIONS" - expire := time.Hour * 3 - cache := network_cache.LoadCache(key, expire) - if cache != "" { - return cache, nil - } - collections, err := client.Collections() - if err != nil { - return "", err - } - buff, _ := json.Marshal(&collections) - cache = string(buff) - network_cache.SaveCache(key, cache) - return cache, nil -} - -func comics(params string) (string, error) { - var paramsStruct struct { - Category string `json:"category"` - Tag string `json:"tag"` - CreatorId string `json:"creatorId"` - ChineseTeam string `json:"chineseTeam"` - Sort string `json:"sort"` - Page int `json:"page"` - } - json.Unmarshal([]byte(params), ¶msStruct) - return cacheable( - fmt.Sprintf("COMICS$%s$%s$%s$%s$%s$%d", paramsStruct.Category, paramsStruct.Tag, paramsStruct.CreatorId, paramsStruct.ChineseTeam, paramsStruct.Sort, paramsStruct.Page), - time.Hour*2, - func() (interface{}, error) { - return client.Comics(paramsStruct.Category, paramsStruct.Tag, paramsStruct.CreatorId, paramsStruct.ChineseTeam, paramsStruct.Sort, paramsStruct.Page) - }, - ) -} - -func searchComics(params string) (string, error) { - var paramsStruct struct { - Categories []string `json:"categories"` - Keyword string `json:"keyword"` - Sort string `json:"sort"` - Page int `json:"page"` - } - json.Unmarshal([]byte(params), ¶msStruct) - categories := paramsStruct.Categories - keyword := paramsStruct.Keyword - sort := paramsStruct.Sort - page := paramsStruct.Page - // - var categoriesInKey string - if len(categories) == 0 { - categoriesInKey = "" - } else { - b, _ := json.Marshal(categories) - categoriesInKey = string(b) - } - return cacheable( - fmt.Sprintf("SEARCH$%s$%s$%s$%d", categoriesInKey, keyword, sort, page), - time.Hour*2, - func() (interface{}, error) { - return client.SearchComics(categories, keyword, sort, page) - }, - ) -} - -func randomComics() (string, error) { - return cacheable( - fmt.Sprintf("RANDOM"), - time.Millisecond*1, - func() (interface{}, error) { - return client.RandomComics() - }, - ) -} - -func leaderboard(typeName string) (string, error) { - return cacheable( - fmt.Sprintf("LEADERBOARD$%s", typeName), - time.Second*200, - func() (interface{}, error) { - return client.Leaderboard(typeName) - }, - ) -} - -func comicInfo(comicId string) (string, error) { - var err error - var comic *source.ComicInfo - // cache - key := fmt.Sprintf("COMIC_INFO$%s", comicId) - expire := time.Hour * 24 * 7 - cache := network_cache.LoadCache(key, expire) - if cache != "" { - var co source.ComicInfo - err = json.Unmarshal([]byte(cache), &co) - if err != nil { - panic(err) - return "", err - } - comic = &co - } else { - // get - comic, err = client.ComicInfo(comicId) - if err != nil { - return "", err - } - var buff []byte - buff, err = json.Marshal(comic) - if err != nil { - return "", err - } - cache = string(buff) - network_cache.SaveCache(key, cache) - } - // 标记历史记录 - view := comic_center.ComicView{} - view.ID = comicId - view.CreatedAt = comic.CreatedAt - view.UpdatedAt = comic.UpdatedAt - view.Title = comic.Title - view.Author = comic.Author - view.PagesCount = int32(comic.PagesCount) - view.EpsCount = int32(comic.EpsCount) - view.Finished = comic.Finished - c, _ := json.Marshal(comic.Categories) - view.Categories = string(c) - view.ThumbOriginalName = comic.Thumb.OriginalName - view.ThumbFileServer = comic.Thumb.FileServer - view.ThumbPath = comic.Thumb.Path - view.LikesCount = int32(comic.LikesCount) - view.Description = comic.Description - view.ChineseTeam = comic.ChineseTeam - t, _ := json.Marshal(comic.Tags) - view.Tags = string(t) - view.AllowDownload = comic.AllowDownload - view.ViewsCount = int32(comic.ViewsCount) - view.IsFavourite = comic.IsFavourite - view.IsLiked = comic.IsLiked - view.CommentsCount = int32(comic.CommentsCount) - err = comic_center.ViewComicUpdateInfo(&view) - if err != nil { - return "", err - } - // return - return cache, nil -} - -func ComicInfoCleanCache(comicId string) { - key := fmt.Sprintf("COMIC_INFO$%s", comicId) - network_cache.RemoveCache(key) -} - -func epPage(params string) (string, error) { - var paramsStruct struct { - ComicId string `json:"comicId"` - Page int `json:"page"` - } - json.Unmarshal([]byte(params), ¶msStruct) - comicId := paramsStruct.ComicId - page := paramsStruct.Page - // - return cacheable( - fmt.Sprintf("COMIC_EP_PAGE$%s$%d", comicId, page), - time.Hour*2, - func() (interface{}, error) { - return client.ComicEpPage(comicId, page) - }, - ) -} - -func comicPicturePageWithQuality(params string) (string, error) { - var paramsStruct struct { - ComicId string `json:"comicId"` - EpOrder int `json:"epOrder"` - Page int `json:"page"` - Quality string `json:"quality"` - } - json.Unmarshal([]byte(params), ¶msStruct) - comicId := paramsStruct.ComicId - epOrder := paramsStruct.EpOrder - page := paramsStruct.Page - quality := paramsStruct.Quality - // - return cacheable( - fmt.Sprintf("COMIC_EP_PAGE$%s$%ds$%ds$%s", comicId, epOrder, page, quality), - time.Hour*2, - func() (interface{}, error) { - return client.ComicPicturePageWithQuality(comicId, epOrder, page, quality) - }, - ) -} - -func switchLike(comicId string) (string, error) { - point, err := client.SwitchLike(comicId) - if err != nil { - return "", err - } - // 更新viewLog里面的favour - comic_center.ViewComicUpdateLike(comicId, strings.HasPrefix(*point, "un")) - // 删除缓存 - ComicInfoCleanCache(comicId) - return *point, nil -} - -func switchFavourite(comicId string) (string, error) { - point, err := client.SwitchFavourite(comicId) - if err != nil { - return "", err - } - // 更新viewLog里面的favour - comic_center.ViewComicUpdateFavourite(comicId, strings.HasPrefix(*point, "un")) - // 删除缓存 - ComicInfoCleanCache(comicId) - return *point, nil -} - -func favouriteComics(params string) (string, error) { - var paramsStruct struct { - Sort string `json:"sort"` - Page int `json:"page"` - } - json.Unmarshal([]byte(params), ¶msStruct) - sort := paramsStruct.Sort - page := paramsStruct.Page - // - point, err := client.FavouriteComics(sort, page) - if err != nil { - return "", err - } - str, err := json.Marshal(point) - if err != nil { - return "", err - } - return string(str), nil -} - -func recommendation(comicId string) (string, error) { - return cacheable( - fmt.Sprintf("RECOMMENDATION$%s", comicId), - time.Hour*2, - func() (interface{}, error) { - return client.ComicRecommendation(comicId) - }, - ) -} - -func comments(params string) (string, error) { - var paramsStruct struct { - ComicId string `json:"comicId"` - Page int `json:"page"` - } - json.Unmarshal([]byte(params), ¶msStruct) - comicId := paramsStruct.ComicId - page := paramsStruct.Page - return cacheable( - fmt.Sprintf("COMMENTS$%s$%d", comicId, page), - time.Hour*2, - func() (interface{}, error) { - return client.ComicCommentsPage(comicId, page) - }, - ) -} - -func commentChildren(params string) (string, error) { - var paramsStruct struct { - CommentId string `json:"commentId"` - Page int `json:"page"` - } - json.Unmarshal([]byte(params), ¶msStruct) - commentId := paramsStruct.CommentId - page := paramsStruct.Page - return cacheable( - fmt.Sprintf("COMMENT_CHILDREN$%s$%d", commentId, page), - time.Hour*2, - func() (interface{}, error) { - return client.CommentChildren(commentId, page) - }, - ) -} - -func postComment(params string) (string, error) { - var paramsStruct struct { - ComicId string `json:"comicId"` - Content string `json:"content"` - } - json.Unmarshal([]byte(params), ¶msStruct) - err := client.PostComment(paramsStruct.ComicId, paramsStruct.Content) - if err != nil { - return "", err - } - network_cache.RemoveCaches("MY_COMMENTS$%") - network_cache.RemoveCaches(fmt.Sprintf("COMMENTS$%s$%%", paramsStruct.ComicId)) - return "", nil -} - -func postChildComment(params string) (string, error) { - var paramsStruct struct { - ComicId string `json:"comicId"` - CommentId string `json:"commentId"` - Content string `json:"content"` - } - json.Unmarshal([]byte(params), ¶msStruct) - err := client.PostChildComment(paramsStruct.CommentId, paramsStruct.Content) - if err != nil { - return "", err - } - network_cache.RemoveCaches(fmt.Sprintf("COMMENT_CHILDREN$%s$%%", paramsStruct.CommentId)) - network_cache.RemoveCaches("MY_COMMENTS$%") - network_cache.RemoveCaches(fmt.Sprintf("COMMENTS$%s$%%", paramsStruct.ComicId)) - return "", nil -} - -func postGameChildComment(params string) (string, error) { - var paramsStruct struct { - GameId string `json:"gameId"` - CommentId string `json:"commentId"` - Content string `json:"content"` - } - json.Unmarshal([]byte(params), ¶msStruct) - err := client.PostChildComment(paramsStruct.CommentId, paramsStruct.Content) - if err != nil { - return "", err - } - network_cache.RemoveCaches(fmt.Sprintf("GAME_COMMENT_CHILDREN$%s$%%", paramsStruct.CommentId)) - network_cache.RemoveCaches("MY_COMMENTS$%") - network_cache.RemoveCaches(fmt.Sprintf("GAME_COMMENTS$%s$%%", paramsStruct.GameId)) - return "", nil -} - -func switchLikeComment(params string) (string, error) { - var paramsStruct struct { - CommentId string `json:"commentId"` - ComicId string `json:"comicId"` - } - json.Unmarshal([]byte(params), ¶msStruct) - rsp, err := client.SwitchLikeComment(paramsStruct.CommentId) - if err != nil { - return "", err - } - network_cache.RemoveCaches(fmt.Sprintf("COMMENT_CHILDREN$%s$%%", paramsStruct.CommentId)) - network_cache.RemoveCaches("MY_COMMENTS$%") - network_cache.RemoveCaches(fmt.Sprintf("COMMENTS$%s$%%", paramsStruct.ComicId)) - return *rsp, nil -} - -func myComments(pageStr string) (string, error) { - page, err := strconv.Atoi(pageStr) - if err != nil { - return "", err - } - return cacheable( - fmt.Sprintf("MY_COMMENTS$%d", page), - time.Hour*2, - func() (interface{}, error) { - return client.MyComments(page) - }, - ) -} - -func games(pageStr string) (string, error) { - page, err := strconv.Atoi(pageStr) - if err != nil { - return "", err - } - return cacheable( - fmt.Sprintf("GAMES$%d", page), - time.Hour*2, - func() (interface{}, error) { - return client.GamePage(page) - }, - ) -} - -func game(gameId string) (string, error) { - return cacheable( - fmt.Sprintf("GAME$%s", gameId), - time.Hour*2, - func() (interface{}, error) { - return client.GameInfo(gameId) - }, - ) -} - -func gameComments(params string) (string, error) { - var paramsStruct struct { - GameId string `json:"gameId"` - Page int `json:"page"` - } - json.Unmarshal([]byte(params), ¶msStruct) - gameId := paramsStruct.GameId - page := paramsStruct.Page - return cacheable( - fmt.Sprintf("GAME_COMMENTS$%s$%d", gameId, page), - time.Hour*2, - func() (interface{}, error) { - return client.GameCommentsPage(gameId, page) - }, - ) -} - -func postGameComment(params string) (string, error) { - var paramsStruct struct { - GameId string `json:"gameId"` - Content string `json:"content"` - } - json.Unmarshal([]byte(params), ¶msStruct) - err := client.PostGameComment(paramsStruct.GameId, paramsStruct.Content) - if err != nil { - return "", err - } - network_cache.RemoveCaches("MY_COMMENTS$%") - network_cache.RemoveCaches(fmt.Sprintf("GAME_COMMENTS$%s$%%", paramsStruct.GameId)) - return "", nil -} - -func gameCommentChildren(params string) (string, error) { - var paramsStruct struct { - CommentId string `json:"commentId"` - Page int `json:"page"` - } - json.Unmarshal([]byte(params), ¶msStruct) - commentId := paramsStruct.CommentId - page := paramsStruct.Page - return cacheable( - fmt.Sprintf("GAME_COMMENT_CHILDREN$%s$%d", commentId, page), - time.Hour*2, - func() (interface{}, error) { - return client.GameCommentChildren(commentId, page) - }, - ) -} - -func switchLikeGameComment(params string) (string, error) { - var paramsStruct struct { - CommentId string `json:"commentId"` - GameId string `json:"gameId"` - } - json.Unmarshal([]byte(params), ¶msStruct) - rsp, err := client.SwitchLikeComment(paramsStruct.CommentId) - if err != nil { - return "", err - } - network_cache.RemoveCaches(fmt.Sprintf("GAME_COMMENT_CHILDREN$%s$%%", paramsStruct.CommentId)) - network_cache.RemoveCaches("MY_COMMENTS$%") - network_cache.RemoveCaches(fmt.Sprintf("GAME_COMMENTS$%s$%%", paramsStruct.GameId)) - return *rsp, nil -} - -func updatePassword(params string) (string, error) { - var paramsStruct struct { - OldPassword string `json:"oldPassword"` - NewPassword string `json:"newPassword"` - } - err := json.Unmarshal([]byte(params), ¶msStruct) - if err != nil { - return "", err - } - err = client.UpdatePassword(paramsStruct.OldPassword, paramsStruct.NewPassword) - if err != nil { - return "", err - } - setPassword(paramsStruct.NewPassword) - return "", nil -} - -func updateSlogan(slogan string) (string, error) { - return "", client.UpdateSlogan(slogan) -} - -func updateAvatar(avatarBase64 string) (string, error) { - buff, err := base64.StdEncoding.DecodeString(avatarBase64) - if err != nil { - return "", err - } - return "", client.UpdateAvatar(buff) -} diff --git a/go/pikapika/common.go b/go/pikapika/common.go deleted file mode 100644 index 0ff18b5..0000000 --- a/go/pikapika/common.go +++ /dev/null @@ -1,76 +0,0 @@ -package pikapika - -import ( - "encoding/json" - "pikapika/pikapika/database/comic_center" - "pikapika/pikapika/database/network_cache" - "time" -) - -// EventNotify EventChannel 总线 -var EventNotify func(message string) - -// 所有的EventChannel都是从这里发出, 格式为json, function代表了是什么事件, content是消息的内容 -// 消息传到前端后由前端调度分发 -func onEvent(function string, content string) { - event := EventNotify - if event != nil { - message := map[string]string{ - "function": function, - "content": content, - } - buff, err := json.Marshal(message) - if err == nil { - event(string(buff)) - } else { - print("SEND ERR?") - } - } -} - -// 发送下载的事件 -func downloadComicEventSend(comicDownload *comic_center.ComicDownload) { - buff, err := json.Marshal(comicDownload) - if err == nil { - onEvent("DOWNLOAD", string(buff)) - } else { - print("SEND ERR?") - } -} - -// 发送导出的事件 -func notifyExport(str string) { - onEvent("EXPORT", str) -} - -// 缓存接口 -func cacheable(key string, expire time.Duration, reload func() (interface{}, error)) (string, error) { - // CACHE - cache := network_cache.LoadCache(key, expire) - if cache != "" { - return cache, nil - } - // obj - obj, err := reload() - if err != nil { - return "", err - } - buff, err := json.Marshal(obj) - // push to cache - if err != nil { - return "", err - } - // return - cache = string(buff) - network_cache.SaveCache(key, cache) - return cache, nil -} - -// 将interface序列化成字符串, 方便与flutter通信 -func serialize(point interface{}, err error) (string, error) { - if err != nil { - return "", err - } - buff, err := json.Marshal(point) - return string(buff), nil -} diff --git a/go/pikapika/config/common.go b/go/pikapika/config/common.go deleted file mode 100644 index fbebc90..0000000 --- a/go/pikapika/config/common.go +++ /dev/null @@ -1,29 +0,0 @@ -package config - -import ( - "path" - "pikapika/pikapika" - "pikapika/pikapika/database/comic_center" - "pikapika/pikapika/database/network_cache" - "pikapika/pikapika/database/properties" - "pikapika/pikapika/utils" -) - -// InitApplication 由不同的平台直接调用, 根据提供的路径初始化数据库, 资料文件夹 -func InitApplication(applicationDir string) { - println("初始化 : " + applicationDir) - var databasesDir, remoteDir, downloadDir, tmpDir string - databasesDir = path.Join(applicationDir, "databases") - remoteDir = path.Join(applicationDir, "pictures", "remote") - downloadDir = path.Join(applicationDir, "download") - tmpDir = path.Join(applicationDir, "tmp") - utils.Mkdir(databasesDir) - utils.Mkdir(remoteDir) - utils.Mkdir(downloadDir) - utils.Mkdir(tmpDir) - properties.InitDBConnect(databasesDir) - network_cache.InitDBConnect(databasesDir) - comic_center.InitDBConnect(databasesDir) - pikapika.InitClient() - pikapika.InitPlugin(remoteDir, downloadDir, tmpDir) -} diff --git a/go/pikapika/database/comic_center/center.go b/go/pikapika/database/comic_center/center.go deleted file mode 100644 index 85de0b6..0000000 --- a/go/pikapika/database/comic_center/center.go +++ /dev/null @@ -1,583 +0,0 @@ -package comic_center - -import ( - "gorm.io/driver/sqlite" - "gorm.io/gorm" - "gorm.io/gorm/clause" - "path" - "pikapika/pikapika/utils" - "sync" - "time" -) - -var mutex = sync.Mutex{} -var db *gorm.DB - -func InitDBConnect(databaseDir string) { - mutex.Lock() - defer mutex.Unlock() - var err error - db, err = gorm.Open(sqlite.Open(path.Join(databaseDir, "comic_center.db")), utils.GormConfig) - if err != nil { - panic("failed to connect database") - } - db.AutoMigrate(&ComicView{}) - db.AutoMigrate(&RemoteImage{}) - db.AutoMigrate(&ComicDownload{}) - db.AutoMigrate(&ComicDownloadEp{}) - db.AutoMigrate(&ComicDownloadPicture{}) -} - -func Transaction(t func(tx *gorm.DB) error) error { - mutex.Lock() - defer mutex.Unlock() - return db.Transaction(t) -} - -func NoLockActionViewComicUpdateInfoDB(view *ComicView, db *gorm.DB) error { - view.LastViewTime = time.Now() - return db.Clauses(clause.OnConflict{ - Columns: []clause.Column{{Name: "id"}}, - DoUpdates: clause.AssignmentColumns([]string{ - "created_at", - "updated_at", - "title", - "author", - "pages_count", - "eps_count", - "finished", - "categories", - "thumb_original_name", - "thumb_file_server", - "thumb_path", - "likes_count", - "description", - "chinese_team", - "tags", - "allow_download", - "views_count", - "is_favourite", - "is_liked", - "comments_count", - "last_view_time", - }), - }).Create(view).Error -} - -func ViewComicUpdateInfo(view *ComicView) error { - mutex.Lock() - defer mutex.Unlock() - return NoLockActionViewComicUpdateInfoDB(view, db) -} - -func ViewComic(comicId string) error { - mutex.Lock() - defer mutex.Unlock() - return db.Model(&ComicView{}).Where( - "id = ?", comicId, - ).Update( - "last_view_time", - time.Now(), - ).Error -} - -func ViewComicUpdateFavourite(comicId string, favourite bool) error { - mutex.Lock() - defer mutex.Unlock() - return db.Model(&ComicView{}).Where( - "id = ?", comicId, - ).Update( - "is_favourite", - favourite, - ).Error -} - -func ViewComicUpdateLike(comicId string, like bool) error { - mutex.Lock() - defer mutex.Unlock() - return db.Model(&ComicView{}).Where( - "id = ?", comicId, - ).Update( - "is_like", - like, - ).Error -} - -func ViewEpAndPicture(comicId string, epOrder int, epTitle string, pictureRank int) error { - mutex.Lock() - defer mutex.Unlock() - return db.Model(&ComicView{}).Where("id", comicId).Updates( - map[string]interface{}{ - "last_view_time": time.Now(), - "last_view_ep_order": epOrder, - "last_view_ep_title": epTitle, - "last_view_picture_rank": pictureRank, - }, - ).Error -} - -func LoadViewLog(comicId string) (*ComicView, error) { - mutex.Lock() - defer mutex.Unlock() - var view ComicView - err := db.First(&view, "id = ?", comicId).Error - if err == gorm.ErrRecordNotFound { - return nil, nil - } - if err != nil { - return nil, err - } - return &view, nil -} - -func FindRemoteImage(fileServer string, path string) *RemoteImage { - mutex.Lock() - defer mutex.Unlock() - var remoteImage RemoteImage - err := db.First(&remoteImage, "file_server = ? AND path = ?", fileServer, path).Error - if err != nil { - if err == gorm.ErrRecordNotFound { - return nil - } else { - panic(err) - } - } - return &remoteImage -} - -func SaveRemoteImage(remote *RemoteImage) error { - mutex.Lock() - defer mutex.Unlock() - return db.Clauses(clause.OnConflict{ - Columns: []clause.Column{{Name: "file_server"}, {Name: "path"}}, - DoUpdates: clause.AssignmentColumns([]string{ - "updated_at", - "file_size", - "format", - "width", - "height", - "local_path", - }), - }).Create(remote).Error -} - -func CreateDownload(comic *ComicDownload, epList *[]ComicDownloadEp) error { - mutex.Lock() - defer mutex.Unlock() - comic.SelectedEpCount = int32(len(*epList)) - return db.Transaction(func(tx *gorm.DB) error { - err := tx.Create(comic).Error - if err != nil { - return err - } - for _, ep := range *epList { - err := tx.Create(&ep).Error - if err != nil { - return err - } - } - return nil - }) -} - -func AddDownload(comic *ComicDownload, epList *[]ComicDownloadEp) error { - mutex.Lock() - defer mutex.Unlock() - return db.Transaction(func(tx *gorm.DB) error { - err := tx.Model(comic).Where("id = ?", comic.ID).Updates(map[string]interface{}{ - "created_at": comic.CreatedAt, - "updated_at": comic.UpdatedAt, - "title": comic.Title, - "author": comic.Author, - "pages_count": comic.PagesCount, - "eps_count": comic.EpsCount, - "finished": comic.Finished, - "categories": comic.Categories, - "thumb_original_name": comic.ThumbOriginalName, - "thumb_file_server": comic.ThumbFileServer, - "thumb_path": comic.ThumbPath, - "description": comic.Description, - "chinese_team": comic.ChineseTeam, - "tags": comic.Tags, - "download_finished": false, // restart - }).Error - if err != nil { - return err - } - err = tx.Exec( - "UPDATE comic_downloads SET eps_count = selected_ep_count + ? WHERE id = ?", - len(*epList), comic.ID, - ).Error - if err != nil { - return err - } - for _, ep := range *epList { - err := tx.Create(&ep).Error - if err != nil { - return err - } - } - return nil - }) -} - -func UpdateDownloadLogo(comicId string, fileSize int64, format string, width int32, height int32, localPath string) error { - mutex.Lock() - defer mutex.Unlock() - return db.Model(&ComicDownload{}).Where("id = ?", comicId).Updates(map[string]interface{}{ - "thumb_file_size": fileSize, - "thumb_format": format, - "thumb_width": width, - "thumb_height": height, - "thumb_local_path": localPath, - }).Error -} - -func FindComicDownloadById(comicId string) (*ComicDownload, error) { - mutex.Lock() - defer mutex.Unlock() - var download ComicDownload - err := db.First(&download, "id = ?", comicId).Error - if err != nil { - if err == gorm.ErrRecordNotFound { - return nil, nil - } - return nil, err - } - return &download, nil -} - -func ListDownloadEpByComicId(comicId string) ([]ComicDownloadEp, error) { - mutex.Lock() - defer mutex.Unlock() - var epList []ComicDownloadEp - err := db.Where("comic_id = ?", comicId).Order("ep_order ASC").Find(&epList).Error - return epList, err -} - -func ListDownloadPictureByEpId(epId string) ([]ComicDownloadPicture, error) { - mutex.Lock() - defer mutex.Unlock() - var pictureList []ComicDownloadPicture - err := db.Where("ep_id = ?", epId).Order("rank_in_ep ASC").Find(&pictureList).Error - return pictureList, err -} - -func AllDownloads() (*[]ComicDownload, error) { - mutex.Lock() - defer mutex.Unlock() - var downloads []ComicDownload - err := db.Table("comic_downloads"). - Joins("LEFT JOIN comic_views ON comic_views.id = comic_downloads.id"). - Select("comic_downloads.*"). - Order("comic_views.last_view_time DESC"). - Scan(&downloads).Error - // err := db.Find(&downloads).Error - return &downloads, err -} - -func LoadFirstNeedDownload() (*ComicDownload, error) { - mutex.Lock() - defer mutex.Unlock() - var download ComicDownload - err := db.First(&download, "download_failed = 0 AND pause = 0 AND deleting = 0 AND download_finished = 0").Error - if err != nil { - if err == gorm.ErrRecordNotFound { - return nil, nil - } - return nil, err - } - return &download, nil -} - -func LoadFirstNeedDownloadEp(comicId string) (*ComicDownloadEp, error) { - mutex.Lock() - defer mutex.Unlock() - var ep ComicDownloadEp - err := db.First( - &ep, - " comic_id = ? AND download_failed = 0 AND download_finished = 0 AND fetched_pictures = 1", - comicId, - ).Error - if err != nil { - if err == gorm.ErrRecordNotFound { - return nil, nil - } - return nil, err - } - return &ep, nil -} - -// LoadNeedDownloadPictures 根据EP.ID获取需要下载的图片 -func LoadNeedDownloadPictures(epId string, limit int) (*[]ComicDownloadPicture, error) { - mutex.Lock() - defer mutex.Unlock() - var pictures []ComicDownloadPicture - err := db.Find( - &pictures, - "ep_id = ? AND download_failed = 0 AND download_finished = 0 LIMIT ?", - epId, limit, - ).Error - return &pictures, err -} - -func FetchPictures(comicId string, epId string, list *[]ComicDownloadPicture) error { - mutex.Lock() - defer mutex.Unlock() - return db.Transaction(func(tx *gorm.DB) error { - var rankInEp int32 - for _, picture := range *list { - rankInEp = rankInEp + 1 - picture.RankInEp = rankInEp - err := tx.Create(&picture).Error - if err != nil { - return err - } - } - err := tx.Model(&ComicDownloadEp{}).Where("id = ?", epId).Updates(map[string]interface{}{ - "fetched_pictures": true, - "selected_picture_count": len(*list), - }).Error - if err != nil { - return err - } - return tx.Exec( - "UPDATE comic_downloads SET selected_picture_count = selected_picture_count + ? WHERE id = ?", - len(*list), comicId, - ).Error - }) -} - -func DownloadFailed(comicId string) error { - mutex.Lock() - defer mutex.Unlock() - return db.Model(&ComicDownload{}).Where("id = ?", comicId).Update("download_failed", true).Error -} - -func DownloadSuccess(comicId string) error { - mutex.Lock() - defer mutex.Unlock() - return db.Model(&ComicDownload{}).Where("id = ?", comicId).Updates(map[string]interface{}{ - "download_finished": true, - "download_finished_time": time.Now(), - }).Error -} - -func EpFailed(epId string) error { - mutex.Lock() - defer mutex.Unlock() - return db.Model(&ComicDownloadEp{}).Where("id = ?", epId).Update("download_failed", true).Error -} - -func EpSuccess(comicId string, epId string) error { - mutex.Lock() - defer mutex.Unlock() - return db.Transaction(func(tx *gorm.DB) error { - err := tx.Model(&ComicDownloadEp{}).Where("id = ?", epId).Updates(map[string]interface{}{ - "download_finished": true, - "download_finished_time": time.Now(), - }).Error - if err != nil { - return err - } - return tx.Exec( - "UPDATE comic_downloads SET download_ep_count = download_ep_count + 1 WHERE id = ?", - comicId, - ).Error - }) -} - -func PictureFailed(pictureId string) error { - mutex.Lock() - defer mutex.Unlock() - return db.Model(&ComicDownloadPicture{}).Where("id = ?", pictureId).Update("download_failed", true).Error -} - -func PictureSuccess( - comicId string, epId string, pictureId string, - fileSize int64, format string, width int32, height int32, localPath string, -) error { - mutex.Lock() - defer mutex.Unlock() - return db.Transaction(func(tx *gorm.DB) error { - err := tx.Model(&ComicDownloadPicture{}).Where("id = ?", pictureId).Updates(map[string]interface{}{ - "file_size": fileSize, - "format": format, - "width": width, - "height": height, - "local_path": localPath, - "download_finished": true, - "download_finished_time": time.Now(), - }).Error - if err != nil { - return err - } - err = tx.Exec( - "UPDATE comic_download_eps SET download_picture_count = download_picture_count + 1 WHERE id = ?", - epId, - ).Error - if err != nil { - return err - } - return tx.Exec( - "UPDATE comic_downloads SET download_picture_count = download_picture_count + 1 WHERE id = ?", - comicId, - ).Error - }) -} - -func ResetAll() error { - mutex.Lock() - defer mutex.Unlock() - return db.Transaction(func(tx *gorm.DB) error { - err := tx.Model(&ComicDownload{}).Where("1 = 1"). - Update("download_failed", false).Error - if err != nil { - return err - } - err = tx.Model(&ComicDownloadEp{}).Where("1 = 1"). - Update("download_failed", false).Error - if err != nil { - return err - } - err = tx.Model(&ComicDownloadPicture{}).Where("1 = 1"). - Update("download_failed", false).Error - return err - }) -} - -func ViewLogPage(offset int, limit int) (*[]ComicView, error) { - mutex.Lock() - defer mutex.Unlock() - var list []ComicView - err := db.Offset(offset).Limit(limit).Order("last_view_time DESC").Find(&list).Error - return &list, err -} - -func ClearAllViewLog() { - mutex.Lock() - defer mutex.Unlock() - db.Unscoped().Where("1 = 1").Delete(&ComicView{}) -} - -func DeleteViewLog(id string) { - mutex.Lock() - defer mutex.Unlock() - db.Unscoped().Where("id = ?", id).Delete(&ComicView{}) -} - -func DeletingComic() (*ComicDownload, error) { - mutex.Lock() - defer mutex.Unlock() - var download ComicDownload - err := db.First(&download, "deleting = 1").Error - if err == gorm.ErrRecordNotFound { - return nil, nil - } - return &download, err -} - -func TrueDelete(comicId string) error { - mutex.Lock() - defer mutex.Unlock() - err := db.Transaction(func(tx *gorm.DB) error { - err := tx.Unscoped().Delete(&ComicDownload{}, "id = ?", comicId).Error - if err != nil { - return err - } - err = tx.Unscoped().Delete(&ComicDownloadEp{}, "comic_id = ?", comicId).Error - if err != nil { - return err - } - err = tx.Unscoped().Delete(&ComicDownloadPicture{}, "comic_id = ?", comicId).Error - if err != nil { - return err - } - return nil - }) - if err != nil { - return err - } - return db.Raw("VACUUM").Error -} - -func Deleting(comicId string) error { - mutex.Lock() - defer mutex.Unlock() - return db.Model(&ComicDownload{}).Where("id = ?", comicId).Updates(map[string]interface{}{ - "deleting": true, - }).Error -} - -func RemoveAllRemoteImage() error { - mutex.Lock() - defer mutex.Unlock() - err := db.Unscoped().Delete(&RemoteImage{}, "1 = 1").Error - if err != nil { - return err - } - return db.Raw("VACUUM").Error -} - -func EarliestRemoteImage(earliest time.Time, pageSize int) ([]RemoteImage, error) { - mutex.Lock() - defer mutex.Unlock() - var images []RemoteImage - err := db.Where("strftime('%s',updated_at) < strftime('%s',?)", earliest). - Order("updated_at").Limit(pageSize).Find(&images).Error - return images, err -} - -func DeleteRemoteImages(images []RemoteImage) error { - mutex.Lock() - defer mutex.Unlock() - if len(images) == 0 { - return nil - } - ids := make([]uint, len(images)) - for i := 0; i < len(images); i++ { - ids[i] = images[i].ID - } - return db.Unscoped().Model(&RemoteImage{}).Delete("id in ?", ids).Error -} - -func DownloadInfo(comicId string) (*ComicDownload, error) { - mutex.Lock() - defer mutex.Unlock() - var download ComicDownload - err := db.First(&download, "id = ?", comicId).Error - if err != nil { - if err == gorm.ErrRecordNotFound { - return nil, nil - } - return nil, err - } - return &download, nil -} - -func UpdateTimeCacheImageTime(id uint) { - now := time.Now() - mutex.Lock() - defer mutex.Unlock() - err := db.Model(&RemoteImage{}).Where("id = ?", id).Updates(map[string]interface{}{ - "created_at": now, - "updated_at": now, - }).Error - if err != nil { - panic(err) - } -} - -func ViewedList(ids []string) (viewedList []ComicView) { - err := db.Find(&viewedList, ids).Error - if err != nil { - panic(err) - } - return -} - -func VACUUM() error { - mutex.Lock() - defer mutex.Unlock() - return db.Raw("VACUUM").Error -} diff --git a/go/pikapika/database/comic_center/entities.go b/go/pikapika/database/comic_center/entities.go deleted file mode 100644 index f2f6a6b..0000000 --- a/go/pikapika/database/comic_center/entities.go +++ /dev/null @@ -1,107 +0,0 @@ -package comic_center - -import ( - "gorm.io/gorm" - "time" -) - -type RemoteImage struct { - gorm.Model - FileServer string `gorm:"index:uk_fp,unique" json:"fileServer"` - Path string `gorm:"index:uk_fp,unique" json:"path"` - FileSize int64 `json:"fileSize"` - Format string `json:"format"` - Width int32 `json:"width"` - Height int32 `json:"height"` - LocalPath string `json:"localPath"` -} - -type ComicSimple struct { - ID string `gorm:"primarykey" json:"id"` - CreatedAt time.Time `json:"createdAt"` - UpdatedAt time.Time `json:"updatedAt"` - Title string `json:"title"` - Author string `json:"author"` - PagesCount int32 `json:"pagesCount"` - EpsCount int32 `json:"epsCount"` - Finished bool `json:"finished"` - Categories string `json:"categories"` - ThumbOriginalName string `json:"thumbOriginalName"` - ThumbFileServer string `json:"thumbFileServer"` - ThumbPath string `json:"thumbPath"` -} - -type ComicInfo struct { - ComicSimple - LikesCount int32 `json:"likesCount"` - Description string `json:"description"` - ChineseTeam string `json:"chineseTeam"` - Tags string `json:"tags"` - AllowDownload bool `json:"allowDownload"` - ViewsCount int32 `json:"viewsCount"` - IsFavourite bool `json:"isFavourite"` - IsLiked bool `json:"isLiked"` - CommentsCount int32 `json:"commentsCount"` -} - -type ComicView struct { - ComicInfo - LastViewTime time.Time `json:"lastViewTime"` - LastViewEpOrder int32 `json:"lastViewEpOrder"` - LastViewEpTitle string `json:"lastViewEpTitle"` - LastViewPictureRank int32 `json:"lastViewPictureRank"` -} - -type ComicDownload struct { - ComicSimple - Description string `json:"description"` - ChineseTeam string `json:"chineseTeam"` - Tags string `json:"tags"` - SelectedEpCount int32 `json:"selectedEpCount"` - SelectedPictureCount int32 `json:"selectedPictureCount"` - DownloadEpCount int32 `json:"downloadEpCount"` - DownloadPictureCount int32 `json:"downloadPictureCount"` - DownloadFinished bool `json:"downloadFinished"` - DownloadFinishedTime time.Time `json:"downloadFinishedTime"` - DownloadFailed bool `json:"downloadFailed"` - Deleting bool `json:"deleting"` - ThumbFileSize int64 `json:"thumbFileSize"` - ThumbFormat string `json:"thumbFormat"` - ThumbWidth int32 `json:"thumbWidth"` - ThumbHeight int32 `json:"thumbHeight"` - ThumbLocalPath string `json:"thumbLocalPath"` - Pause bool `json:"pause"` -} - -type ComicDownloadEp struct { - ComicId string `gorm:"index:idx_comic_id" json:"comicId"` - ID string `gorm:"primarykey" json:"id"` - UpdatedAt time.Time `json:"updated_at"` - EpOrder int32 `json:"epOrder"` - Title string `json:"title"` - FetchedPictures bool `json:"fetchedPictures"` - SelectedPictureCount int32 `json:"selectedPictureCount"` - DownloadPictureCount int32 `json:"downloadPictureCount"` - DownloadFinished bool `json:"downloadFinish"` - DownloadFinishedTime time.Time `json:"downloadFinishTime"` - DownloadFailed bool `json:"downloadFailed"` -} - -type ComicDownloadPicture struct { - ID string `gorm:"primarykey" json:"id"` - ComicId string `gorm:"index:idx_comic_id" json:"comicId"` - EpId string `gorm:"index:idx_ep_id" json:"epId"` - EpOrder int32 `gorm:"index:idx_ep_order" json:"epOrder"` - RankInEp int32 `json:"rankInEp"` - DownloadFinished bool `json:"downloadFinish"` - DownloadFinishedTime time.Time `json:"downloadFinishTime"` - DownloadFailed bool `json:"downloadFailed"` - OriginalName string - FileServer string `gorm:"index:idx_fp,priority:1" json:"fileServer"` - Path string `gorm:"index:idx_fp,priority:2" json:"path"` - FileSize int64 `json:"fileSize"` - Format string `json:"format"` - Width int32 `json:"width"` - Height int32 `json:"height"` - LocalPath string `json:"localPath"` -} diff --git a/go/pikapika/database/network_cache/cache.go b/go/pikapika/database/network_cache/cache.go deleted file mode 100644 index 3bf8e31..0000000 --- a/go/pikapika/database/network_cache/cache.go +++ /dev/null @@ -1,99 +0,0 @@ -package network_cache - -import ( - "errors" - "gorm.io/driver/sqlite" - "gorm.io/gorm" - "gorm.io/gorm/clause" - "path" - "pikapika/pikapika/utils" - "sync" - "time" -) - -var mutex = sync.Mutex{} -var db *gorm.DB - -type NetworkCache struct { - gorm.Model - K string `gorm:"index:uk_k,unique"` - V string -} - -func InitDBConnect(databaseDir string) { - mutex.Lock() - defer mutex.Unlock() - var err error - db, err = gorm.Open(sqlite.Open(path.Join(databaseDir, "network_cache.db")), utils.GormConfig) - if err != nil { - panic("failed to connect database") - } - db.AutoMigrate(&NetworkCache{}) -} - -func LoadCache(key string, expire time.Duration) string { - mutex.Lock() - defer mutex.Unlock() - var cache NetworkCache - err := db.First(&cache, "k = ? AND updated_at > ?", key, time.Now().Add(expire*-1)).Error - if err == nil { - return cache.V - } - if gorm.ErrRecordNotFound == err { - return "" - } - panic(errors.New("?")) -} - -func SaveCache(key string, value string) { - mutex.Lock() - defer mutex.Unlock() - db.Clauses(clause.OnConflict{ - Columns: []clause.Column{{Name: "k"}}, - DoUpdates: clause.AssignmentColumns([]string{"created_at", "updated_at", "v"}), - }).Create(&NetworkCache{ - K: key, - V: value, - }) -} - -func RemoveCache(key string) error { - mutex.Lock() - defer mutex.Unlock() - err := db.Unscoped().Delete(&NetworkCache{}, "k = ?", key).Error - if err == gorm.ErrRecordNotFound { - return nil - } - return err -} - -func RemoveCaches(like string) error { - mutex.Lock() - defer mutex.Unlock() - err := db.Unscoped().Delete(&NetworkCache{}, "k LIKE ?", like).Error - if err == gorm.ErrRecordNotFound { - return nil - } - return err -} - -func RemoveAll() error { - mutex.Lock() - defer mutex.Unlock() - err := db.Unscoped().Delete(&NetworkCache{}, "1 = 1").Error - if err != nil { - return err - } - return db.Raw("VACUUM").Error -} - -func RemoveEarliest(earliest time.Time) error { - mutex.Lock() - defer mutex.Unlock() - err := db.Unscoped().Where("strftime('%s',updated_at) < strftime('%s',?)", earliest). - Delete(&NetworkCache{}).Error - if err != nil { - return err - } - return db.Raw("VACUUM").Error -} diff --git a/go/pikapika/database/properties/properties.go b/go/pikapika/database/properties/properties.go deleted file mode 100644 index 573cd01..0000000 --- a/go/pikapika/database/properties/properties.go +++ /dev/null @@ -1,127 +0,0 @@ -package properties - -import ( - "errors" - "fmt" - "gorm.io/driver/sqlite" - "gorm.io/gorm" - "gorm.io/gorm/clause" - "path" - "pikapika/pikapika/utils" - "strconv" - "sync" -) - -var mutex = sync.Mutex{} -var db *gorm.DB - -func InitDBConnect(databaseDir string) { - mutex.Lock() - defer mutex.Unlock() - var err error - db, err = gorm.Open(sqlite.Open(path.Join(databaseDir, "properties.db")), utils.GormConfig) - if err != nil { - panic("failed to connect database") - } - db.AutoMigrate(&Property{}) -} - -type Property struct { - gorm.Model - K string `gorm:"index:uk_k,unique"` - V string -} - -func LoadProperty(name string, defaultValue string) (string, error) { - mutex.Lock() - defer mutex.Unlock() - var property Property - err := db.First(&property, "k", name).Error - if err == nil { - return property.V, nil - } - if gorm.ErrRecordNotFound == err { - return defaultValue, nil - } - panic(errors.New("?")) -} - -func SaveProperty(name string, value string) error { - mutex.Lock() - defer mutex.Unlock() - return db.Clauses(clause.OnConflict{ - Columns: []clause.Column{{Name: "k"}}, - DoUpdates: clause.AssignmentColumns([]string{"created_at", "updated_at", "v"}), - }).Create(&Property{ - K: name, - V: value, - }).Error -} - -func LoadBoolProperty(name string, defaultValue bool) (bool, error) { - stringValue, err := LoadProperty(name, strconv.FormatBool(defaultValue)) - if err != nil { - return false, err - } - return strconv.ParseBool(stringValue) -} - -func SaveBoolProperty(name string, value bool) error { - return SaveProperty(name, strconv.FormatBool(value)) -} - -func LoadIntProperty(name string, defaultValue int) (int, error) { - str, err := LoadProperty(name, fmt.Sprintf("%d", defaultValue)) - if err != nil { - return 0, err - } - return strconv.Atoi(str) -} - -func SaveIntProperty(name string, value int) error { - return SaveProperty(name, strconv.Itoa(value)) -} - -func SaveProxy(value string) error { - return SaveProperty("proxy", value) -} - -func LoadProxy() (string, error) { - return LoadProperty("proxy", "") -} - -func SaveUsername(value string) error { - return SaveProperty("username", value) -} - -func LoadUsername() (string, error) { - return LoadProperty("username", "") -} - -func SavePassword(value string) error { - return SaveProperty("password", value) -} - -func LoadPassword() (string, error) { - return LoadProperty("password", "") -} - -func SaveToken(value string) { - SaveProperty("token", value) -} - -func LoadToken() (string, error) { - return LoadProperty("token", "") -} - -func SaveTokenTime(value int64) { - SaveProperty("token_time", strconv.FormatInt(value, 10)) -} - -func LoadTokenTime() (int64, error) { - str, err := LoadProperty("token_time", "0") - if err != nil { - return 0, err - } - return strconv.ParseInt(str, 10, 64) -} diff --git a/go/pikapika/download.go b/go/pikapika/download.go deleted file mode 100644 index cd3b8ee..0000000 --- a/go/pikapika/download.go +++ /dev/null @@ -1,498 +0,0 @@ -package pikapika - -import ( - "bytes" - "fmt" - "image" - "io/ioutil" - "os" - "path" - "path/filepath" - comic_center2 "pikapika/pikapika/database/comic_center" - utils2 "pikapika/pikapika/utils" - "sync" - "time" -) - -// 使用协程进行后台下载 -// downloadRunning 如果为false则停止下载 -// downloadRestart 为true则取消从新启动下载功能 - -var downloadThreadCount = 1 -var downloadThreadFetch = 100 - -var downloadRunning = false -var downloadRestart = false - -var downloadingComic *comic_center2.ComicDownload -var downloadingEp *comic_center2.ComicDownloadEp - -var dlFlag = true - -// 程序启动后仅调用一次, 启动后台线程 -func downloadBackground() { - println("后台线程启动") - if dlFlag { - dlFlag = false - go downloadBegin() - } -} - -// 下载启动/重新启动会暂停三秒 -func downloadBegin() { - time.Sleep(time.Second * 3) - go downloadLoadComic() -} - -// 下载周期中, 每个下载单元会调用此方法, 如果返回true应该停止当前动作 -func downloadHasStop() bool { - if !downloadRunning { - return true - } - if downloadRestart { - downloadRestart = false - return true - } - return false -} - -// 删除下载任务, 当用户要删除下载的时候, 他会被加入删除队列, 而不是直接被删除, 以减少出错 -func downloadDelete() bool { - c, e := comic_center2.DeletingComic() - if e != nil { - panic(e) - } - if c != nil { - os.RemoveAll(downloadPath(c.ID)) - e = comic_center2.TrueDelete(c.ID) - if e != nil { - panic(e) - } - return true - } - return false -} - -// 加载第一个需要下载的漫画 -func downloadLoadComic() { - // 每次下载完一个漫画, 或者启动的时候, 首先进行删除任务 - for downloadDelete() { - } - // 检测是否需要停止 - if downloadHasStop() { - go downloadBegin() - return - } - // 找到第一个要下载的漫画, 查库有错误就停止, 因为这些错误很少出现, 一旦出现必然是严重的, 例如数据库文件突然被删除 - var err error - downloadingComic, err = comic_center2.LoadFirstNeedDownload() - if err != nil { - panic(err) - } - // 处理找到的下载任务 - go downloadInitComic() -} - -// 初始化找到的下载任务 -func downloadInitComic() { - // 检测是否需要停止 - if downloadHasStop() { - go downloadBegin() - return - } - // 若没有漫画要下载则重新启动 - if downloadingComic == nil { - println("没有找到要下载的漫画") - go downloadBegin() - return - } - // 打印日志, 并向前端的eventChannel发送下载信息 - println("正在下载漫画 " + downloadingComic.Title) - downloadComicEventSend(downloadingComic) - eps, err := comic_center2.ListDownloadEpByComicId(downloadingComic.ID) - if err != nil { - panic(err) - } - // 找到这个漫画需要下载的EP, 并搜索获取图片地址 - for _, ep := range eps { - // FetchedPictures字段标志着这个章节的图片地址有没有获取过, 如果没有获取过就重新获取 - if !ep.FetchedPictures { - println("正在获取章节的图片 " + downloadingComic.Title + " " + ep.Title) - // 搜索图片地址, 如果五次没有请求成功, 就不在请求 - for i := 0; i < 5; i++ { - if client.Token == "" { - continue - } - err := downloadFetchPictures(&ep) - if err != nil { - println(err.Error()) - continue - } - ep.FetchedPictures = true - break - } - // 如果未能获取图片地址, 则直接置为失败 - if !ep.FetchedPictures { - println("章节的图片获取失败 " + downloadingComic.Title + " " + ep.Title) - err = comic_center2.EpFailed(ep.ID) - if err != nil { - panic(err) - } - } else { - println("章节的图片获取成功 " + downloadingComic.Title + " " + ep.Title) - downloadingComic.SelectedPictureCount = downloadingComic.SelectedPictureCount + ep.SelectedPictureCount - downloadComicEventSend(downloadingComic) - } - } - } - // 获取图片地址结束, 去初始化下载的章节 - go downloadLoadEp() -} - -// 获取图片地址 -func downloadFetchPictures(downloadEp *comic_center2.ComicDownloadEp) error { - var list []comic_center2.ComicDownloadPicture - // 官方的图片只能分页获取, 从第1页开始获取, 每页最多40张图片 - page := 1 - for true { - rsp, err := client.ComicPicturePage(downloadingComic.ID, int(downloadEp.EpOrder), page) - if err != nil { - return err - } - for _, doc := range rsp.Docs { - list = append(list, comic_center2.ComicDownloadPicture{ - ID: doc.Id, - ComicId: downloadEp.ComicId, - EpId: downloadEp.ID, - EpOrder: downloadEp.EpOrder, - OriginalName: doc.Media.OriginalName, - FileServer: doc.Media.FileServer, - Path: doc.Media.Path, - }) - } - // 如果不是最后一页, 页码加1, 获取下一页 - if rsp.Page < rsp.Pages { - page++ - continue - } - break - } - // 保存获取到的图片 - err := comic_center2.FetchPictures(downloadEp.ComicId, downloadEp.ID, &list) - if err != nil { - panic(err) - } - downloadEp.SelectedPictureCount = int32(len(list)) - return err -} - -// 初始化下载 -func downloadLoadEp() { - // 周期停止检测 - if downloadHasStop() { - go downloadBegin() - return - } - // 找到第一个需要下载的章节并去处理 (未下载失败的, 且未完成下载的) - var err error - downloadingEp, err = comic_center2.LoadFirstNeedDownloadEp(downloadingComic.ID) - if err != nil { - panic(err) - } - go downloadInitEp() -} - -// 处理需要下载的EP -func downloadInitEp() { - if downloadingEp == nil { - // 所有Ep都下完了, 汇总Download下载情况 - go downloadSummaryDownload() - return - } - // 没有下载完则去下载图片 - println("正在下载章节 " + downloadingEp.Title) - go downloadLoadPicture() -} - -// EP下载汇总 -func downloadSummaryDownload() { - // 暂停检测 - if downloadHasStop() { - go downloadBegin() - return - } - // 加载这个漫画的所有EP - list, err := comic_center2.ListDownloadEpByComicId(downloadingComic.ID) - if err != nil { - panic(err) - } - // 判断所有章节是否下载完成 - over := true - for _, downloadEp := range list { - over = over && downloadEp.DownloadFinished - } - if over { - // 如果所有章节下载完成则下载成功 - downloadAndExportLogo(downloadingComic) - err = comic_center2.DownloadSuccess(downloadingComic.ID) - if err != nil { - panic(err) - } - downloadingComic.DownloadFinished = true - downloadingComic.DownloadFinishedTime = time.Now() - } else { - // 否则下载失败 - err = comic_center2.DownloadFailed(downloadingComic.ID) - if err != nil { - panic(err) - } - downloadingComic.DownloadFailed = true - } - // 向前端发送下载状态 - downloadComicEventSend(downloadingComic) - // 去下载下一个漫画 - go downloadLoadComic() -} - -// 加载需要下载的图片 -func downloadLoadPicture() { - // 暂停检测 - if downloadHasStop() { - go downloadBegin() - return - } - // 获取到这个章节需要下载的图片 - downloadingPictures, err := comic_center2.LoadNeedDownloadPictures(downloadingEp.ID, downloadThreadFetch) - if err != nil { - panic(err) - } - // 如果不需要下载 - if len(*downloadingPictures) == 0 { - // 所有图片都下完了, 汇总EP下载情况 - go downloadSummaryEp() - return - } - // 线程池 - channel := make(chan int, downloadThreadCount) - defer close(channel) - wg := sync.WaitGroup{} - for i := 0; i < len(*downloadingPictures); i++ { - // 暂停检测 - if downloadHasStop() { - wg.Wait() - go downloadBegin() - return - } - channel <- 0 - wg.Add(1) - // 不放入携程, 防止i已经变化 - picPoint := &((*downloadingPictures)[i]) - go func() { - downloadPicture(picPoint) - <-channel - wg.Done() - }() - } - wg.Wait() - // 再次新一轮的下载, 直至 len(*downloadingPictures) == 0 - go downloadLoadPicture() -} - -var downloadEventChannelMutex = sync.Mutex{} - -// 这里不能使用暂停检测, 多次检测会导致问题 -func downloadPicture(downloadingPicture *comic_center2.ComicDownloadPicture) { - // 下载图片, 最多重试5次 - println("正在下载图片 " + fmt.Sprintf("%d", downloadingPicture.RankInEp)) - for i := 0; i < 5; i++ { - err := downloadThePicture(downloadingPicture) - if err != nil { - continue - } - func() { - downloadEventChannelMutex.Lock() - defer downloadEventChannelMutex.Unlock() - // 对下载的漫画临时变量热更新并通知前端 - downloadingPicture.DownloadFinished = true - downloadingEp.DownloadPictureCount = downloadingEp.DownloadPictureCount + 1 - downloadingComic.DownloadPictureCount = downloadingComic.DownloadPictureCount + 1 - downloadComicEventSend(downloadingComic) - }() - break - } - // 没能下载成功, 图片置为下载失败 - if !downloadingPicture.DownloadFinished { - err := comic_center2.PictureFailed(downloadingPicture.ID) - if err != nil { - // ??? panic X channel ??? - // panic(err) - } - } -} - -// 下载指定图片 -func downloadThePicture(picturePoint *comic_center2.ComicDownloadPicture) error { - // 为了不和页面前端浏览的数据冲突, 使用url做hash锁 - lock := utils2.HashLock(fmt.Sprintf("%s$%s", picturePoint.FileServer, picturePoint.Path)) - lock.Lock() - defer lock.Unlock() - // 图片保存位置使用相对路径储存, 使用绝对路径操作 - picturePath := fmt.Sprintf("%s/%d/%d", picturePoint.ComicId, picturePoint.EpOrder, picturePoint.RankInEp) - realPath := downloadPath(picturePath) - // 从缓存获取图片 - buff, img, format, err := decodeFromCache(picturePoint.FileServer, picturePoint.Path) - if err != nil { - // 若缓存不存在, 则从网络获取 - buff, img, format, err = decodeFromUrl(picturePoint.FileServer, picturePoint.Path) - } - if err != nil { - return err - } - // 将图片保存到文件 - dir := filepath.Dir(realPath) - if _, err := os.Stat(dir); os.IsNotExist(err) { - os.Mkdir(dir, utils2.CreateDirMode) - } - err = ioutil.WriteFile(downloadPath(picturePath), buff, utils2.CreateFileMode) - if err != nil { - return err - } - // 下载时同时导出 - downloadAndExport(downloadingComic, downloadingEp, picturePoint, buff, format) - // 存入数据库 - return comic_center2.PictureSuccess( - picturePoint.ComicId, - picturePoint.EpId, - picturePoint.ID, - int64(len(buff)), - format, - int32(img.Bounds().Dx()), - int32(img.Bounds().Dy()), - picturePath, - ) -} - -// EP 下载内容汇总 -func downloadSummaryEp() { - // 暂停检测 - if downloadHasStop() { - go downloadBegin() - return - } - // 找到所有下载的图片 - list, err := comic_center2.ListDownloadPictureByEpId(downloadingEp.ID) - if err != nil { - panic(err) - } - // 全部下载完成置为成功, 否则置为失败 - over := true - for _, downloadPicture := range list { - over = over && downloadPicture.DownloadFinished - } - if over { - err = comic_center2.EpSuccess(downloadingEp.ComicId, downloadingEp.ID) - if err != nil { - panic(err) - } - } else { - err = comic_center2.EpFailed(downloadingEp.ID) - if err != nil { - panic(err) - } - } - // 去加载下一个EP - go downloadLoadEp() -} - -// 边下载边导出(导出路径) -var downloadAndExportPath = "" - -// 边下载边导出(导出图片) -func downloadAndExport( - downloadingComic *comic_center2.ComicDownload, - downloadingEp *comic_center2.ComicDownloadEp, - downloadingPicture *comic_center2.ComicDownloadPicture, - buff []byte, - format string, -) { - if downloadAndExportPath == "" { - return - } - if i, e := os.Stat(downloadAndExportPath); e == nil { - if i.IsDir() { - // 进入漫画目录 - comicDir := path.Join(downloadAndExportPath, utils2.ReasonableFileName(downloadingComic.Title)) - i, e = os.Stat(comicDir) - if e != nil { - if os.IsNotExist(e) { - e = os.Mkdir(comicDir, utils2.CreateDirMode) - } else { - return - } - } - if e != nil { - return - } - // 进入章节目录 - epDir := path.Join(comicDir, utils2.ReasonableFileName(fmt.Sprintf("%02d - ", downloadingEp.EpOrder)+downloadingEp.Title)) - i, e = os.Stat(epDir) - if e != nil { - if os.IsNotExist(e) { - e = os.Mkdir(epDir, utils2.CreateDirMode) - } else { - return - } - } - if e != nil { - return - } - // 写入文件 - filePath := path.Join(epDir, fmt.Sprintf("%03d.%s", downloadingPicture.RankInEp, aliasFormat(format))) - ioutil.WriteFile(filePath, buff, utils2.CreateFileMode) - } - } -} - -// 边下载边导出(导出logo) -func downloadAndExportLogo( - downloadingComic *comic_center2.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, utils2.ReasonableFileName(downloadingComic.Title)) - i, e = os.Stat(comicDir) - if e != nil { - if os.IsNotExist(e) { - e = os.Mkdir(comicDir, utils2.CreateDirMode) - } - } - if e != nil { - return - } - // 写入文件 - filePath := path.Join(comicDir, fmt.Sprintf("%s.%s", "logo", aliasFormat(f))) - ioutil.WriteFile(filePath, buff, utils2.CreateFileMode) - } - } - } - } - } -} - -// jpeg的拓展名 -func aliasFormat(format string) string { - if format == "jpeg" { - return "jpg" - } - return format -} diff --git a/go/pikapika/export.go b/go/pikapika/export.go deleted file mode 100644 index 231d632..0000000 --- a/go/pikapika/export.go +++ /dev/null @@ -1,510 +0,0 @@ -package pikapika - -import ( - "archive/tar" - "archive/zip" - "compress/gzip" - "encoding/json" - "errors" - "fmt" - "io" - "io/ioutil" - "net" - "os" - "path" - "pikapika/pikapika/database/comic_center" - "pikapika/pikapika/utils" - "strings" - "time" -) - -// 通过局域网导出 - -var exportingListener net.Listener -var exportingConn net.Conn - -func exportComicUsingSocket(comicId string) (int, error) { - var err error - exportingListener, err = net.Listen("tcp", ":0") - if err != nil { - return 0, err - } - go handleExportingConn(comicId) - return exportingListener.Addr().(*net.TCPAddr).Port, nil -} - -func handleExportingConn(comicId string) { - defer exportingListener.Close() - var err error - exportingConn, err = exportingListener.Accept() - if err != nil { - notifyExport(fmt.Sprintf("导出失败")) - println(err.Error()) - return - } - defer exportingConn.Close() - gw := gzip.NewWriter(exportingConn) - defer gw.Close() - tw := tar.NewWriter(gw) - defer tw.Close() - err = exportComicDownloadFetch(comicId, func(path string, size int64) (io.Writer, error) { - header := tar.Header{} - header.Name = path - header.Size = size - return tw, tw.WriteHeader(&header) - }) - if err != nil { - notifyExport(fmt.Sprintf("导出失败")) - } else { - notifyExport(fmt.Sprintf("导出成功")) - } -} - -func exportComicUsingSocketExit() error { - if exportingConn != nil { - exportingConn.Close() - } - if exportingListener != nil { - exportingListener.Close() - } - return nil -} - -func exportComicDownload(params string) (filePath string, err error) { - var paramsStruct struct { - ComicId string `json:"comicId"` - Dir string `json:"dir"` - Name string `json:"name"` - } - json.Unmarshal([]byte(params), ¶msStruct) - comicId := paramsStruct.ComicId - dir := paramsStruct.Dir - println(fmt.Sprintf("导出 %s 到 %s", comicId, dir)) - comic, err := comic_center.FindComicDownloadById(comicId) - if err != nil { - return - } - if comic == nil { - err = errors.New("not found") - return - } - if !comic.DownloadFinished { - err = errors.New("not download finish") - return - } - name := strings.TrimSpace(paramsStruct.Name) - if len(name) > 0 { - name = utils.ReasonableFileName(name) + ".zip" - } else { - name = fmt.Sprintf("%s-%s.zip", utils.ReasonableFileName(comic.Title), time.Now().Format("2006_01_02_15_04_05.999")) - } - filePath = path.Join(dir, name) - ex, err := utils.Exists(filePath) - if err != nil { - return "", err - } - if ex { - err = errors.New("exists") - return - } - println(fmt.Sprintf("ZIP : %s", filePath)) - fileStream, err := os.Create(filePath) - if err != nil { - return - } - defer fileStream.Close() - zipWriter := zip.NewWriter(fileStream) - defer zipWriter.Close() - err = exportComicDownloadFetch(comicId, func(path string, size int64) (io.Writer, error) { - header := tar.Header{} - header.Name = path - header.Size = size - return zipWriter.Create(path) - }) - return -} - -func exportComicDownloadFetch(comicId string, onWriteFile func(path string, size int64) (io.Writer, error)) error { - comic, err := comic_center.FindComicDownloadById(comicId) - if err != nil { - return err - } - if comic == nil { - return errors.New("not found") - } - if !comic.DownloadFinished { - return errors.New("not download finish") - } - epList, err := comic_center.ListDownloadEpByComicId(comicId) - if err != nil { - return err - } - jsonComic := JsonComicDownload{} - jsonComic.ComicDownload = *comic - jsonComic.EpList = make([]JsonComicDownloadEp, 0) - for _, ep := range epList { - jsonEp := JsonComicDownloadEp{} - jsonEp.ComicDownloadEp = ep - jsonEp.PictureList = make([]JsonComicDownloadPicture, 0) - pictures, err := comic_center.ListDownloadPictureByEpId(ep.ID) - if err != nil { - return err - } - for _, picture := range pictures { - jsonPicture := JsonComicDownloadPicture{} - jsonPicture.ComicDownloadPicture = picture - jsonPicture.SrcPath = fmt.Sprintf("pictures/%04d_%04d", ep.EpOrder, picture.RankInEp) - notifyExport(fmt.Sprintf("正在导出 EP:%d PIC:%d", ep.EpOrder, picture.RankInEp)) - entryWriter, err := onWriteFile(jsonPicture.SrcPath, jsonPicture.FileSize) - if err != nil { - return err - } - source, err := os.Open(downloadPath(picture.LocalPath)) - if err != nil { - return err - } - _, err = func() (int64, error) { - defer source.Close() - return io.Copy(entryWriter, source) - }() - if err != nil { - return err - } - jsonEp.PictureList = append(jsonEp.PictureList, jsonPicture) - } - jsonComic.EpList = append(jsonComic.EpList, jsonEp) - } - if comic.ThumbLocalPath != "" { - logoBuff, err := ioutil.ReadFile(downloadPath(comic.ThumbLocalPath)) - if err == nil { - entryWriter, err := onWriteFile("logo", int64(len(logoBuff))) - if err != nil { - return err - } - _, err = entryWriter.Write(logoBuff) - if err != nil { - return err - } - } - } - // JS - { - buff, err := json.Marshal(&jsonComic) - if err != nil { - return err - } - logoBuff := append([]byte("data = "), buff...) - if err == nil { - entryWriter, err := onWriteFile("data.js", int64(len(logoBuff))) - if err != nil { - return err - } - _, err = entryWriter.Write(logoBuff) - if err != nil { - return err - } - } - } - // HTML - { - var htmlBuff = []byte(indexHtml) - if err == nil { - entryWriter, err := onWriteFile("index.html", int64(len(htmlBuff))) - if err != nil { - return err - } - _, err = entryWriter.Write(htmlBuff) - if err != nil { - return err - } - } - } - println("OK") - // - return nil -} - -const indexHtml = ` - - - - - - - - - -
- - -
-
-
- - -` - -func exportComicDownloadToJPG(params string) error { - var paramsStruct struct { - ComicId string `json:"comicId"` - Dir string `json:"dir"` - Name string `json:"name"` - } - json.Unmarshal([]byte(params), ¶msStruct) - comicId := paramsStruct.ComicId - dir := paramsStruct.Dir - println(fmt.Sprintf("导出 %s 到 %s", comicId, dir)) - comic, err := comic_center.FindComicDownloadById(comicId) - if err != nil { - return err - } - if comic == nil { - return errors.New("not found") - } - if !comic.DownloadFinished { - return errors.New("not download finish") - } - name := strings.TrimSpace(paramsStruct.Name) - if len(name) > 0 { - name = utils.ReasonableFileName(name) - } else { - name = fmt.Sprintf("%s-%s", utils.ReasonableFileName(comic.Title), time.Now().Format("2006_01_02_15_04_05.999")) - } - dirPath := path.Join(dir, name) - println(fmt.Sprintf("DIR : %s", dirPath)) - ex, err := utils.Exists(dirPath) - if err != nil { - return err - } - if ex { - return errors.New("exists") - } - err = os.Mkdir(dirPath, utils.CreateDirMode) - if err != nil { - return err - } - err = os.Mkdir(path.Join(dirPath, "pictures"), utils.CreateDirMode) - if err != nil { - return err - } - - epList, err := comic_center.ListDownloadEpByComicId(comicId) - if err != nil { - return err - } - jsonComic := JsonComicDownload{} - jsonComic.ComicDownload = *comic - jsonComic.EpList = make([]JsonComicDownloadEp, 0) - for _, ep := range epList { - jsonEp := JsonComicDownloadEp{} - jsonEp.ComicDownloadEp = ep - jsonEp.PictureList = make([]JsonComicDownloadPicture, 0) - pictures, err := comic_center.ListDownloadPictureByEpId(ep.ID) - if err != nil { - return err - } - for _, picture := range pictures { - jsonPicture := JsonComicDownloadPicture{} - jsonPicture.ComicDownloadPicture = picture - jsonPicture.SrcPath = fmt.Sprintf("pictures/%04d_%04d.%s", ep.EpOrder, picture.RankInEp, picture.Format) - notifyExport(fmt.Sprintf("正在导出 EP:%d PIC:%d", ep.EpOrder, picture.RankInEp)) - entryWriter, err := os.Create(path.Join(dirPath, jsonPicture.SrcPath)) - if err != nil { - return err - } - err = func() error { - defer entryWriter.Close() - source, err := os.Open(downloadPath(picture.LocalPath)) - if err != nil { - return err - } - _, err = func() (int64, error) { - defer source.Close() - return io.Copy(entryWriter, source) - }() - return err - }() - jsonEp.PictureList = append(jsonEp.PictureList, jsonPicture) - } - jsonComic.EpList = append(jsonComic.EpList, jsonEp) - } - if comic.ThumbLocalPath != "" { - logoBuff, err := ioutil.ReadFile(downloadPath(comic.ThumbLocalPath)) - if err == nil { - entryWriter, err := os.Create(path.Join(dirPath, "logo")) - if err != nil { - return err - } - defer entryWriter.Close() - if err != nil { - return err - } - _, err = entryWriter.Write(logoBuff) - if err != nil { - return err - } - } - } - // JS - { - buff, err := json.Marshal(&jsonComic) - if err != nil { - return err - } - logoBuff := append([]byte("data = "), buff...) - if err == nil { - - entryWriter, err := os.Create(path.Join(dirPath, "data.js")) - if err != nil { - return err - } - defer entryWriter.Close() - _, err = entryWriter.Write(logoBuff) - if err != nil { - return err - } - } - } - // HTML - { - var htmlBuff = []byte(indexHtml) - if err == nil { - entryWriter, err := os.Create(path.Join(dirPath, "index.html")) - if err != nil { - return err - } - defer entryWriter.Close() - _, err = entryWriter.Write(htmlBuff) - if err != nil { - return err - } - } - } - println("OK") - return nil -} diff --git a/go/pikapika/game.go b/go/pikapika/game.go deleted file mode 100644 index e064d43..0000000 --- a/go/pikapika/game.go +++ /dev/null @@ -1,40 +0,0 @@ -package pikapika - -import ( - "errors" - "fmt" - "github.com/PuerkitoBio/goquery" - "net/http" - "regexp" - "time" -) - -var downloadGameUrlPattern, _ = regexp.Compile("^https://game\\.eroge\\.xyz/hhh\\.php\\?id=\\d+$") - -func downloadGame(url string) (string, error) { - if downloadGameUrlPattern.MatchString(url) { - return cacheable(fmt.Sprintf("GAME_PAGE$%s", url), time.Hour*1000, func() (interface{}, error) { - req, err := http.NewRequest("GET", url, nil) - if err != nil { - return nil, err - } - req.Header.Set("user-agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36") - rsp, err := client.Do(req) - if err != nil { - return nil, err - } - defer rsp.Body.Close() - doc, err := goquery.NewDocumentFromReader(rsp.Body) - if err != nil { - return nil, err - } - find := doc.Find("a.layui-btn") - list := make([]string, find.Size()) - find.Each(func(i int, selection *goquery.Selection) { - list[i] = selection.AttrOr("href", "") - }) - return list, nil - }) - } - return "", errors.New("not support url") -} diff --git a/go/pikapika/image.go b/go/pikapika/image.go deleted file mode 100644 index 6a34b08..0000000 --- a/go/pikapika/image.go +++ /dev/null @@ -1,130 +0,0 @@ -package pikapika - -import ( - "bytes" - "context" - "errors" - _ "golang.org/x/image/webp" - "image" - _ "image/gif" - _ "image/jpeg" - _ "image/png" - "io/ioutil" - "net" - "net/http" - "pikapika/pikapika/database/comic_center" - "sync" - "time" -) - -var mutexCounter = -1 -var busMutex *sync.Mutex -var subMutexes []*sync.Mutex -var imageHttpClient *http.Client - -// imageSwitchAddress -// 图片的分流直接使用 switchAddressPattern 可以正常使用 -// 通过ping发现图片的分流地址与ip一致 -// 这里为了域名与官方一致改为域名分流 -var imageSwitchAddresses = map[int]string{ - 1: "https://storage.wika" + "wika.xyz", - 2: "https://s2.pica" + "comic.com", - 3: "https://s3.pica" + "comic.com", -} - -var imageSwitchAddress int - -func init() { - busMutex = &sync.Mutex{} - for i := 0; i < 5; i++ { - subMutexes = append(subMutexes, &sync.Mutex{}) - } - imageHttpClient = &http.Client{ - Transport: &http.Transport{ - TLSHandshakeTimeout: time.Second * 10, - ExpectContinueTimeout: time.Second * 10, - ResponseHeaderTimeout: time.Second * 10, - IdleConnTimeout: time.Second * 10, - DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) { - return dialer.DialContext(ctx, network, addr) - }, - }, - } -} - -// takeMutex 下载图片获取一个锁, 这样只能同时下载5张图片 -func takeMutex() *sync.Mutex { - busMutex.Lock() - defer busMutex.Unlock() - mutexCounter = (mutexCounter + 1) % len(subMutexes) - return subMutexes[mutexCounter] -} - -func decodeInfoFromBuff(buff []byte) (image.Image, string, error) { - buffer := bytes.NewBuffer(buff) - return image.Decode(buffer) -} - -func decodeFromFile(path string) ([]byte, image.Image, string, error) { - b, e := ioutil.ReadFile(path) - if e != nil { - return nil, nil, "", e - } - i, f, e := decodeInfoFromBuff(b) - if e != nil { - return nil, nil, "", e - } - return b, i, f, e -} - -// 下载图片并decode -func decodeFromUrl(fileServer string, path string) ([]byte, image.Image, string, error) { - useClient := imageHttpClient - if imageSwitchAddress == -1 { - useClient = &client.Client - } - if server, ok := imageSwitchAddresses[imageSwitchAddress]; ok { - fileServer = server - } - m := takeMutex() - m.Lock() - defer m.Unlock() - request, err := http.NewRequest("GET", fileServer+"/static/"+path, nil) - if err != nil { - return nil, nil, "", err - } - response, err := useClient.Do(request) - if err != nil { - return nil, nil, "", err - } - defer response.Body.Close() - if response.StatusCode != 200 { - return nil, nil, "", errors.New("code is not 200") - } - buff, err := ioutil.ReadAll(response.Body) - if err != nil { - return nil, nil, "", err - } - img, format, err := decodeInfoFromBuff(buff) - if err != nil { - return nil, nil, "", err - } - return buff, img, format, err -} - -// decodeFromCache 仅下载使用 -func decodeFromCache(fileServer string, path string) ([]byte, image.Image, string, error) { - cache := comic_center.FindRemoteImage(fileServer, path) - if cache != nil { - buff, err := ioutil.ReadFile(remotePath(cache.LocalPath)) - if err != nil { - return nil, nil, "", err - } - img, format, err := decodeInfoFromBuff(buff) - if err != nil { - return nil, nil, "", err - } - return buff, img, format, err - } - return nil, nil, "", errors.New("not found") -} diff --git a/go/pikapika/import.go b/go/pikapika/import.go deleted file mode 100644 index d6d35a2..0000000 --- a/go/pikapika/import.go +++ /dev/null @@ -1,196 +0,0 @@ -package pikapika - -import ( - "archive/tar" - "archive/zip" - "compress/gzip" - "encoding/json" - "gorm.io/gorm" - "io" - "io/ioutil" - "net" - "os" - path2 "path" - "pikapika/pikapika/database/comic_center" - "pikapika/pikapika/utils" - "strconv" - "strings" -) - -func importComicDownloadUsingSocket(addr string) error { - // - conn, err := net.Dial("tcp", addr) - if err != nil { - return err - } - defer conn.Close() - gr, err := gzip.NewReader(conn) - if err != nil { - return err - } - tr := tar.NewReader(gr) - // - zipPath := path2.Join(tmpDir, "tmp.zip") - closed := false - zipFile, err := os.Create(zipPath) - if err != nil { - return err - } - defer func() { - if !closed { - zipFile.Close() - } - os.Remove(zipPath) - }() - zipWriter := zip.NewWriter(zipFile) - defer func() { - if !closed { - zipWriter.Close() - } - }() - // - for { - header, err := tr.Next() - if err == io.EOF { - break - } - if err != nil { - return err - } - if header.Typeflag != tar.TypeReg { - continue - } - writer, err := zipWriter.Create(header.Name) - if err != nil { - return err - } - _, err = io.Copy(writer, tr) - if err != nil { - return err - } - } - err = zipWriter.Close() - zipFile.Close() - closed = true - return importComicDownload(zipPath) -} - -func importComicDownload(zipPath string) error { - zip, err := zip.OpenReader(zipPath) - if err != nil { - return err - } - defer zip.Close() - dataJs, err := zip.Open("data.js") - if err != nil { - return err - } - defer dataJs.Close() - dataBuff, err := ioutil.ReadAll(dataJs) - if err != nil { - return err - } - data := strings.TrimLeft(string(dataBuff), "data = ") - var jsonComicDownload JsonComicDownload - err = json.Unmarshal([]byte(data), &jsonComicDownload) - if err != nil { - return err - } - return comic_center.Transaction(func(tx *gorm.DB) error { - // 删除 - err := tx.Unscoped().Delete(&comic_center.ComicDownload{}, "id = ?", jsonComicDownload.ID).Error - if err != nil { - return err - } - err = tx.Unscoped().Delete(&comic_center.ComicDownloadEp{}, "comic_id = ?", jsonComicDownload.ID).Error - if err != nil { - return err - } - err = tx.Unscoped().Delete(&comic_center.ComicDownloadPicture{}, "comic_id = ?", jsonComicDownload.ID).Error - if err != nil { - return err - } - // 插入 - err = tx.Save(&jsonComicDownload.ComicDownload).Error - if err != nil { - return err - } - for _, ep := range jsonComicDownload.EpList { - err = tx.Save(&ep.ComicDownloadEp).Error - if err != nil { - return err - } - for _, picture := range ep.PictureList { - notifyExport("事务 : " + picture.LocalPath) - err = tx.Save(&picture.ComicDownloadPicture).Error - if err != nil { - return err - } - } - } - // VIEW日志 - view := comic_center.ComicView{} - view.ID = jsonComicDownload.ID - view.CreatedAt = jsonComicDownload.CreatedAt - view.UpdatedAt = jsonComicDownload.UpdatedAt - view.Title = jsonComicDownload.Title - view.Author = jsonComicDownload.Author - view.PagesCount = jsonComicDownload.PagesCount - view.EpsCount = jsonComicDownload.EpsCount - view.Finished = jsonComicDownload.Finished - c, _ := json.Marshal(jsonComicDownload.Categories) - view.Categories = string(c) - view.ThumbOriginalName = jsonComicDownload.ThumbOriginalName - view.ThumbFileServer = jsonComicDownload.ThumbFileServer - view.ThumbPath = jsonComicDownload.ThumbPath - view.LikesCount = 0 - view.Description = jsonComicDownload.Description - view.ChineseTeam = jsonComicDownload.ChineseTeam - t, _ := json.Marshal(jsonComicDownload.Tags) - view.Tags = string(t) - view.AllowDownload = true - view.ViewsCount = 0 - view.IsFavourite = false - view.IsLiked = false - view.CommentsCount = 0 - err = comic_center.NoLockActionViewComicUpdateInfoDB(&view, tx) - if err != nil { - return err - } - // 覆盖文件 - comicDirPath := downloadPath(jsonComicDownload.ID) - utils.Mkdir(comicDirPath) - logoReader, err := zip.Open("logo") - if err == nil { - defer logoReader.Close() - logoBuff, err := ioutil.ReadAll(logoReader) - if err != nil { - return err - } - ioutil.WriteFile(path2.Join(comicDirPath, "logo"), logoBuff, utils.CreateFileMode) - } - for _, ep := range jsonComicDownload.EpList { - utils.Mkdir(path2.Join(comicDirPath, strconv.Itoa(int(ep.EpOrder)))) - for _, picture := range ep.PictureList { - notifyExport("写入 : " + picture.LocalPath) - zipEntry, err := zip.Open(picture.SrcPath) - if err != nil { - return err - } - err = func() error { - defer zipEntry.Close() - entryBuff, err := ioutil.ReadAll(zipEntry) - if err != nil { - return err - } - return ioutil.WriteFile(downloadPath(picture.LocalPath), entryBuff, utils.CreateFileMode) - }() - if err != nil { - return err - } - } - } - // 结束 - return nil - }) -} diff --git a/go/pikapika/modles.go b/go/pikapika/modles.go deleted file mode 100644 index 8370be4..0000000 --- a/go/pikapika/modles.go +++ /dev/null @@ -1,33 +0,0 @@ -package pikapika - -import ( - "pikapika/pikapika/database/comic_center" -) - -type DisplayImageData struct { - FileSize int64 `json:"fileSize"` - Format string `json:"format"` - Width int32 `json:"width"` - Height int32 `json:"height"` - FinalPath string `json:"finalPath"` -} - -type ComicDownloadPictureWithFinalPath struct { - comic_center.ComicDownloadPicture - FinalPath string `json:"finalPath"` -} - -type JsonComicDownload struct { - comic_center.ComicDownload - EpList []JsonComicDownloadEp `json:"epList"` -} - -type JsonComicDownloadEp struct { - comic_center.ComicDownloadEp - PictureList []JsonComicDownloadPicture `json:"pictureList"` -} - -type JsonComicDownloadPicture struct { - comic_center.ComicDownloadPicture - SrcPath string `json:"srcPath"` -} diff --git a/go/pikapika/network.go b/go/pikapika/network.go deleted file mode 100644 index 892806c..0000000 --- a/go/pikapika/network.go +++ /dev/null @@ -1,24 +0,0 @@ -package pikapika - -import ( - "net" - "strings" -) - -// 获取IP的集合 -func clientIpSet() (string, error) { - address, err := net.InterfaceAddrs() - if err != nil { - return "", err - } - ipSet := make([]string, 0) - for _, address := range address { - // 检查ip地址判断是否回环地址 - if ipNet, ok := address.(*net.IPNet); ok && !ipNet.IP.IsLoopback() { - if ipNet.IP.To4() != nil { - ipSet = append(ipSet, ipNet.IP.To4().String()) - } - } - } - return strings.Join(ipSet, ","), nil -} diff --git a/go/pikapika/pikapika.go b/go/pikapika/pikapika.go deleted file mode 100644 index b1436de..0000000 --- a/go/pikapika/pikapika.go +++ /dev/null @@ -1,755 +0,0 @@ -package pikapika - -import ( - "crypto/md5" - "encoding/json" - "errors" - "fmt" - source "github.com/niuhuan/pica-go" - "image/jpeg" - "io/ioutil" - "net/http" - "os" - path2 "path" - "pikapika/pikapika/database/comic_center" - "pikapika/pikapika/database/network_cache" - "pikapika/pikapika/database/properties" - "pikapika/pikapika/utils" - "strconv" - "time" -) - -var ( - remoteDir string - downloadDir string - tmpDir string -) - -var initFlag bool - -func InitPlugin(_remoteDir string, _downloadDir string, _tmpDir string) { - if initFlag { - return - } - initFlag = true - remoteDir = _remoteDir - downloadDir = _downloadDir - tmpDir = _tmpDir - comic_center.ResetAll() - downloadAndExportPath = loadDownloadAndExportPath() - downloadThreadCount = loadDownloadThreadCount() - go downloadBackground() - downloadRunning = true -} - -func remotePath(path string) string { - return path2.Join(remoteDir, path) -} - -func downloadPath(path string) string { - return path2.Join(downloadDir, path) -} - -func saveProperty(params string) error { - var paramsStruct struct { - Name string `json:"name"` - Value string `json:"value"` - } - json.Unmarshal([]byte(params), ¶msStruct) - return properties.SaveProperty(paramsStruct.Name, paramsStruct.Value) -} - -func loadProperty(params string) (string, error) { - var paramsStruct struct { - Name string `json:"name"` - DefaultValue string `json:"defaultValue"` - } - json.Unmarshal([]byte(params), ¶msStruct) - 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 saveDownloadThreadCount(value int) { - strValue := strconv.Itoa(value) - properties.SaveProperty("downloadThreadCount", strValue) - downloadThreadCount = value - downloadRestart = true -} - -func loadDownloadThreadCount() int { - count, err := properties.LoadProperty("downloadThreadCount", "2") - if err != nil { - return 1 - } - i, err := strconv.Atoi(count) - if err != nil { - return 1 - } - return i -} - -func setSwitchAddress(nSwitchAddress string) error { - num, err := strconv.Atoi(nSwitchAddress) - if err != nil { - return err - } - err = properties.SaveIntProperty("switchAddress", num) - if err != nil { - return err - } - switchAddress = num - return nil -} - -func getSwitchAddress() (string, error) { - return strconv.Itoa(switchAddress), nil -} - -func setImageSwitchAddress(nSwitchAddress string) error { - num, err := strconv.Atoi(nSwitchAddress) - if err != nil { - return err - } - err = properties.SaveIntProperty("imageSwitchAddress", num) - if err != nil { - return err - } - switchAddress = num - return nil -} - -func getImageSwitchAddress() (string, error) { - return strconv.Itoa(imageSwitchAddress), nil -} - -func setProxy(value string) error { - err := properties.SaveProxy(value) - if err != nil { - return err - } - changeProxyUrl(value) - return nil -} - -func getProxy() (string, error) { - return properties.LoadProxy() -} - -func setUsername(value string) error { - return properties.SaveUsername(value) -} - -func getUsername() (string, error) { - return properties.LoadUsername() -} - -func setPassword(value string) error { - return properties.SavePassword(value) -} - -func getPassword() (string, error) { - return properties.LoadPassword() -} - -func preLogin() (string, error) { - token, _ := properties.LoadToken() - tokenTime, _ := properties.LoadTokenTime() - if token != "" && tokenTime > 0 { - if utils.Timestamp()-(1000*60*60*24) < tokenTime { - client.Token = token - return "true", nil - } - } - err := login() - if err == nil { - return "true", nil - } - return "false", nil -} - -func login() error { - username, _ := properties.LoadUsername() - password, _ := properties.LoadPassword() - if password == "" || username == "" { - return errors.New(" 需要设定用户名和密码 ") - } - err := client.Login(username, password) - if err != nil { - return err - } - properties.SaveToken(client.Token) - properties.SaveTokenTime(utils.Timestamp()) - return nil -} - -func register(params string) error { - var dto source.RegisterDto - err := json.Unmarshal([]byte(params), &dto) - if err != nil { - return err - } - return client.Register(dto) -} - -func clearToken() error { - properties.SaveTokenTime(0) - properties.SaveToken("") - return nil -} - -func remoteImageData(params string) (string, error) { - var paramsStruct struct { - FileServer string `json:"fileServer"` - Path string `json:"path"` - } - json.Unmarshal([]byte(params), ¶msStruct) - fileServer := paramsStruct.FileServer - path := paramsStruct.Path - lock := utils.HashLock(fmt.Sprintf("%s$%s", fileServer, path)) - lock.Lock() - defer lock.Unlock() - cache := comic_center.FindRemoteImage(fileServer, path) - if cache == nil { - remote, err := decodeAndSaveImage(fileServer, path) - if err != nil { - return "", err - } - cache = remote - } else { - go comic_center.UpdateTimeCacheImageTime(cache.ID) - } - display := DisplayImageData{ - FileSize: cache.FileSize, - Format: cache.Format, - Width: cache.Width, - Height: cache.Height, - FinalPath: remotePath(cache.LocalPath), - } - return serialize(&display, nil) -} - -func remoteImagePreload(params string) error { - var paramsStruct struct { - FileServer string `json:"fileServer"` - Path string `json:"path"` - } - json.Unmarshal([]byte(params), ¶msStruct) - fileServer := paramsStruct.FileServer - path := paramsStruct.Path - lock := utils.HashLock(fmt.Sprintf("%s$%s", fileServer, path)) - lock.Lock() - defer lock.Unlock() - cache := comic_center.FindRemoteImage(fileServer, path) - var err error - if cache == nil { - _, err = decodeAndSaveImage(fileServer, path) - } - return err -} - -func decodeAndSaveImage(fileServer string, path string) (*comic_center.RemoteImage, error) { - buff, img, format, err := decodeFromUrl(fileServer, path) - if err != nil { - println(fmt.Sprintf("decode error : %s/static/%s %s", fileServer, path, err.Error())) - return nil, err - } - local := - fmt.Sprintf("%x", - md5.Sum([]byte(fmt.Sprintf("%s$%s", fileServer, path))), - ) - real := remotePath(local) - err = ioutil.WriteFile( - real, - buff, os.FileMode(0600), - ) - if err != nil { - return nil, err - } - remote := comic_center.RemoteImage{ - FileServer: fileServer, - Path: path, - FileSize: int64(len(buff)), - Format: format, - Width: int32(img.Bounds().Dx()), - Height: int32(img.Bounds().Dy()), - LocalPath: local, - } - err = comic_center.SaveRemoteImage(&remote) - return &remote, err -} - -func downloadImagePath(path string) (string, error) { - return downloadPath(path), nil -} - -func createDownload(params string) error { - var paramsStruct struct { - Comic comic_center.ComicDownload `json:"comic"` - EpList []comic_center.ComicDownloadEp `json:"epList"` - } - json.Unmarshal([]byte(params), ¶msStruct) - comic := paramsStruct.Comic - epList := paramsStruct.EpList - if comic.Title == "" || len(epList) == 0 { - return errors.New("params error") - } - err := comic_center.CreateDownload(&comic, &epList) - if err != nil { - return err - } - // 创建文件夹 - utils.Mkdir(downloadPath(comic.ID)) - // 复制图标 - downloadComicLogo(&comic) - return nil -} - -func downloadComicLogo(comic *comic_center.ComicDownload) { - lock := utils.HashLock(fmt.Sprintf("%s$%s", comic.ThumbFileServer, comic.ThumbPath)) - lock.Lock() - defer lock.Unlock() - buff, image, format, err := decodeFromCache(comic.ThumbFileServer, comic.ThumbPath) - if err != nil { - buff, image, format, err = decodeFromUrl(comic.ThumbFileServer, comic.ThumbPath) - } - if err == nil { - comicLogoPath := path2.Join(comic.ID, "logo") - ioutil.WriteFile(downloadPath(comicLogoPath), buff, utils.CreateFileMode) - comic_center.UpdateDownloadLogo( - comic.ID, - int64(len(buff)), - format, - int32(image.Bounds().Dx()), - int32(image.Bounds().Dy()), - comicLogoPath, - ) - comic.ThumbFileSize = int64(len(buff)) - comic.ThumbFormat = format - comic.ThumbWidth = int32(image.Bounds().Dx()) - comic.ThumbHeight = int32(image.Bounds().Dy()) - comic.ThumbLocalPath = comicLogoPath - } - if err != nil { - println(err.Error()) - } -} - -func addDownload(params string) error { - var paramsStruct struct { - Comic comic_center.ComicDownload `json:"comic"` - EpList []comic_center.ComicDownloadEp `json:"epList"` - } - json.Unmarshal([]byte(params), ¶msStruct) - comic := paramsStruct.Comic - epList := paramsStruct.EpList - if comic.Title == "" || len(epList) == 0 { - return errors.New("params error") - } - return comic_center.AddDownload(&comic, &epList) -} - -func deleteDownloadComic(comicId string) error { - err := comic_center.Deleting(comicId) - if err != nil { - return err - } - downloadRestart = true - return nil -} - -func loadDownloadComic(comicId string) (string, error) { - download, err := comic_center.FindComicDownloadById(comicId) - if err != nil { - return "", err - } - if download == nil { - return "", nil - } - comic_center.ViewComic(comicId) // VIEW - return serialize(download, err) -} - -func allDownloads() (string, error) { - return serialize(comic_center.AllDownloads()) -} - -func downloadEpList(comicId string) (string, error) { - return serialize(comic_center.ListDownloadEpByComicId(comicId)) -} - -func viewLogPage(params string) (string, error) { - var paramsStruct struct { - Offset int `json:"offset"` - Limit int `json:"limit"` - } - json.Unmarshal([]byte(params), ¶msStruct) - return serialize(comic_center.ViewLogPage(paramsStruct.Offset, paramsStruct.Limit)) -} - -func downloadPicturesByEpId(epId string) (string, error) { - return serialize(comic_center.ListDownloadPictureByEpId(epId)) -} - -func getDownloadRunning() bool { - return downloadRunning -} - -func setDownloadRunning(status bool) { - downloadRunning = status -} - -func cleanNetworkCache() error { - err := network_cache.RemoveAll() - if err != nil { - return err - } - notifyExport("清理结束") - return nil -} - -func cleanImageCache() error { - notifyExport("清理图片缓存") - err := comic_center.RemoveAllRemoteImage() - if err != nil { - return err - } - notifyExport("清理图片文件") - os.RemoveAll(remoteDir) - utils.Mkdir(remoteDir) - notifyExport("清理结束") - return nil -} - -func clean() error { - var err error - notifyExport("清理网络缓存") - err = network_cache.RemoveAll() - if err != nil { - return err - } - notifyExport("清理图片缓存") - err = comic_center.RemoveAllRemoteImage() - if err != nil { - return err - } - notifyExport("清理图片文件") - os.RemoveAll(remoteDir) - utils.Mkdir(remoteDir) - notifyExport("清理结束") - return nil -} - -func autoClean(expire int64) error { - now := time.Now() - earliest := now.Add(time.Second * time.Duration(0-expire)) - err := network_cache.RemoveEarliest(earliest) - if err != nil { - return err - } - pageSize := 10 - for true { - images, err := comic_center.EarliestRemoteImage(earliest, pageSize) - if err != nil { - return err - } - if len(images) == 0 { - return comic_center.VACUUM() - } - // delete data & remove pic - err = comic_center.DeleteRemoteImages(images) - if err != nil { - return err - } - for i := 0; i < len(images); i++ { - err = os.Remove(remotePath(images[i].LocalPath)) - if err != nil { - return err - } - } - } - return nil -} - -func storeViewEp(params string) error { - var paramsStruct struct { - ComicId string `json:"comicId"` - EpOrder int `json:"epOrder"` - EpTitle string `json:"epTitle"` - PictureRank int `json:"pictureRank"` - } - json.Unmarshal([]byte(params), ¶msStruct) - return comic_center.ViewEpAndPicture( - paramsStruct.ComicId, - paramsStruct.EpOrder, - paramsStruct.EpTitle, - paramsStruct.PictureRank, - ) -} - -func loadView(comicId string) (string, error) { - view, err := comic_center.LoadViewLog(comicId) - if err != nil { - return "", nil - } - if view != nil { - b, err := json.Marshal(view) - if err != nil { - return "", err - } - return string(b), nil - } - return "", nil -} - -func convertImageToJPEG100(params string) error { - var paramsStruct struct { - Path string `json:"path"` - Dir string `json:"dir"` - } - err := json.Unmarshal([]byte(params), ¶msStruct) - if err != nil { - return err - } - _, i, _, err := decodeFromFile(paramsStruct.Path) - if err != nil { - return err - } - to := path2.Join(paramsStruct.Dir, path2.Base(paramsStruct.Path)+".jpg") - stream, err := os.Create(to) - if err != nil { - return err - } - defer stream.Close() - return jpeg.Encode(stream, i, &jpeg.Options{Quality: 100}) -} - -// 检查更新只能使用defaultHttpClient, 而不能使用pika的client, 否则会 "tls handshake failure" -func defaultHttpClientGet(url string) (string, error) { - rsp, err := http.DefaultClient.Get(url) - if err != nil { - return "", err - } - defer rsp.Body.Close() - buff, err := ioutil.ReadAll(rsp.Body) - if err != nil { - return "", err - } - return string(buff), nil -} - -func loadViewedList(params string) (string, error) { - var ids []string - err := json.Unmarshal([]byte(params), &ids) - if err != nil { - return "", err - } - viewedList := comic_center.ViewedList(ids) - ids = make([]string, len(viewedList)) - for i, view := range viewedList { - ids[i] = view.ID - } - return serialize(ids, nil) -} - -func FlatInvoke(method string, params string) (string, error) { - switch method { - case "saveProperty": - return "", saveProperty(params) - case "loadProperty": - return loadProperty(params) - case "setSwitchAddress": - return "", setSwitchAddress(params) - case "getSwitchAddress": - return getSwitchAddress() - case "setImageSwitchAddress": - return "", setImageSwitchAddress(params) - case "getImageSwitchAddress": - return getImageSwitchAddress() - case "setProxy": - return "", setProxy(params) - case "getProxy": - return getProxy() - case "setUsername": - return "", setUsername(params) - case "setPassword": - return "", setPassword(params) - case "getUsername": - return getUsername() - case "getPassword": - return getPassword() - case "preLogin": - return preLogin() - case "login": - return "", login() - case "register": - return "", register(params) - case "clearToken": - return "", clearToken() - case "userProfile": - return userProfile() - case "punchIn": - return punchIn() - case "categories": - return categories() - case "comics": - return comics(params) - case "searchComics": - return searchComics(params) - case "randomComics": - return randomComics() - case "leaderboard": - return leaderboard(params) - case "comicInfo": - return comicInfo(params) - case "comicEpPage": - return epPage(params) - case "comicPicturePageWithQuality": - return comicPicturePageWithQuality(params) - case "switchLike": - return switchLike(params) - case "switchFavourite": - return switchFavourite(params) - case "favouriteComics": - return favouriteComics(params) - case "recommendation": - return recommendation(params) - case "comments": - return comments(params) - case "commentChildren": - return commentChildren(params) - case "myComments": - return myComments(params) - case "postComment": - return postComment(params) - case "postChildComment": - return postChildComment(params) - case "game": - return game(params) - case "games": - return games(params) - case "gameComments": - return gameComments(params) - case "postGameComment": - return postGameComment(params) - case "gameCommentChildren": - return gameCommentChildren(params) - case "switchLikeGameComment": - return switchLikeGameComment(params) - case "postGameChildComment": - return postGameChildComment(params) - case "viewLogPage": - return viewLogPage(params) - case "clearAllViewLog": - comic_center.ClearAllViewLog() - return "", nil - case "deleteViewLog": - comic_center.DeleteViewLog(params) - return "", nil - case "cleanNetworkCache": - return "", cleanNetworkCache() - case "cleanImageCache": - return "", cleanImageCache() - case "clean": - return "", clean() - case "autoClean": - expire, err := strconv.ParseInt(params, 10, 64) - if err != nil { - return "", err - } - return "", autoClean(expire) - case "storeViewEp": - return "", storeViewEp(params) - case "loadView": - return loadView(params) - case "downloadRunning": - return strconv.FormatBool(getDownloadRunning()), nil - case "setDownloadRunning": - b, e := strconv.ParseBool(params) - if e != nil { - return "", e - } - setDownloadRunning(b) - return "", nil - case "createDownload": - return "", createDownload(params) - case "addDownload": - return "", addDownload(params) - case "loadDownloadComic": - return loadDownloadComic(params) - case "allDownloads": - return allDownloads() - case "deleteDownloadComic": - return "", deleteDownloadComic(params) - case "downloadEpList": - return downloadEpList(params) - case "downloadPicturesByEpId": - return downloadPicturesByEpId(params) - case "resetAllDownloads": - return "", comic_center.ResetAll() - case "exportComicDownload": - return exportComicDownload(params) - case "exportComicDownloadToJPG": - return "", exportComicDownloadToJPG(params) - case "exportComicUsingSocket": - i, e := exportComicUsingSocket(params) - return fmt.Sprintf("%d", i), e - case "exportComicUsingSocketExit": - return "", exportComicUsingSocketExit() - case "importComicDownload": - return "", importComicDownload(params) - case "importComicDownloadUsingSocket": - return "", importComicDownloadUsingSocket(params) - case "remoteImageData": - return remoteImageData(params) - case "remoteImagePreload": - return "", remoteImagePreload(params) - case "clientIpSet": - return clientIpSet() - case "downloadImagePath": - return downloadImagePath(params) - case "downloadGame": - return downloadGame(params) - case "convertImageToJPEG100": - return "", convertImageToJPEG100(params) - case "loadDownloadAndExportPath": - return loadDownloadAndExportPath(), nil - case "saveDownloadAndExportPath": - return "", saveDownloadAndExportPath(params) - case "saveDownloadThreadCount": - i, e := strconv.Atoi(params) - if e != nil { - return "", e - } - saveDownloadThreadCount(i) - return "", nil - case "loadDownloadThreadCount": - return strconv.Itoa(loadDownloadThreadCount()), nil - case "switchLikeComment": - return switchLikeComment(params) - case "updatePassword": - return updatePassword(params) - case "updateSlogan": - return updateSlogan(params) - case "updateAvatar": - return updateAvatar(params) - case "defaultHttpClientGet": - return defaultHttpClientGet(params) - case "loadViewedList": - return loadViewedList(params) - case "collections": - return collections(params) - } - return "", errors.New("method not found : " + method) -} diff --git a/go/pikapika/utils/const.go b/go/pikapika/utils/const.go deleted file mode 100644 index 79bef19..0000000 --- a/go/pikapika/utils/const.go +++ /dev/null @@ -1,16 +0,0 @@ -package utils - -import ( - "gorm.io/gorm" - "gorm.io/gorm/logger" - "os" -) - -var ( - CreateDirMode = os.FileMode(0700) - CreateFileMode = os.FileMode(0600) - GormConfig = &gorm.Config{ - Logger: logger.Default.LogMode(logger.Info), - } -) - diff --git a/go/pikapika/utils/file.go b/go/pikapika/utils/file.go deleted file mode 100644 index 0ba204c..0000000 --- a/go/pikapika/utils/file.go +++ /dev/null @@ -1,42 +0,0 @@ -package utils - -import ( - "errors" - "os" - "strings" -) - -func Mkdir(dir string) { - if _, err := os.Stat(dir); err != nil { - if os.IsNotExist(err) { - err = os.MkdirAll(dir, CreateDirMode) - if err != nil { - panic(err) - } - } else { - panic(err) - } - } -} - -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 -} - -func Exists(name string) (bool, error) { - _, err := os.Stat(name) - if err == nil { - return true, nil - } - if errors.Is(err, os.ErrNotExist) { - return false, nil - } - return false, err -} \ No newline at end of file diff --git a/go/pikapika/utils/mutex.go b/go/pikapika/utils/mutex.go deleted file mode 100644 index 9f73309..0000000 --- a/go/pikapika/utils/mutex.go +++ /dev/null @@ -1,21 +0,0 @@ -package utils - -import ( - "hash/fnv" - "sync" -) - -var hashMutex []*sync.Mutex - -func init() { - for i := 0; i < 32; i++ { - hashMutex = append(hashMutex, &sync.Mutex{}) - } -} - -// HashLock Hash一样的图片不同时处理 -func HashLock(key string) *sync.Mutex { - hash := fnv.New32() - hash.Write([]byte(key)) - return hashMutex[int(hash.Sum32()%uint32(len(hashMutex)))] -} diff --git a/go/pikapika/utils/time.go b/go/pikapika/utils/time.go deleted file mode 100644 index 8b1b471..0000000 --- a/go/pikapika/utils/time.go +++ /dev/null @@ -1,8 +0,0 @@ -package utils - -import "time" - -// Timestamp 获取当前的Unix时间戳 -func Timestamp() int64 { - return time.Now().UnixNano() / int64(time.Millisecond) -} diff --git a/lib/basic/Method.dart b/lib/basic/Method.dart index 6e2ee33..0d0035a 100644 --- a/lib/basic/Method.dart +++ b/lib/basic/Method.dart @@ -285,7 +285,7 @@ class Method { return ComicsPage.fromJson(json.decode(rsp)); } - /// 看了此漫画的人还看了...(此接口似乎失效了) + /// 看了此漫画的人还看了... Future> recommendation(String comicId) async { String rsp = await _flatInvoke("recommendation", comicId); List list = json.decode(rsp); diff --git a/lib/screens/ComicInfoScreen.dart b/lib/screens/ComicInfoScreen.dart index 3d6082c..70cd7d6 100644 --- a/lib/screens/ComicInfoScreen.dart +++ b/lib/screens/ComicInfoScreen.dart @@ -7,6 +7,7 @@ import 'package:pikapika/basic/Navigator.dart'; import 'package:pikapika/screens/ComicsScreen.dart'; import 'package:pikapika/screens/components/CommentMainType.dart'; import 'package:pikapika/screens/components/ItemBuilder.dart'; +import 'package:pikapika/screens/components/Recommendation.dart'; import 'ComicReaderScreen.dart'; import 'DownloadConfirmScreen.dart'; @@ -111,10 +112,12 @@ class _ComicInfoScreenState extends State with RouteAware { var _tabs = [ Tab(text: '章节 (${_comicInfo.epsCount})'), Tab(text: '评论 (${_comicInfo.commentsCount})'), + const Tab(text: '推荐'), ]; var _views = [ _buildEpWrap(_epListFuture, _comicInfo), CommentList(CommentMainType.COMIC, _comicInfo.id), + Recommendation(comicId: _comicInfo.id), ]; return DefaultTabController( length: _tabs.length, diff --git a/lib/screens/components/Recommendation.dart b/lib/screens/components/Recommendation.dart index 44c0ba9..4ea310a 100644 --- a/lib/screens/components/Recommendation.dart +++ b/lib/screens/components/Recommendation.dart @@ -7,7 +7,6 @@ import 'ItemBuilder.dart'; import 'Images.dart'; // 看过此本子的也在看 -// 一直返回空数组, 所以没有使用 class Recommendation extends StatefulWidget { final String comicId;