├── .github
└── workflows
│ ├── ci.yml
│ ├── golint.yml
│ └── release.yml
├── .gitignore
├── LICENSE
├── README.md
├── go.mod
├── go.sum
├── http.go
├── index.html
└── main.go
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on: [ push, pull_request, workflow_dispatch ]
4 |
5 | env:
6 | BINARY_PREFIX: "go-pixiv-proxy_"
7 | BINARY_SUFFIX: ""
8 | COMMIT_ID: "${{ github.sha }}"
9 | PR_PROMPT: "::warning:: Build artifact will not be uploaded due to the workflow is trigged by pull request."
10 |
11 | jobs:
12 | build:
13 | name: Build binary CI
14 | runs-on: ubuntu-latest
15 | strategy:
16 | matrix:
17 | # build and publish in parallel: linux/386, linux/amd64, windows/386, windows/amd64, darwin/amd64, darwin/arm64
18 | goos: [ linux, windows, darwin ]
19 | goarch: [ amd64, arm, arm64 ]
20 | exclude:
21 | - goos: darwin
22 | goarch: arm
23 | fail-fast: true
24 | steps:
25 | - uses: actions/checkout@v2
26 | - name: Setup Go environment
27 | uses: actions/setup-go@v2.1.3
28 | with:
29 | go-version: 1.17
30 | - name: Cache downloaded module
31 | uses: actions/cache@v2
32 | with:
33 | path: |
34 | ~/.cache/go-build
35 | ~/go/pkg/mod
36 | key: ${{ runner.os }}-go-${{ matrix.goos }}-${{ matrix.goarch }}-${{ hashFiles('**/go.sum') }}
37 | - name: Build binary file
38 | env:
39 | GOOS: ${{ matrix.goos }}
40 | GOARCH: ${{ matrix.goarch }}
41 | IS_PR: ${{ !!github.head_ref }}
42 | run: |
43 | if [ $GOOS = "windows" ]; then export BINARY_SUFFIX="$BINARY_SUFFIX.exe"; fi
44 | if $IS_PR ; then echo $PR_PROMPT; fi
45 | export BINARY_NAME="$BINARY_PREFIX$GOOS_$GOARCH$BINARY_SUFFIX"
46 | export LD_FLAGS="-w -s"
47 | go build -o "output/$BINARY_NAME" -trimpath -ldflags "$LD_FLAGS" .
48 | - name: Upload artifact
49 | uses: actions/upload-artifact@v2
50 | if: ${{ !github.head_ref }}
51 | with:
52 | name: ${{ matrix.goos }}_${{ matrix.goarch }}
53 | path: output/
54 |
--------------------------------------------------------------------------------
/.github/workflows/golint.yml:
--------------------------------------------------------------------------------
1 | name: Lint
2 |
3 | on: [push,pull_request,workflow_dispatch]
4 |
5 | jobs:
6 | golangci:
7 | name: lint
8 | runs-on: ubuntu-latest
9 | steps:
10 | - uses: actions/checkout@v2
11 |
12 | - name: Setup Go environment
13 | uses: actions/setup-go@v2.1.3
14 | with:
15 | go-version: 1.17
16 |
17 | - name: golangci-lint
18 | uses: golangci/golangci-lint-action@v2
19 | with:
20 | version: latest
21 |
22 | - name: Tests
23 | run: |
24 | go test $(go list ./...)
25 |
26 | - name: Commit back
27 | if: ${{ github.repository_owner == 'Mrs4s' && !github.event.pull_request }}
28 | continue-on-error: true
29 | run: |
30 | git config --local user.name 'github-actions[bot]'
31 | git config --local user.email '41898282+github-actions[bot]@users.noreply.github.com'
32 | git add --all
33 | git commit -m "ci(chore): Fix stylings"
34 | git push
35 |
36 | - name: Suggester
37 | if: ${{ github.event.pull_request }}
38 | uses: reviewdog/action-suggester@v1
39 | with:
40 | github_token: ${{ secrets.GITHUB_TOKEN }}
41 | tool_name: golangci-lint
42 |
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | name: release
2 |
3 | on:
4 | push:
5 | tags:
6 | - 'v*'
7 |
8 | jobs:
9 | goreleaser:
10 | runs-on: ubuntu-latest
11 | steps:
12 | - name: Checkout
13 | uses: actions/checkout@v2.3.4
14 | with:
15 | fetch-depth: 0
16 |
17 | - name: Set up Go
18 | uses: actions/setup-go@v2
19 | with:
20 | go-version: '1.17'
21 |
22 | - name: Run GoReleaser
23 | uses: goreleaser/goreleaser-action@v2
24 | with:
25 | version: latest
26 | args: release --rm-dist
27 | env:
28 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | .vscode
3 |
4 | *.exe
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | BSD 3-Clause License
2 |
3 | Copyright (c) 2022, 秋葉杏
4 | All rights reserved.
5 |
6 | Redistribution and use in source and binary forms, with or without
7 | modification, are permitted provided that the following conditions are met:
8 |
9 | 1. Redistributions of source code must retain the above copyright notice, this
10 | list of conditions and the following disclaimer.
11 |
12 | 2. Redistributions in binary form must reproduce the above copyright notice,
13 | this list of conditions and the following disclaimer in the documentation
14 | and/or other materials provided with the distribution.
15 |
16 | 3. Neither the name of the copyright holder nor the names of its
17 | contributors may be used to endorse or promote products derived from
18 | this software without specific prior written permission.
19 |
20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |

4 |
5 | # go-pixiv-proxy
6 | _✨ 一个简单易懂的p站图片代理! ✨_
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | 下载
24 | ·
25 | 文档
26 |
27 |
28 | # 简介
29 |
30 | 一个简单易懂的p站图片代理!
31 |
32 | # 使用说明
33 |
34 | ## 部署
35 |
36 | ### 直接部署
37 |
38 | 从 [release](https://github.com/Akegarasu/go-pixiv-proxy/releases) 下载对应系统的可执行文件直接运行
39 |
40 | ### 启动参数
41 |
42 | `-h`: host 默认 127.0.0.1
43 |
44 | `-p`: 端口 默认 18090
45 |
46 | `-d`: 指定域名(用于主页展示示例图片可以不填)
47 |
48 | ### 环境变量
49 |
50 | 注意:环境变量会 **默认覆盖** 启动参数
51 |
52 | `GPP_HOST`: host
53 |
54 | `GPP_PORT`: 端口
55 |
56 | `GPP_DOMAIN`: 域名
57 |
58 |
59 | ## 代理图片
60 |
61 | 提供了两种代理的方法
62 |
63 | ### 替换 `i.piximg.net` 为你的域名
64 |
65 | https://i.pximg.net/img-original/img/2022/05/21/22/35/46/98505703_p0.jpg
66 |
67 | 替换为
68 |
69 | http://example.com/img-original/img/2022/05/21/22/35/46/98505703_p0.jpg
70 |
71 | ### url 后接 pid
72 |
73 | http://example.com/98505703
74 |
75 | ## 图片质量选择
76 |
77 | 针对 **url 后接 pid** 的使用方法,提供了图片质量选择的参数
78 |
79 | 使用方法:添加参数 `t`
80 |
81 | 支持
82 |
83 | - original
84 | - regular
85 | - small
86 | - thumb
87 | - mini
88 |
89 | 例子: http://example.com/98505703?t=original
90 |
91 |
92 | ## 代理 api
93 |
94 | http://example.com/api/pid
95 |
96 | ## 其他示范用例
97 |
98 | ```
99 | 1. http://example.com/$path
100 | - http://example.com/img-original/img/0000/00/00/00/00/00/12345678_p0.png
101 |
102 | 2. http://example.com/$pid[/$p][?t=original|regular|small|thumb|mini]
103 | - http://example.com/12345678 (p0)
104 | - http://example.com/12345678/0 (p0)
105 | - http://example.com/12345678/1 (p1)
106 | - http://example.com/12345678?t=small (small image)
107 | ```
108 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module go-pixiv-proxy
2 |
3 | go 1.18
4 |
5 | require (
6 | github.com/sirupsen/logrus v1.8.1
7 | github.com/t-tomalak/logrus-easy-formatter v0.0.0-20190827215021-c074f06c5816
8 | github.com/tidwall/gjson v1.12.1
9 | )
10 |
11 | require (
12 | github.com/stretchr/testify v1.7.1 // indirect
13 | github.com/tidwall/match v1.1.1 // indirect
14 | github.com/tidwall/pretty v1.2.0 // indirect
15 | golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect
16 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
17 | )
18 |
--------------------------------------------------------------------------------
/go.sum:
--------------------------------------------------------------------------------
1 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
2 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
3 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
4 | github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
5 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
6 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
7 | github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
8 | github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
9 | github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
10 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
11 | github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
12 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
13 | github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
14 | github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
15 | github.com/t-tomalak/logrus-easy-formatter v0.0.0-20190827215021-c074f06c5816 h1:J6v8awz+me+xeb/cUTotKgceAYouhIB3pjzgRd6IlGk=
16 | github.com/t-tomalak/logrus-easy-formatter v0.0.0-20190827215021-c074f06c5816/go.mod h1:tzym/CEb5jnFI+Q0k4Qq3+LvRF4gO3E2pxS8fHP8jcA=
17 | github.com/tidwall/gjson v1.12.1 h1:ikuZsLdhr8Ws0IdROXUS1Gi4v9Z4pGqpX/CvJkxvfpo=
18 | github.com/tidwall/gjson v1.12.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
19 | github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
20 | github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
21 | github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
22 | github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
23 | golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
24 | golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
25 | golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k=
26 | golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
27 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
28 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
29 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
30 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
31 |
--------------------------------------------------------------------------------
/http.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "io"
5 | "net/http"
6 | "net/url"
7 |
8 | log "github.com/sirupsen/logrus"
9 | )
10 |
11 | var (
12 | headers = map[string]string{
13 | "Referer": "https://www.pixiv.net",
14 | "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.113 Safari/537.36",
15 | }
16 | client = &http.Client{
17 | Transport: &http.Transport{
18 | Proxy: func(request *http.Request) (u *url.URL, e error) {
19 | return http.ProxyFromEnvironment(request)
20 | },
21 | },
22 | }
23 | )
24 |
25 | type Context struct {
26 | rw http.ResponseWriter
27 | req *http.Request
28 | }
29 |
30 | func (c *Context) write(b []byte, status int) {
31 | c.rw.WriteHeader(status)
32 | _, err := c.rw.Write(b)
33 | if err != nil {
34 | log.Error(err)
35 | }
36 | }
37 |
38 | func (c *Context) String(status int, s string) {
39 | c.write([]byte(s), status)
40 | }
41 |
42 | func (c *Context) WriteHeader(statusCode int) {
43 | c.rw.WriteHeader(statusCode)
44 | }
45 |
46 | func proxyHttpReq(c *Context, url string, errMsg string) {
47 | resp, err := httpGet(url)
48 | if err != nil {
49 | c.String(500, errMsg)
50 | return
51 | }
52 | defer resp.Body.Close()
53 | copyHeader(c.rw.Header(), resp.Header)
54 | resp.Header.Del("Cookie")
55 | resp.Header.Del("Set-Cookie")
56 | _, _ = io.Copy(c.rw, resp.Body)
57 | }
58 |
59 | func httpGet(u string) (*http.Response, error) {
60 | req, err := http.NewRequest("GET", u, nil)
61 | if err != nil {
62 | return nil, err
63 | }
64 | for k, v := range headers {
65 | req.Header.Set(k, v)
66 | }
67 | req.Header.Set("Cookie", cookies)
68 | resp, err := client.Do(req)
69 | if err != nil {
70 | return nil, err
71 | }
72 | return resp, nil
73 | }
74 |
75 | func httpGetReadCloser(u string) (io.ReadCloser, error) {
76 | resp, err := httpGet(u)
77 | if err != nil {
78 | return nil, err
79 | }
80 | return resp.Body, nil
81 | }
82 |
83 | func httpGetBytes(url string) ([]byte, error) {
84 | body, err := httpGetReadCloser(url)
85 | if err != nil {
86 | return nil, err
87 | }
88 | defer body.Close()
89 | b, err := io.ReadAll(body)
90 | if err != nil {
91 | return nil, err
92 | }
93 | return b, nil
94 | }
95 |
96 | func copyHeader(dst, src http.Header) {
97 | for k, vv := range src {
98 | for _, v := range vv {
99 | dst.Add(k, v)
100 | }
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | **go-pixiv-proxy**
5 |
6 | # 简介
7 |
8 | 一个简单易懂的p站图片代理!
9 |
10 | 项目地址 [go-pixiv-proxy](https://github.com/Akegarasu/go-pixiv-proxy)
11 |
12 | # 使用说明
13 |
14 | ## 启动参数
15 |
16 | `-h`: host
17 |
18 | `-p`: 端口
19 |
20 | `-d`: 指定域名(用于主页展示示例图片可以不填)
21 |
22 | ## 代理图片
23 |
24 | 提供了两种代理的方法
25 |
26 | ### 替换 `i.piximg.net` 为你的域名
27 |
28 | https://i.pximg.net/img-original/img/2022/05/21/22/35/46/98505703_p0.jpg
29 |
30 | 替换为
31 |
32 | http://example.com/img-original/img/2022/05/21/22/35/46/98505703_p0.jpg
33 |
34 | ### url 后接 pid
35 |
36 | http://example.com/98505703
37 |
38 | ## 图片质量选择
39 |
40 | 针对 **url 后接 pid** 的使用方法,提供了图片质量选择的参数
41 |
42 | 使用方法:添加参数 `t`
43 |
44 | 支持
45 |
46 | - original
47 | - regular
48 | - small
49 | - thumb
50 | - mini
51 |
52 | 例子: http://example.com/98505703?t=original
53 |
54 | {image-examples}
55 |
56 | ## 代理 api
57 |
58 | http://example.com/api/pid
59 |
60 | ## 其他示范用例
61 |
62 | ```
63 | 1. http://example.com/$path
64 | - http://example.com/img-original/img/0000/00/00/00/00/00/12345678_p0.png
65 |
66 | 2. http://example.com/$pid[/$p][?t=original|regular|small|thumb|mini]
67 | - http://example.com/12345678 (p0)
68 | - http://example.com/12345678/0 (p0)
69 | - http://example.com/12345678/1 (p1)
70 | - http://example.com/12345678?t=small (small image)
71 | ```
72 |
73 |
74 |
81 |
84 |
85 |
--------------------------------------------------------------------------------
/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | _ "embed"
5 | "flag"
6 | "fmt"
7 | "net/http"
8 | "os"
9 | "strconv"
10 | "strings"
11 |
12 | log "github.com/sirupsen/logrus"
13 | easy "github.com/t-tomalak/logrus-easy-formatter"
14 | "github.com/tidwall/gjson"
15 | )
16 |
17 | var (
18 | host string
19 | port string
20 | domain string
21 | cookies string
22 | //go:embed index.html
23 | indexHtml string
24 | directTypes = []string{"img-original", "img-master", "c", "user-profile", "img-zip-ugoira"}
25 | imgTypes = []string{"original", "regular", "small", "thumb", "mini"}
26 | docExampleImg = `
27 |
28 | 
29 |
30 | 
31 |
32 | `
33 | )
34 |
35 | type Illust struct {
36 | origUrl string
37 | urls map[string]gjson.Result
38 | }
39 |
40 | func handlePixivProxy(rw http.ResponseWriter, req *http.Request) {
41 | var err error
42 | var realUrl string
43 | c := &Context{
44 | rw: rw,
45 | req: req,
46 | }
47 | path := req.URL.Path
48 | log.Info(req.Method, " ", req.URL.String())
49 | spl := strings.Split(path, "/")[1:]
50 | switch spl[0] {
51 | case "":
52 | c.String(200, indexHtml)
53 | return
54 | case "favicon.ico":
55 | c.WriteHeader(404)
56 | return
57 | case "api":
58 | handleIllustInfo(c)
59 | return
60 | }
61 | imgType := req.URL.Query().Get("t")
62 | if imgType == "" {
63 | imgType = "original"
64 | }
65 | if !in(imgTypes, imgType) {
66 | c.String(400, "invalid query")
67 | return
68 | }
69 | if in(directTypes, spl[0]) {
70 | realUrl = "https://i.pximg.net" + path
71 | } else {
72 | if _, err = strconv.Atoi(spl[0]); err != nil {
73 | c.String(400, "invalid query")
74 | return
75 | }
76 | illust, err := getIllust(spl[0])
77 | if err != nil {
78 | c.String(400, "pixiv api error")
79 | return
80 | }
81 | if r, ok := illust.urls[imgType]; ok {
82 | realUrl = r.String()
83 | } else {
84 | c.String(400, "this image type not exists")
85 | return
86 | }
87 | if realUrl == "" {
88 | c.String(400, "this image needs login, set GPP_COOKIES env.")
89 | }
90 | if len(spl) > 1 {
91 | realUrl = strings.Replace(realUrl, "_p0", "_p"+spl[1], 1)
92 | }
93 | }
94 | proxyHttpReq(c, realUrl, "fetch pixiv image error")
95 | }
96 |
97 | func handleIllustInfo(c *Context) {
98 | params := strings.Split(c.req.URL.Path, "/")
99 | pid := params[len(params)-1]
100 | if _, err := strconv.Atoi(pid); err != nil {
101 | c.String(400, "pid invalid")
102 | return
103 | }
104 | proxyHttpReq(c, "https://www.pixiv.net/ajax/illust/"+pid, "pixiv api error")
105 | }
106 |
107 | func getIllust(pid string) (*Illust, error) {
108 | b, err := httpGetBytes("https://www.pixiv.net/ajax/illust/" + pid)
109 | if err != nil {
110 | return nil, err
111 | }
112 | g := gjson.ParseBytes(b)
113 | imgUrl := g.Get("body.urls.original").String()
114 | return &Illust{
115 | origUrl: imgUrl,
116 | urls: g.Get("body.urls").Map(),
117 | }, nil
118 | }
119 |
120 | func in(orig []string, str string) bool {
121 | for _, b := range orig {
122 | if b == str {
123 | return true
124 | }
125 | }
126 | return false
127 | }
128 |
129 | func checkEnv() {
130 | if os.Getenv("GPP_HOST") != "" {
131 | host = os.Getenv("GPP_HOST")
132 | }
133 | if os.Getenv("GPP_PORT") != "" {
134 | port = os.Getenv("GPP_PORT")
135 | }
136 | if os.Getenv("GPP_DOMAIN") != "" {
137 | domain = os.Getenv("GPP_DOMAIN")
138 | }
139 | if os.Getenv("GPP_COOKIES") != "" {
140 | cookies = os.Getenv("GPP_COOKIES")
141 | }
142 | }
143 |
144 | func init() {
145 | flag.StringVar(&host, "h", "127.0.0.1", "host")
146 | flag.StringVar(&port, "p", "18090", "port")
147 | flag.StringVar(&domain, "d", "", "your domain")
148 | flag.StringVar(&cookies, "c", "", "cookie")
149 | log.SetFormatter(&easy.Formatter{
150 | TimestampFormat: "2006-01-02 15:04:05",
151 | LogFormat: "[%lvl%][%time%]: %msg% \n",
152 | })
153 | log.SetLevel(log.InfoLevel)
154 | }
155 |
156 | func main() {
157 | flag.Parse()
158 | checkEnv()
159 | if domain != "" {
160 | indexHtml = strings.ReplaceAll(indexHtml, "{image-examples}", docExampleImg)
161 | indexHtml = strings.ReplaceAll(indexHtml, "http://example.com", domain)
162 | }
163 | http.HandleFunc("/", handlePixivProxy)
164 | log.Infof("started: %s:%s %s", host, port, domain)
165 | err := http.ListenAndServe(fmt.Sprintf("%s:%s", host, port), nil)
166 | if err != nil {
167 | log.Error("start failed: ", err)
168 | }
169 | }
170 |
--------------------------------------------------------------------------------