├── .github
└── workflows
│ ├── codeql-analysis.yml
│ ├── go.yml
│ └── goreleaser.yml
├── .gitignore
├── LICENSE
├── Makefile
├── README.md
├── bin
├── arm
│ └── go-pd
├── linux
│ └── go-pd
└── windows
│ └── go-pd.exe
├── cmd
├── download.go
├── root.go
└── upload.go
├── dist
├── artifacts.json
├── config.yaml
├── go-pd_1.1.0-SNAPSHOT-85d261a_checksums.txt
├── go-pd_1.1.0-SNAPSHOT-85d261a_darwin_amd64.tar.gz
├── go-pd_1.1.0-SNAPSHOT-85d261a_darwin_arm64.tar.gz
├── go-pd_1.1.0-SNAPSHOT-85d261a_linux_386.tar.gz
├── go-pd_1.1.0-SNAPSHOT-85d261a_linux_amd64.tar.gz
├── go-pd_1.1.0-SNAPSHOT-85d261a_linux_arm64.tar.gz
├── go-pd_darwin_amd64_v1
│ └── go-pd
├── go-pd_darwin_arm64
│ └── go-pd
├── go-pd_linux_386
│ └── go-pd
├── go-pd_linux_amd64_v1
│ └── go-pd
├── go-pd_linux_arm64
│ └── go-pd
└── metadata.json
├── go-pd-upload-and-download.gif
├── go.mod
├── go.sum
├── internal
└── app
│ ├── cmdDownload.go
│ └── cmdUpload.go
├── logo.jpg
├── main.go
└── pkg
└── pd
├── .env
├── .gitignore
├── mock_server.go
├── pd.go
├── pd_test.go
├── request.go
├── request_test.go
├── response.go
├── response_test.go
└── testdata
├── cat.jpg
└── cat_thumbnail.jpg
/.github/workflows/codeql-analysis.yml:
--------------------------------------------------------------------------------
1 | # For most projects, this workflow file will not need changing; you simply need
2 | # to commit it to your repository.
3 | #
4 | # You may wish to alter this file to override the set of languages analyzed,
5 | # or to provide custom queries or build logic.
6 | #
7 | # ******** NOTE ********
8 | # We have attempted to detect the languages in your repository. Please check
9 | # the `language` matrix defined below to confirm you have the correct set of
10 | # supported CodeQL languages.
11 | #
12 | name: "CodeQL"
13 |
14 | on:
15 | push:
16 | branches: [ main ]
17 | pull_request:
18 | # The branches below must be a subset of the branches above
19 | branches: [ main ]
20 | schedule:
21 | - cron: '43 1 * * 0'
22 |
23 | jobs:
24 | analyze:
25 | name: Analyze
26 | runs-on: ubuntu-latest
27 | permissions:
28 | actions: read
29 | contents: read
30 | security-events: write
31 |
32 | strategy:
33 | fail-fast: false
34 | matrix:
35 | language: [ 'go' ]
36 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
37 | # Learn more about CodeQL language support at https://git.io/codeql-language-support
38 |
39 | steps:
40 | - name: Checkout repository
41 | uses: actions/checkout@v3
42 |
43 | # Initializes the CodeQL tools for scanning.
44 | - name: Initialize CodeQL
45 | uses: github/codeql-action/init@v2
46 | with:
47 | languages: ${{ matrix.language }}
48 | # If you wish to specify custom queries, you can do so here or in a config file.
49 | # By default, queries listed here will override any specified in a config file.
50 | # Prefix the list here with "+" to use these queries and those in the config file.
51 | # queries: ./path/to/local/query, your-org/your-repo/queries@main
52 |
53 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
54 | # If this step fails, then you should remove it and run the build manually (see below)
55 | - name: Autobuild
56 | uses: github/codeql-action/autobuild@v2
57 |
58 | # ℹ️ Command-line programs to run using the OS shell.
59 | # 📚 https://git.io/JvXDl
60 |
61 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
62 | # and modify them (or add more) to build your code if your project
63 | # uses a compiled language
64 |
65 | #- run: |
66 | # make bootstrap
67 | # make release
68 |
69 | - name: Perform CodeQL Analysis
70 | uses: github/codeql-action/analyze@v2
71 |
--------------------------------------------------------------------------------
/.github/workflows/go.yml:
--------------------------------------------------------------------------------
1 | name: Go
2 |
3 | on:
4 | push:
5 | branches: [ main ]
6 | pull_request:
7 | branches: [ main ]
8 |
9 | jobs:
10 |
11 | test-build:
12 | runs-on: ubuntu-latest
13 | strategy:
14 | matrix:
15 | go-version: ['1.21']
16 | steps:
17 | - uses: actions/checkout@v4
18 |
19 | - name: Set up Go ${{ matrix.go-version }}
20 | uses: actions/setup-go@v4
21 | with:
22 | go-version: ${{ matrix.go-version }}
23 |
24 | - name: Display Go Version
25 | run: go version
26 |
27 | - name: Install dependencies
28 | run: go get .
29 |
30 | - name: test
31 | run: make test
32 |
33 | - name: build
34 | run: make build
35 |
--------------------------------------------------------------------------------
/.github/workflows/goreleaser.yml:
--------------------------------------------------------------------------------
1 | name: goreleaser
2 |
3 | on:
4 | push:
5 | tags:
6 | - '*'
7 |
8 | jobs:
9 | goreleaser:
10 | runs-on: ubuntu-latest
11 | steps:
12 | -
13 | name: Checkout
14 | uses: actions/checkout@v3
15 | with:
16 | fetch-depth: 0
17 | -
18 | name: Set up Go
19 | uses: actions/setup-go@v4
20 | with:
21 | go-version: stable
22 | -
23 | name: Run GoReleaser
24 | uses: goreleaser/goreleaser-action@v4
25 | with:
26 | # either 'goreleaser' (default) or 'goreleaser-pro'
27 | distribution: goreleaser
28 | version: latest
29 | args: release --rm-dist
30 | env:
31 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
32 | # Your GoReleaser Pro key, if you are using the 'goreleaser-pro' distribution
33 | # GORELEASER_KEY: ${{ secrets.GORELEASER_KEY }}
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .vscode
2 | c.out
3 | coverage.html
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Manuel Reschke
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | FILES ?= $(shell find . -type f -name '*.go' -not -path "./vendor/*")
2 |
3 | .PHONY: hello
4 | hello:
5 | echo "Hello World"
6 | .PHONY: hello
7 |
8 | test: ## run all unit test
9 | go test ./... -v -short
10 | .PHONY: test
11 |
12 | test-integration: ## run all integration test
13 | go test ./... -v -run Integration
14 | .PHONY: test-integration
15 |
16 | coverage: ## create coverage report with go get golang.org/x/tools/cmd/cover
17 | go test -cover -coverprofile=c.out ./...
18 | go tool cover -html=c.out -o coverage.html
19 | .PHONY: coverage
20 |
21 | fmt: ## format the go source files
22 | go fmt ./...
23 | .PHONY: fmt
24 |
25 | build:
26 | env GOOS=linux GOARCH=amd64 go build -o bin/linux/go-pd
27 | env GOOS=linux GOARCH=arm64 go build -o bin/arm/go-pd
28 | env GOOS=windows GOARCH=amd64 go build -o bin/windows/go-pd.exe
29 | .PHONY: build
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://github.com/ManuelReschke/go-pd/releases)
2 | 
3 | 
4 | 
5 | 
6 |
7 | # Go-PD - A pixeldrain.com client pkg and CLI tool
8 |
9 | 
10 |
11 | A free pixeldrain.com client written in go. We use the super power from [imroc/req](https://github.com/imroc/req) (v3.43.x) to build a robust and fast pixeldrain client and [cobra](https://github.com/spf13/cobra) for our CLI tool.
12 |
13 | 
14 |
15 | ## Content:
16 | - [Using the CLI tool](#cli-tool)
17 | - [CLI Tool: Install](#cli-tool-install)
18 | - [CLI Tool: Upload a file](#cli-tool-upload-a-file)
19 | - [CLI Tool: Download a file](#cli-tool-download-a-file)
20 | - [Using the client pkg](#client-pkg)
21 | - [Why?](#why)
22 | - [Import pkg](#import-the-pkg)
23 | - [Example 1 - the easiest way to upload an anonymous file](#example-1---the-easiest-way-to-upload-an-anonymous-file)
24 | - [Example 2 - advanced way to upload a file to user account](#example-2---advanced-way-to-upload-a-file-to-user-account)
25 | - [ToDo's](#todos)
26 | - [Covered methods](#pixeldrain-methods-covered-by-this-package)
27 | - [License](#license)
28 |
29 |
30 | # Using the CLI tool
31 |
32 | ## CLI Tool: Install
33 |
34 | Follow the link to download the correct binary for your system. [View Releases](https://github.com/ManuelReschke/go-pd/releases). It's available for Linux, ARM and Windows.
35 | Download the correct archive, extract it and use the binary.
36 |
37 | ## CLI Tool: Upload a file
38 |
39 | Go to the folder where you download the binary file and run the following command in a CLI.
40 |
41 | **Simple upload:**
42 |
43 | ```
44 | ./go-pd upload my-cat.jpg
45 |
46 | Output:
47 | https://pixeldrain.com/u/aaaaaaaa
48 | ```
49 |
50 | **Upload to your account (-verbose):**
51 | The verbose option enable also the progress in % and the env check message.
52 |
53 | ```
54 | ./go-pd upload -k -v my-cat.jpg my-cat2.jpg
55 |
56 | Output:
57 | Using API Key from environment variable: PIXELDRAIN_API_KEY
58 | "my-cat.jpg" uploaded 100.00%
59 | Successful! Anonymous upload: false | ID: xBxxxxxx | URL: https://pixeldrain.com/u/xBxxxxxx
60 | "my-cat2.jpg" uploaded 100.00%
61 | Successful! Anonymous upload: false | ID: xAxxxxxx | URL: https://pixeldrain.com/u/xAxxxxxx
62 | ```
63 |
64 | ## CLI Tool: Download a file
65 |
66 | Go to the folder where you download the binary file and run the following command in a CLI.
67 |
68 | **Simple download:**
69 |
70 | ```
71 | ./go-pd download https://pixeldrain.com/u/YqiUjXXX
72 |
73 | Output:
74 | /the/path/to/your/file
75 | ```
76 |
77 | **Download multiple files to a specific path (-verbose):**
78 |
79 | ```
80 | ./go-pd download -k -p /home/pixeldrain/pictures/ YqiUjXXX YqiUjX02 YqiUjX03
81 |
82 | Output:
83 | Successful! Download complete: filename01.jpg | ID: xBxxxxxx | Stored to: /home/pixeldrain/pictures/filename01.jpg
84 | Successful! Download complete: filename02.jpg | ID: xBxxxxxx | Stored to: /home/pixeldrain/pictures/filename02.jpg
85 | Successful! Download complete: filename03.jpg | ID: xBxxxxxx | Stored to: /home/pixeldrain/pictures/filename03.jpg
86 | ```
87 |
88 |
89 | # Using the client pkg
90 |
91 |
92 | ## Why the package?
93 |
94 | Because we want a simple, fast, robust and tested go package to upload to pixeldrain.com.
95 |
96 |
97 | ### Import the pkg
98 |
99 | ```
100 | go get github.com/ManuelReschke/go-pd/pkg/pd
101 | ```
102 |
103 | ## Example 1 - the easiest way to upload an anonymous file
104 |
105 | ```go
106 | package main
107 |
108 | import (
109 | "fmt"
110 | "time"
111 |
112 | "github.com/ManuelReschke/go-pd/pkg/pd"
113 | )
114 |
115 | func main() {
116 | req := &pd.RequestUpload{
117 | PathToFile: "testdata/cat.jpg",
118 | Anonymous: true,
119 | }
120 |
121 | c := pd.New(nil, nil)
122 | rsp, err := c.UploadPOST(req)
123 | if err != nil {
124 | fmt.Println(err)
125 | }
126 |
127 | // print the full URL
128 | fmt.Println(rsp.GetFileURL())
129 |
130 | // example ID = xFNz76Vp
131 | // example URL = https://pixeldrain.com/u/xFNz76Vp
132 | }
133 | ```
134 |
135 | ## Example 2 - advanced way - upload a file to user account with progress callback
136 |
137 | ```go
138 | package main
139 |
140 | import (
141 | "fmt"
142 | "time"
143 |
144 | "github.com/ManuelReschke/go-pd/pkg/pd"
145 | "github.com/imroc/req/v3"
146 | )
147 |
148 | func main() {
149 | req := &pd.RequestUpload{
150 | PathToFile: "testdata/cat.jpg",
151 | FileName: "test_post_cat.jpg",
152 | Anonymous: false,
153 | Auth: pd.Auth{
154 | APIKey: "you-api-key-from-pixeldrain-account",
155 | },
156 | }
157 |
158 | // set specific request options
159 | opt := &pd.ClientOptions{
160 | Debug: false,
161 | ProxyURL: "example.socks5.proxy",
162 | EnableCookies: true,
163 | EnableInsecureTLS: true,
164 | Timeout: 1 * time.Hour,
165 | }
166 |
167 | c := pd.New(opt, nil)
168 |
169 | // enable progress
170 | c.SetUploadCallback(func(info req.UploadInfo) {
171 | if info.FileSize > 0 {
172 | fmt.Printf("%q uploaded %.2f%%\n", info.FileName, float64(info.UploadedSize)/float64(info.FileSize)*100.0)
173 | } else {
174 | fmt.Printf("%q uploaded 0%% (file size is zero)\n", info.FileName)
175 | }
176 | })
177 |
178 | rsp, err := c.UploadPOST(req)
179 | if err != nil {
180 | fmt.Println(err)
181 | }
182 |
183 | // print the full URL
184 | fmt.Println(rsp.GetFileURL())
185 |
186 | // example ID = xFNz76Vp
187 | // example URL = https://pixeldrain.com/u/xFNz76Vp
188 | }
189 | ```
190 | ## ToDo's:
191 |
192 | - [x] implement simple upload method over POST /file
193 | - [x] implement simple upload over PUT /file/{filename}
194 | - [x] write unit tests
195 | - [x] write integration tests
196 | - [x] add API-KEY auth to requests
197 | - [x] implement all other API methods
198 | - [x] implement GET - /file/{id}
199 | - [x] implement GET - /file/{id}/info
200 | - [x] implement GET - /file/{id}/thumbnail?width=x&height=x
201 | - [x] implement DELETE - /file/{id}
202 | - [x] implement POST - /list
203 | - [X] implement GET - /list/{id}
204 | - [x] implement GET - /user
205 | - [x] implement GET - /user/files
206 | - [x] implement GET - /user/lists
207 | - [x] create CLI tool for uploading to pixeldrain.com
208 | - [x] update imroc/req to the latest version
209 | - [ ] refactor the hole shit and use nice to have patterns (like Option Pattern)
210 |
211 | ## PixelDrain methods covered by this package
212 |
213 | ### File Methods
214 | | PixelDrain Call | Package Func |
215 | |-------------------------------------------------|---|
216 | | [x] POST - /file | UploadPOST(r *RequestUpload) (*ResponseUpload, error) |
217 | | [x] PUT - /file/{name} | UploadPUT(r *RequestUpload) (*ResponseUpload, error) |
218 | | [x] GET - /file/{id} | Download(r *RequestDownload) (*ResponseDownload, error) |
219 | | [x] GET - /file/{id}/info | GetFileInfo(r *RequestFileInfo) (*ResponseFileInfo, error) |
220 | | [x] GET - /file/{id}/thumbnail?width=x&height=x | DownloadThumbnail(r *RequestThumbnail) (*ResponseThumbnail, error) |
221 | | [x] DELETE - /file/{id} | Delete(r *RequestDelete) (*ResponseDelete, error) |
222 | ### List Methods
223 | | PixelDrain Call | Package Func |
224 | |----------------------|---|
225 | | [x] POST - /list | CreateList(r *RequestCreateList) (*ResponseCreateList, error) |
226 | | [x] GET - /list/{id} | GetList(r *RequestGetList) (*ResponseGetList, error) |
227 | ### User Methods
228 | | PixelDrain Call | Package Func |
229 | |------------------------|---|
230 | | [x] GET - /user | GetUser(r *RequestGetUser) (*ResponseGetUser, error) |
231 | | [x] POST - /user/files | GetUserFiles(r *RequestGetUserFiles) (*ResponseGetUserFiles, error) |
232 | | [x] GET - /user/lists | GetUserLists(r *RequestGetUserLists) (*ResponseGetUserLists, error) |
233 |
234 | ## Package CLI commands
235 |
236 | ### Unit Tests - Run pkg unit tests
237 | Run unit tests against a local emulated server.
238 | ```shell
239 | make test
240 | ```
241 |
242 | ### Integration Tests - Run pkg integration tests
243 | Run real integration tests against the real pixeldrain.com website.
244 | ```shell
245 | make test-integration
246 | ```
247 |
248 | ### Test Coverage - create test coverage report
249 | Create a coverage report c.out and a coverage.html to view the results in web browser
250 | ```shell
251 | make coverage
252 | ```
253 |
254 | ## Thanks to
255 | Special thanks to Visual Studio Code and to Jetbrains for this amazing IDE and [supporting the open source community](https://www.jetbrains.com/de-de/community/opensource/#support).
256 |
257 | ## License
258 |
259 | This software is released under the MIT License, see LICENSE.
260 |
--------------------------------------------------------------------------------
/bin/arm/go-pd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ManuelReschke/go-pd/471b70b89daca049586be995aebf24ab5fc94819/bin/arm/go-pd
--------------------------------------------------------------------------------
/bin/linux/go-pd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ManuelReschke/go-pd/471b70b89daca049586be995aebf24ab5fc94819/bin/linux/go-pd
--------------------------------------------------------------------------------
/bin/windows/go-pd.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ManuelReschke/go-pd/471b70b89daca049586be995aebf24ab5fc94819/bin/windows/go-pd.exe
--------------------------------------------------------------------------------
/cmd/download.go:
--------------------------------------------------------------------------------
1 | package cmd
2 |
3 | import (
4 | "github.com/ManuelReschke/go-pd/internal/app"
5 |
6 | "github.com/spf13/cobra"
7 | )
8 |
9 | const (
10 | cmdDownloadUse = "download"
11 | cmdDownloadShort = "With that command you can download a file"
12 | cmdDownloadLong = "Download file by passing the file url or file id and your API Key with -k"
13 | )
14 |
15 | // downloadCmd represents the upload command
16 | var downloadCmd = &cobra.Command{
17 | Use: cmdDownloadUse,
18 | Short: cmdDownloadShort,
19 | Long: cmdDownloadLong,
20 | RunE: app.RunDownload,
21 | }
22 |
23 | func init() {
24 | rootCmd.AddCommand(downloadCmd)
25 | downloadCmd.Flags().StringP("path", "p", "", "Path where the files are stored")
26 | downloadCmd.Flags().StringP("api-key", "k", "", "Auth key for authentication")
27 | downloadCmd.Flags().BoolP("verbose", "v", true, "Show more information after an upload (Anonymous, ID, URL)")
28 | }
29 |
--------------------------------------------------------------------------------
/cmd/root.go:
--------------------------------------------------------------------------------
1 | package cmd
2 |
3 | import (
4 | "os"
5 |
6 | "github.com/spf13/cobra"
7 | )
8 |
9 | // rootCmd represents the base command when called without any subcommands
10 | var rootCmd = &cobra.Command{
11 | Use: "go-pd",
12 | Short: "go-pd is a CLI tool to manage your pixeldrain.com account via cli.",
13 | Long: `
14 | go-pd is a CLI tool to manage your pixeldrain.com account via cli.
15 |
16 | @Copyright by Manuel Reschke
17 | `,
18 | // Uncomment the following line if your bare application
19 | // has an action associated with it:
20 | // Run: func(cmd *cobra.Command, args []string) { },
21 | }
22 |
23 | // Execute adds all child commands to the root command and sets flags appropriately.
24 | // This is called by main.main(). It only needs to happen once to the rootCmd.
25 | func Execute() {
26 | err := rootCmd.Execute()
27 | if err != nil {
28 | os.Exit(1)
29 | }
30 | }
31 |
32 | func init() {
33 | // Here you will define your flags and configuration settings.
34 | // Cobra supports persistent flags, which, if defined here,
35 | // will be global for your application.
36 |
37 | // rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.go-pd.yaml)")
38 |
39 | // Cobra also supports local flags, which will only run
40 | // when this action is called directly.
41 | //rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
42 | }
43 |
--------------------------------------------------------------------------------
/cmd/upload.go:
--------------------------------------------------------------------------------
1 | package cmd
2 |
3 | import (
4 | "github.com/ManuelReschke/go-pd/internal/app"
5 |
6 | "github.com/spf13/cobra"
7 | )
8 |
9 | const (
10 | cmdUploadUse = "upload"
11 | cmdUploadShort = "With that command you can upload files"
12 | cmdUploadLong = "Upload files by passing the -f flag for your file and your API Key with -k"
13 | )
14 |
15 | // uploadCmd represents the upload command
16 | var uploadCmd = &cobra.Command{
17 | Use: cmdUploadUse,
18 | Short: cmdUploadShort,
19 | Long: cmdUploadLong,
20 | RunE: app.RunUpload,
21 | }
22 |
23 | func init() {
24 | rootCmd.AddCommand(uploadCmd)
25 | uploadCmd.Flags().StringP("api-key", "k", "", "Auth key for authentication")
26 | uploadCmd.Flags().BoolP("verbose", "v", true, "Show more information after an upload (Anonymous, ID, URL)")
27 | }
28 |
--------------------------------------------------------------------------------
/dist/artifacts.json:
--------------------------------------------------------------------------------
1 | [{"name":"go-pd","path":"/home/manuel/Workspace/go/go-pd/dist/go-pd_linux_amd64_v1/go-pd","goos":"linux","goarch":"amd64","goamd64":"v1","type":"Binary","extra":{"Binary":"go-pd","Ext":"","ID":"go-pd"}},{"name":"go-pd","path":"/home/manuel/Workspace/go/go-pd/dist/go-pd_linux_386/go-pd","goos":"linux","goarch":"386","type":"Binary","extra":{"Binary":"go-pd","Ext":"","ID":"go-pd"}},{"name":"go-pd","path":"/home/manuel/Workspace/go/go-pd/dist/go-pd_linux_arm64/go-pd","goos":"linux","goarch":"arm64","type":"Binary","extra":{"Binary":"go-pd","Ext":"","ID":"go-pd"}},{"name":"go-pd","path":"/home/manuel/Workspace/go/go-pd/dist/go-pd_darwin_amd64_v1/go-pd","goos":"darwin","goarch":"amd64","goamd64":"v1","type":"Binary","extra":{"Binary":"go-pd","Ext":"","ID":"go-pd"}},{"name":"go-pd","path":"/home/manuel/Workspace/go/go-pd/dist/go-pd_darwin_arm64/go-pd","goos":"darwin","goarch":"arm64","type":"Binary","extra":{"Binary":"go-pd","Ext":"","ID":"go-pd"}},{"name":"go-pd_1.1.0-SNAPSHOT-85d261a_linux_386.tar.gz","path":"dist/go-pd_1.1.0-SNAPSHOT-85d261a_linux_386.tar.gz","goos":"linux","goarch":"386","type":"Archive","extra":{"Binaries":["go-pd"],"Builds":[{"name":"go-pd","path":"/home/manuel/Workspace/go/go-pd/dist/go-pd_linux_386/go-pd","goos":"linux","goarch":"386","type":"Binary","extra":{"Binary":"go-pd","Ext":"","ID":"go-pd"}}],"Format":"tar.gz","ID":"default","Replaces":null,"WrappedIn":""}},{"name":"go-pd_1.1.0-SNAPSHOT-85d261a_linux_arm64.tar.gz","path":"dist/go-pd_1.1.0-SNAPSHOT-85d261a_linux_arm64.tar.gz","goos":"linux","goarch":"arm64","type":"Archive","extra":{"Binaries":["go-pd"],"Builds":[{"name":"go-pd","path":"/home/manuel/Workspace/go/go-pd/dist/go-pd_linux_arm64/go-pd","goos":"linux","goarch":"arm64","type":"Binary","extra":{"Binary":"go-pd","Ext":"","ID":"go-pd"}}],"Format":"tar.gz","ID":"default","Replaces":null,"WrappedIn":""}},{"name":"go-pd_1.1.0-SNAPSHOT-85d261a_darwin_arm64.tar.gz","path":"dist/go-pd_1.1.0-SNAPSHOT-85d261a_darwin_arm64.tar.gz","goos":"darwin","goarch":"arm64","type":"Archive","extra":{"Binaries":["go-pd"],"Builds":[{"name":"go-pd","path":"/home/manuel/Workspace/go/go-pd/dist/go-pd_darwin_arm64/go-pd","goos":"darwin","goarch":"arm64","type":"Binary","extra":{"Binary":"go-pd","Ext":"","ID":"go-pd"}}],"Format":"tar.gz","ID":"default","Replaces":null,"WrappedIn":""}},{"name":"go-pd_1.1.0-SNAPSHOT-85d261a_darwin_amd64.tar.gz","path":"dist/go-pd_1.1.0-SNAPSHOT-85d261a_darwin_amd64.tar.gz","goos":"darwin","goarch":"amd64","goamd64":"v1","type":"Archive","extra":{"Binaries":["go-pd"],"Builds":[{"name":"go-pd","path":"/home/manuel/Workspace/go/go-pd/dist/go-pd_darwin_amd64_v1/go-pd","goos":"darwin","goarch":"amd64","goamd64":"v1","type":"Binary","extra":{"Binary":"go-pd","Ext":"","ID":"go-pd"}}],"Format":"tar.gz","ID":"default","Replaces":null,"WrappedIn":""}},{"name":"go-pd_1.1.0-SNAPSHOT-85d261a_linux_amd64.tar.gz","path":"dist/go-pd_1.1.0-SNAPSHOT-85d261a_linux_amd64.tar.gz","goos":"linux","goarch":"amd64","goamd64":"v1","type":"Archive","extra":{"Binaries":["go-pd"],"Builds":[{"name":"go-pd","path":"/home/manuel/Workspace/go/go-pd/dist/go-pd_linux_amd64_v1/go-pd","goos":"linux","goarch":"amd64","goamd64":"v1","type":"Binary","extra":{"Binary":"go-pd","Ext":"","ID":"go-pd"}}],"Format":"tar.gz","ID":"default","Replaces":null,"WrappedIn":""}},{"name":"go-pd_1.1.0-SNAPSHOT-85d261a_checksums.txt","path":"dist/go-pd_1.1.0-SNAPSHOT-85d261a_checksums.txt","type":"Checksum","extra":{"Refresh":"func() error"}}]
--------------------------------------------------------------------------------
/dist/config.yaml:
--------------------------------------------------------------------------------
1 | project_name: go-pd
2 | release:
3 | github:
4 | owner: ManuelReschke
5 | name: go-pd
6 | name_template: '{{.Tag}}'
7 | scoop:
8 | name: go-pd
9 | commit_author:
10 | name: goreleaserbot
11 | email: bot@goreleaser.com
12 | commit_msg_template: Scoop update for {{ .ProjectName }} version {{ .Tag }}
13 | goamd64: v1
14 | builds:
15 | - id: go-pd
16 | goos:
17 | - linux
18 | - darwin
19 | - windows
20 | goarch:
21 | - amd64
22 | - arm64
23 | - "386"
24 | goarm:
25 | - 7
26 | gomips:
27 | - hardfloat
28 | goamd64:
29 | - v1
30 | dir: .
31 | main: .
32 | binary: go-pd
33 | builder: go
34 | gobinary: go
35 | command: build
36 | ldflags:
37 | - -s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}} -X main.builtBy=goreleaser
38 | archives:
39 | - id: default
40 | name_template: '{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ with .Arm }}v{{ . }}{{ end }}{{ with .Mips }}_{{ . }}{{ end }}{{ if not (eq .Amd64 "v1") }}{{ .Amd64 }}{{ end }}'
41 | format: tar.gz
42 | files:
43 | - src: license*
44 | - src: LICENSE*
45 | - src: readme*
46 | - src: README*
47 | - src: changelog*
48 | - src: CHANGELOG*
49 | snapshot:
50 | name_template: '{{ .Version }}-SNAPSHOT-{{ .ShortCommit }}'
51 | checksum:
52 | name_template: '{{ .ProjectName }}_{{ .Version }}_checksums.txt'
53 | algorithm: sha256
54 | dist: dist
55 | env_files:
56 | github_token: ~/.config/goreleaser/github_token
57 | gitlab_token: ~/.config/goreleaser/gitlab_token
58 | gitea_token: ~/.config/goreleaser/gitea_token
59 | source:
60 | name_template: '{{ .ProjectName }}-{{ .Version }}'
61 | format: tar.gz
62 | gomod:
63 | gobinary: go
64 | announce:
65 | twitter:
66 | message_template: '{{ .ProjectName }} {{ .Tag }} is out! Check it out at {{ .ReleaseURL }}'
67 | reddit:
68 | title_template: '{{ .ProjectName }} {{ .Tag }} is out!'
69 | url_template: '{{ .ReleaseURL }}'
70 | slack:
71 | message_template: '{{ .ProjectName }} {{ .Tag }} is out! Check it out at {{ .ReleaseURL }}'
72 | username: GoReleaser
73 | discord:
74 | message_template: '{{ .ProjectName }} {{ .Tag }} is out! Check it out at {{ .ReleaseURL }}'
75 | author: GoReleaser
76 | color: "3888754"
77 | icon_url: https://goreleaser.com/static/avatar.png
78 | teams:
79 | title_template: '{{ .ProjectName }} {{ .Tag }} is out!'
80 | message_template: '{{ .ProjectName }} {{ .Tag }} is out! Check it out at {{ .ReleaseURL }}'
81 | color: '#2D313E'
82 | icon_url: https://goreleaser.com/static/avatar.png
83 | smtp:
84 | subject_template: '{{ .ProjectName }} {{ .Tag }} is out!'
85 | body_template: 'You can view details from: {{ .ReleaseURL }}'
86 | mattermost:
87 | message_template: '{{ .ProjectName }} {{ .Tag }} is out! Check it out at {{ .ReleaseURL }}'
88 | title_template: '{{ .ProjectName }} {{ .Tag }} is out!'
89 | username: GoReleaser
90 | linkedin:
91 | message_template: '{{ .ProjectName }} {{ .Tag }} is out! Check it out at {{ .ReleaseURL }}'
92 | telegram:
93 | message_template: '{{ .ProjectName }} {{ .Tag }} is out! Check it out at {{ .ReleaseURL }}'
94 | webhook:
95 | message_template: '{ "message": "{{ .ProjectName }} {{ .Tag }} is out! Check it out at {{ .ReleaseURL }}"}'
96 | content_type: application/json; charset=utf-8
97 | github_urls:
98 | download: https://github.com
99 | gitlab_urls:
100 | download: https://gitlab.com
101 |
--------------------------------------------------------------------------------
/dist/go-pd_1.1.0-SNAPSHOT-85d261a_checksums.txt:
--------------------------------------------------------------------------------
1 | 1de185c883496e85ea02c549e8e84959f22c43c542658934c89f04f67b432a90 go-pd_1.1.0-SNAPSHOT-85d261a_linux_386.tar.gz
2 | a14cc163ce1e54c451f2522b5e99233d25fc24f0b78c7877e47d6f8067a41b65 go-pd_1.1.0-SNAPSHOT-85d261a_linux_amd64.tar.gz
3 | c62389c77ea243fa6025c49bf7c27b49bd3110cb5ac3b1f81fae699dbe6c8650 go-pd_1.1.0-SNAPSHOT-85d261a_darwin_amd64.tar.gz
4 | ee1667dfea2f2e80d0dc4c1a2144c0de2840f6dca96a941e36f8916afd8e8917 go-pd_1.1.0-SNAPSHOT-85d261a_darwin_arm64.tar.gz
5 | f910f67600f6ac80c8c8842f7ce8bdd462fbf2883e257c0dca55bcec16be512c go-pd_1.1.0-SNAPSHOT-85d261a_linux_arm64.tar.gz
6 |
--------------------------------------------------------------------------------
/dist/go-pd_1.1.0-SNAPSHOT-85d261a_darwin_amd64.tar.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ManuelReschke/go-pd/471b70b89daca049586be995aebf24ab5fc94819/dist/go-pd_1.1.0-SNAPSHOT-85d261a_darwin_amd64.tar.gz
--------------------------------------------------------------------------------
/dist/go-pd_1.1.0-SNAPSHOT-85d261a_darwin_arm64.tar.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ManuelReschke/go-pd/471b70b89daca049586be995aebf24ab5fc94819/dist/go-pd_1.1.0-SNAPSHOT-85d261a_darwin_arm64.tar.gz
--------------------------------------------------------------------------------
/dist/go-pd_1.1.0-SNAPSHOT-85d261a_linux_386.tar.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ManuelReschke/go-pd/471b70b89daca049586be995aebf24ab5fc94819/dist/go-pd_1.1.0-SNAPSHOT-85d261a_linux_386.tar.gz
--------------------------------------------------------------------------------
/dist/go-pd_1.1.0-SNAPSHOT-85d261a_linux_amd64.tar.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ManuelReschke/go-pd/471b70b89daca049586be995aebf24ab5fc94819/dist/go-pd_1.1.0-SNAPSHOT-85d261a_linux_amd64.tar.gz
--------------------------------------------------------------------------------
/dist/go-pd_1.1.0-SNAPSHOT-85d261a_linux_arm64.tar.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ManuelReschke/go-pd/471b70b89daca049586be995aebf24ab5fc94819/dist/go-pd_1.1.0-SNAPSHOT-85d261a_linux_arm64.tar.gz
--------------------------------------------------------------------------------
/dist/go-pd_darwin_amd64_v1/go-pd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ManuelReschke/go-pd/471b70b89daca049586be995aebf24ab5fc94819/dist/go-pd_darwin_amd64_v1/go-pd
--------------------------------------------------------------------------------
/dist/go-pd_darwin_arm64/go-pd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ManuelReschke/go-pd/471b70b89daca049586be995aebf24ab5fc94819/dist/go-pd_darwin_arm64/go-pd
--------------------------------------------------------------------------------
/dist/go-pd_linux_386/go-pd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ManuelReschke/go-pd/471b70b89daca049586be995aebf24ab5fc94819/dist/go-pd_linux_386/go-pd
--------------------------------------------------------------------------------
/dist/go-pd_linux_amd64_v1/go-pd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ManuelReschke/go-pd/471b70b89daca049586be995aebf24ab5fc94819/dist/go-pd_linux_amd64_v1/go-pd
--------------------------------------------------------------------------------
/dist/go-pd_linux_arm64/go-pd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ManuelReschke/go-pd/471b70b89daca049586be995aebf24ab5fc94819/dist/go-pd_linux_arm64/go-pd
--------------------------------------------------------------------------------
/dist/metadata.json:
--------------------------------------------------------------------------------
1 | {"project_name":"go-pd","tag":"1.1.0","previous_tag":"1.0.0","version":"1.1.0-SNAPSHOT-85d261a","commit":"85d261a48a0ff7d0c80db5200f09808c71c42268","date":"2022-05-25T11:41:43.172837013+02:00","runtime":{"goos":"linux","goarch":"amd64"}}
--------------------------------------------------------------------------------
/go-pd-upload-and-download.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ManuelReschke/go-pd/471b70b89daca049586be995aebf24ab5fc94819/go-pd-upload-and-download.gif
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/ManuelReschke/go-pd
2 |
3 | go 1.21
4 |
5 | require (
6 | github.com/imroc/req v0.3.2
7 | github.com/imroc/req/v3 v3.43.5
8 | github.com/joho/godotenv v1.4.0
9 | github.com/spf13/cobra v1.8.0
10 | github.com/stretchr/testify v1.8.4
11 | )
12 |
13 | require (
14 | github.com/andybalholm/brotli v1.1.0 // indirect
15 | github.com/cloudflare/circl v1.3.8 // indirect
16 | github.com/davecgh/go-spew v1.1.1 // indirect
17 | github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
18 | github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
19 | github.com/google/pprof v0.0.0-20240509144519-723abb6459b7 // indirect
20 | github.com/hashicorp/errwrap v1.1.0 // indirect
21 | github.com/hashicorp/go-multierror v1.1.1 // indirect
22 | github.com/inconshreveable/mousetrap v1.1.0 // indirect
23 | github.com/klauspost/compress v1.17.8 // indirect
24 | github.com/onsi/ginkgo/v2 v2.17.3 // indirect
25 | github.com/pmezard/go-difflib v1.0.0 // indirect
26 | github.com/quic-go/qpack v0.4.0 // indirect
27 | github.com/quic-go/quic-go v0.44.0 // indirect
28 | github.com/refraction-networking/utls v1.6.6 // indirect
29 | github.com/spf13/pflag v1.0.5 // indirect
30 | go.uber.org/mock v0.4.0 // indirect
31 | golang.org/x/crypto v0.23.0 // indirect
32 | golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // indirect
33 | golang.org/x/mod v0.17.0 // indirect
34 | golang.org/x/net v0.25.0 // indirect
35 | golang.org/x/sys v0.20.0 // indirect
36 | golang.org/x/text v0.15.0 // indirect
37 | golang.org/x/tools v0.21.0 // indirect
38 | gopkg.in/yaml.v3 v3.0.1 // indirect
39 | )
40 |
--------------------------------------------------------------------------------
/go.sum:
--------------------------------------------------------------------------------
1 | github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
2 | github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
3 | github.com/cloudflare/circl v1.3.8 h1:j+V8jJt09PoeMFIu2uh5JUyEaIHTXVOHslFoLNAKqwI=
4 | github.com/cloudflare/circl v1.3.8/go.mod h1:PDRU+oXvdD7KCtgKxW95M5Z8BpSCJXQORiZFnBQS5QU=
5 | github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
6 | github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
7 | github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
8 | github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
9 | github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
10 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
11 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
12 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
13 | github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
14 | github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
15 | github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
16 | github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
17 | github.com/google/pprof v0.0.0-20240509144519-723abb6459b7 h1:velgFPYr1X9TDwLIfkV7fWqsFlf7TeP11M/7kPd/dVI=
18 | github.com/google/pprof v0.0.0-20240509144519-723abb6459b7/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw=
19 | github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
20 | github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
21 | github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
22 | github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
23 | github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
24 | github.com/imroc/req v0.3.2 h1:M/JkeU6RPmX+WYvT2vaaOL0K+q8ufL5LxwvJc4xeB4o=
25 | github.com/imroc/req v0.3.2/go.mod h1:F+NZ+2EFSo6EFXdeIbpfE9hcC233id70kf0byW97Caw=
26 | github.com/imroc/req/v3 v3.43.4 h1:NSXlB5dELZuxzGEFRWLWEQ9dQmh8d9pUMPa7MevK1K4=
27 | github.com/imroc/req/v3 v3.43.4/go.mod h1:SQIz5iYop16MJxbo8ib+4LnostGCok8NQf8ToyQc2xA=
28 | github.com/imroc/req/v3 v3.43.5 h1:fL7dOEfld+iEv1rwnIxseJz2/Y7JZ/HgbAURLZkat80=
29 | github.com/imroc/req/v3 v3.43.5/go.mod h1:SQIz5iYop16MJxbo8ib+4LnostGCok8NQf8ToyQc2xA=
30 | github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
31 | github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
32 | github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
33 | github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
34 | github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
35 | github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg=
36 | github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
37 | github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU=
38 | github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
39 | github.com/onsi/ginkgo/v2 v2.17.3 h1:oJcvKpIb7/8uLpDDtnQuf18xVnwKp8DTD7DQ6gTd/MU=
40 | github.com/onsi/ginkgo/v2 v2.17.3/go.mod h1:nP2DPOQoNsQmsVyv5rDA8JkXQoCs6goXIvr/PRJ1eCc=
41 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
42 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
43 | github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo=
44 | github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A=
45 | github.com/quic-go/quic-go v0.43.1 h1:fLiMNfQVe9q2JvSsiXo4fXOEguXHGGl9+6gLp4RPeZQ=
46 | github.com/quic-go/quic-go v0.43.1/go.mod h1:132kz4kL3F9vxhW3CtQJLDVwcFe5wdWeJXXijhsO57M=
47 | github.com/quic-go/quic-go v0.44.0 h1:So5wOr7jyO4vzL2sd8/pD9Kesciv91zSk8BoFngItQ0=
48 | github.com/quic-go/quic-go v0.44.0/go.mod h1:z4cx/9Ny9UtGITIPzmPTXh1ULfOyWh4qGQlpnPcWmek=
49 | github.com/refraction-networking/utls v1.6.6 h1:igFsYBUJPYM8Rno9xUuDoM5GQrVEqY4llzEXOkL43Ig=
50 | github.com/refraction-networking/utls v1.6.6/go.mod h1:BC3O4vQzye5hqpmDTWUqi4P5DDhzJfkV1tdqtawQIH0=
51 | github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
52 | github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
53 | github.com/spf13/cobra v1.4.0 h1:y+wJpx64xcgO1V+RcnwW0LEHxTKRi2ZDPSBjWnrg88Q=
54 | github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g=
55 | github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA=
56 | github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY=
57 | github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I=
58 | github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0=
59 | github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=
60 | github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=
61 | github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
62 | github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
63 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
64 | github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
65 | github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
66 | github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
67 | github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
68 | github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
69 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
70 | github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
71 | github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
72 | github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
73 | github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
74 | github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
75 | github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
76 | go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU=
77 | go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
78 | golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
79 | golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
80 | golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM=
81 | golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc=
82 | golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
83 | golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
84 | golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
85 | golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
86 | golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
87 | golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
88 | golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
89 | golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
90 | golang.org/x/tools v0.21.0 h1:qc0xYgIbsSDt9EyWz05J5wfa7LOVW0YTLOXrqdLAWIw=
91 | golang.org/x/tools v0.21.0/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
92 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
93 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
94 | gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
95 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
96 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
97 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
98 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
99 |
--------------------------------------------------------------------------------
/internal/app/cmdDownload.go:
--------------------------------------------------------------------------------
1 | package app
2 |
3 | import (
4 | "errors"
5 | "fmt"
6 | "os"
7 | "path/filepath"
8 | "strings"
9 |
10 | "github.com/ManuelReschke/go-pd/pkg/pd"
11 | "github.com/spf13/cobra"
12 | )
13 |
14 | func RunDownload(cmd *cobra.Command, args []string) error {
15 | if len(args) == 0 {
16 | return errors.New("please add a pixeldrain URL or file id to your download request")
17 | }
18 |
19 | path, err := cmd.Flags().GetString("path")
20 | if err != nil {
21 | return errors.New("please add a valid path where you want to save the files")
22 | }
23 | if path == "" {
24 | path, _ = os.Getwd()
25 | }
26 |
27 | apiKey, err := cmd.Flags().GetString("api-key")
28 | if err != nil {
29 | return errors.New("please add a valid API-Key to your request")
30 | }
31 |
32 | // file is here an url or an ID to a file
33 | for _, file := range args {
34 | fileID := file
35 | if strings.ContainsAny(file, pd.BaseURL) {
36 | fileID = filepath.Base(file)
37 | }
38 |
39 | req01 := &pd.RequestFileInfo{
40 | ID: fileID,
41 | }
42 | if apiKey != "" {
43 | req01.Auth.APIKey = apiKey
44 | }
45 |
46 | c := pd.New(nil, nil)
47 | rsp, err := c.GetFileInfo(req01)
48 | if err != nil {
49 | return err
50 | }
51 |
52 | req := &pd.RequestDownload{
53 | ID: fileID,
54 | PathToSave: filepath.FromSlash(path + "/" + rsp.Name),
55 | }
56 | if apiKey != "" {
57 | req.Auth.APIKey = apiKey
58 | }
59 |
60 | rspDL, err := c.Download(req)
61 | if err != nil {
62 | return err
63 | }
64 |
65 | msg := ""
66 | if rspDL.Success {
67 | if cmd.Flags().Changed("verbose") {
68 | msg = fmt.Sprintf("Successful! Download complete: %s | ID: %s | Stored to: %s", rspDL.FileName, req.ID, req.PathToSave)
69 | } else {
70 | msg = fmt.Sprintf("%s", req.PathToSave)
71 | }
72 | } else {
73 | msg = fmt.Sprintf("Failed! ID: %s | Value: %s | Message: %s", req.ID, rspDL.Value, rspDL.Message)
74 | }
75 |
76 | fmt.Println(msg)
77 | }
78 |
79 | return nil
80 | }
81 |
--------------------------------------------------------------------------------
/internal/app/cmdUpload.go:
--------------------------------------------------------------------------------
1 | package app
2 |
3 | import (
4 | "errors"
5 | "fmt"
6 | "os"
7 | "path/filepath"
8 |
9 | "github.com/ManuelReschke/go-pd/pkg/pd"
10 | "github.com/imroc/req/v3"
11 | "github.com/spf13/cobra"
12 | )
13 |
14 | func RunUpload(cmd *cobra.Command, args []string) error {
15 | if len(args) == 0 {
16 | return errors.New("please add a file to your upload request")
17 | }
18 |
19 | verboseFlag := cmd.Flags().Changed("verbose")
20 |
21 | // get key from ENV if available
22 | apiKeyEnv, ok := os.LookupEnv("PIXELDRAIN_API_KEY")
23 | if ok && verboseFlag {
24 | fmt.Println("Using API Key from environment variable: PIXELDRAIN_API_KEY")
25 | }
26 |
27 | apiKeyParam, err := cmd.Flags().GetString("api-key")
28 | if err != nil {
29 | return errors.New("please add a valid API-Key to your upload request")
30 | }
31 |
32 | for _, file := range args {
33 | // check if file exist
34 | if _, err := os.Stat(filepath.FromSlash(file)); errors.Is(err, os.ErrNotExist) {
35 | return errors.New("one of the given files does not exist")
36 | }
37 |
38 | r := &pd.RequestUpload{
39 | PathToFile: file,
40 | Anonymous: true,
41 | }
42 |
43 | if apiKeyEnv != "" {
44 | r.Anonymous = false
45 | r.Auth.APIKey = apiKeyEnv
46 | }
47 | if apiKeyParam != "" {
48 | r.Anonymous = false
49 | r.Auth.APIKey = apiKeyParam
50 | }
51 |
52 | c := pd.New(nil, nil)
53 | if verboseFlag {
54 | c.SetUploadCallback(func(info req.UploadInfo) {
55 | if info.FileSize > 0 {
56 | fmt.Printf("%q uploaded %.2f%%\n", info.FileName, float64(info.UploadedSize)/float64(info.FileSize)*100.0)
57 | } else {
58 | fmt.Printf("%q uploaded 0%% (file size is zero)\n", info.FileName)
59 | }
60 | })
61 | }
62 | rsp, err := c.UploadPOST(r)
63 | if err != nil {
64 | return err
65 | }
66 |
67 | msg := ""
68 | if verboseFlag {
69 | msg = fmt.Sprintf("Successful! Anonymous upload: %v | ID: %s | URL: %s", r.Anonymous, rsp.ID, rsp.GetFileURL())
70 | } else {
71 | msg = fmt.Sprintf("%s", rsp.GetFileURL())
72 | }
73 |
74 | fmt.Println(msg)
75 | }
76 |
77 | return nil
78 | }
79 |
--------------------------------------------------------------------------------
/logo.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ManuelReschke/go-pd/471b70b89daca049586be995aebf24ab5fc94819/logo.jpg
--------------------------------------------------------------------------------
/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import "github.com/ManuelReschke/go-pd/cmd"
4 |
5 | func main() {
6 | cmd.Execute()
7 | }
8 |
--------------------------------------------------------------------------------
/pkg/pd/.env:
--------------------------------------------------------------------------------
1 | API_KEY=""
--------------------------------------------------------------------------------
/pkg/pd/.gitignore:
--------------------------------------------------------------------------------
1 | .vscode
2 | .env_test
3 | testdata/cat_download.jpg
4 | testdata/cat_download_thumbnail.jpg
--------------------------------------------------------------------------------
/pkg/pd/mock_server.go:
--------------------------------------------------------------------------------
1 | package pd
2 |
3 | import (
4 | "io/ioutil"
5 | "log"
6 | "net/http"
7 | "net/http/httptest"
8 | "path/filepath"
9 | "strings"
10 | )
11 |
12 | func MockFileUploadServer() *httptest.Server {
13 | return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
14 |
15 | switch r.Method {
16 | case "POST":
17 | // ##########################################
18 | // POST /file
19 | if r.URL.EscapedPath() == "/file" {
20 | _ = r.ParseMultipartForm(10485760)
21 | file := r.MultipartForm.File["file"]
22 |
23 | if file == nil || len(file) == 0 {
24 | log.Fatalln("Except request to have 'file'")
25 | }
26 |
27 | if r.FormValue("anonymous") == "" {
28 | log.Fatalln("Except request to have form value 'anonymous'")
29 | }
30 |
31 | w.WriteHeader(http.StatusCreated)
32 | str := `{
33 | "success": true,
34 | "id": "123456"
35 | }`
36 | _, _ = w.Write([]byte(str))
37 | }
38 |
39 | // ##########################################
40 | // POST /list
41 | if r.URL.EscapedPath() == "/list" {
42 | _ = r.ParseForm()
43 |
44 | w.WriteHeader(http.StatusOK)
45 | str := `{
46 | "success": true,
47 | "id": "123456"
48 | }`
49 | _, _ = w.Write([]byte(str))
50 | }
51 |
52 | case "PUT":
53 | // ##########################################
54 | // PUT /file/{name}
55 | if !strings.Contains(r.URL.EscapedPath(), "/file/") {
56 | log.Fatalf("wrong path'%s'", r.URL.EscapedPath())
57 | }
58 |
59 | _ = r.ParseForm()
60 |
61 | if r.Body == nil || r.ContentLength == 0 {
62 | log.Fatalln("Empty body in PUT request")
63 | }
64 |
65 | //if r.FormValue("anonymous") == "" {
66 | // log.Fatalln("Except request to have form value 'anonymous'")
67 | //}
68 |
69 | w.WriteHeader(http.StatusCreated)
70 | str := `{
71 | "id": "123456"
72 | }`
73 | _, _ = w.Write([]byte(str))
74 | case "GET":
75 | // ##########################################
76 | // GET /file/{id}
77 | if r.URL.EscapedPath() == "/file/K1dA8U5W" {
78 | _ = r.ParseForm()
79 |
80 | fileID := filepath.Base(r.URL.EscapedPath())
81 | if len(fileID) == 0 {
82 | log.Fatalf("empty file ID '%s'", fileID)
83 | }
84 |
85 | fileContent, err := ioutil.ReadFile("testdata/cat.jpg")
86 | if err != nil {
87 | log.Fatalln(err)
88 | }
89 |
90 | w.WriteHeader(http.StatusOK)
91 | w.Write(fileContent)
92 | }
93 |
94 | // ##########################################
95 | // GET /file/{id}/info
96 | if r.URL.EscapedPath() == "/file/K1dA8U5W/info" {
97 | _ = r.ParseForm()
98 |
99 | w.WriteHeader(http.StatusOK)
100 | str := `{
101 | "id": "K1dA8U5W",
102 | "name": "screenshot.png",
103 | "size": 37621,
104 | "views": 1234,
105 | "bandwidth_used": 1234567890,
106 | "bandwidth_used_paid": 1234567890,
107 | "downloads": 1234,
108 | "date_upload": "2020-02-04T18:34:05.706801Z",
109 | "date_last_view": "2020-02-04T18:34:05.706801Z",
110 | "mime_type": "image/png",
111 | "thumbnail_href": "/file/1234abcd/thumbnail",
112 | "hash_sha256": "1af93d68009bdfd52e1da100a019a30b5fe083d2d1130919225ad0fd3d1fed0b",
113 | "can_edit": true
114 | }`
115 | _, _ = w.Write([]byte(str))
116 | }
117 |
118 | // ##########################################
119 | // GET /file/{id}/thumbnail?width=x&height=x
120 | if r.URL.EscapedPath() == "/file/K1dA8U5W/thumbnail" {
121 | _ = r.ParseForm()
122 |
123 | fileContent, err := ioutil.ReadFile("testdata/cat_thumbnail.jpg")
124 | if err != nil {
125 | log.Fatalln(err)
126 | }
127 |
128 | w.WriteHeader(http.StatusOK)
129 | w.Write(fileContent)
130 | }
131 |
132 | // ##########################################
133 | // GET /list/{id}
134 | if r.URL.EscapedPath() == "/list/123" {
135 | _ = r.ParseForm()
136 |
137 | w.WriteHeader(http.StatusOK)
138 | str := `{
139 | "success": true,
140 | "id": "123",
141 | "title": "Rust in Peace",
142 | "date_created": "2020-02-04T18:34:13.466276Z",
143 | "files": [
144 | {
145 | "detail_href": "/file/_SqVWi/info",
146 | "description": "",
147 | "success": true,
148 | "id": "_SqVWi",
149 | "name": "01 Holy Wars... The Punishment Due.mp3",
150 | "size": 123456,
151 | "date_created": "2020-02-04T18:34:13.466276Z",
152 | "date_last_view": "2020-02-04T18:34:13.466276Z",
153 | "mime_type": "audio/mp3",
154 | "views": 1,
155 | "bandwidth_used": 1234567890,
156 | "thumbnail_href": "/file/_SqVWi/thumbnail"
157 | },
158 | {
159 | "detail_href": "/file/RKwgZb/info",
160 | "description": "",
161 | "success": true,
162 | "id": "RKwgZb",
163 | "name": "02 Hangar 18.mp3",
164 | "size": 123456,
165 | "date_created": "2020-02-04T18:34:13.466276Z",
166 | "date_last_view": "2020-02-04T18:34:13.466276Z",
167 | "mime_type": "audio/mp3",
168 | "views": 2,
169 | "bandwidth_used": 1234567890,
170 | "thumbnail_href": "/file/RKwgZb/thumbnail"
171 | }
172 | ]
173 | }`
174 | _, _ = w.Write([]byte(str))
175 | }
176 |
177 | // ##########################################
178 | // GET /user/files
179 | if r.URL.EscapedPath() == "/user/files" {
180 | _ = r.ParseForm()
181 |
182 | w.WriteHeader(http.StatusOK)
183 | str := `{
184 | "files": [
185 | {
186 | "id": "tUxgDCoQ",
187 | "name": "test_post_cat.jpg",
188 | "size": 37621,
189 | "views": 0,
190 | "bandwidth_used": 0,
191 | "bandwidth_used_paid": 0,
192 | "downloads": 0,
193 | "date_upload": "2022-03-30T16:30:17.152Z",
194 | "date_last_view": "2022-03-30T16:30:17.152Z",
195 | "mime_type": "image/jpeg",
196 | "thumbnail_href": "/file/tUxgDCoQ/thumbnail",
197 | "hash_sha256": "1af93d68009bdfd52e1da100a019a30b5fe083d2d1130919225ad0fd3d1fed0b",
198 | "availability": "",
199 | "availability_message": "",
200 | "abuse_type": "",
201 | "abuse_reporter_name": "",
202 | "can_edit": true,
203 | "show_ads": false,
204 | "allow_video_player": true,
205 | "download_speed_limit": 0
206 | }
207 | ]
208 | }`
209 | _, _ = w.Write([]byte(str))
210 | }
211 |
212 | // ##########################################
213 | // GET /user
214 | if r.URL.EscapedPath() == "/user" {
215 | _ = r.ParseForm()
216 |
217 | w.WriteHeader(http.StatusOK)
218 | str := `{
219 | "username":"TestTest",
220 | "email":"test@test.de",
221 | "subscription":{
222 | "id":"",
223 | "name":"Free",
224 | "type":"",
225 | "file_size_limit":20000000000,
226 | "file_expiry_days":60,
227 | "storage_space":-1,
228 | "price_per_tb_storage":0,
229 | "price_per_tb_bandwidth":0,
230 | "monthly_transfer_cap":0,
231 | "file_viewer_branding":false
232 | },
233 | "storage_space_used":18834,
234 | "is_admin":false,
235 | "balance_micro_eur":0,
236 | "hotlinking_enabled":true,
237 | "monthly_transfer_cap":0,
238 | "monthly_transfer_used":0,
239 | "file_viewer_branding":null,
240 | "file_embed_domains":"",
241 | "skip_file_viewer":false
242 | }`
243 | _, _ = w.Write([]byte(str))
244 | }
245 |
246 | // ##########################################
247 | // GET /user/lists
248 | if r.URL.EscapedPath() == "/user/lists" {
249 | _ = r.ParseForm()
250 |
251 | w.WriteHeader(http.StatusOK)
252 | str := `{
253 | "lists": [
254 | {
255 | "id": "Cap4T1LP",
256 | "title": "Test List",
257 | "date_created": "2022-04-04T15:24:06.834Z",
258 | "file_count": 2,
259 | "files": null,
260 | "can_edit": true
261 | },
262 | {
263 | "id": "fiEm5arj",
264 | "title": "Wallpaper",
265 | "date_created": "2022-04-20T09:46:42.017Z",
266 | "file_count": 2,
267 | "files": null,
268 | "can_edit": true
269 | }
270 | ]
271 | }`
272 | _, _ = w.Write([]byte(str))
273 | }
274 |
275 | return
276 | case "DELETE":
277 | // ##########################################
278 | // DELETE /file/{id}
279 | if r.URL.EscapedPath() == "/file/K1dA8U5W" {
280 |
281 | w.WriteHeader(http.StatusOK)
282 | str := `{
283 | "success": true,
284 | "value": "file_deleted",
285 | "message": "The file has been deleted."
286 | }`
287 | _, _ = w.Write([]byte(str))
288 | }
289 |
290 | return
291 | default:
292 | return
293 | }
294 | }))
295 | }
296 |
--------------------------------------------------------------------------------
/pkg/pd/pd.go:
--------------------------------------------------------------------------------
1 | package pd
2 |
3 | import (
4 | "encoding/base64"
5 | "encoding/json"
6 | "errors"
7 | "fmt"
8 | "log"
9 | "net/http"
10 | "os"
11 | "strconv"
12 | "time"
13 |
14 | "github.com/imroc/req/v3"
15 | )
16 |
17 | const (
18 | Name = "PixelDrain.com"
19 | BaseURL = "https://pixeldrain.com/"
20 | APIURL = BaseURL + "api"
21 | DefaultUserAgent = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.117 Safari/537.36"
22 | // errors
23 | ErrMissingPathToFile = "file path or file reader is required"
24 | ErrMissingFileID = "file id is required"
25 | ErrMissingFilename = "if you use ReadCloser you need to specify the filename"
26 | )
27 |
28 | type ErrorMessage struct {
29 | ErrorCode int `json:"error_code" xml:"ErrorCode"`
30 | ErrorMessage string `json:"error_message" xml:"ErrorMessage"`
31 | }
32 |
33 | type ClientOptions struct {
34 | Debug bool
35 | ProxyURL string
36 | EnableCookies bool
37 | EnableInsecureTLS bool
38 | Timeout time.Duration
39 | }
40 |
41 | type ClientWrapper struct {
42 | Client *req.Client
43 | UploadCallback func(info req.UploadInfo)
44 | }
45 |
46 | type PixelDrainClient struct {
47 | Client *ClientWrapper
48 | Debug bool
49 | }
50 |
51 | // New - create a new PixelDrainClient
52 | func New(opt *ClientOptions, c *ClientWrapper) *PixelDrainClient {
53 | // set default values if no other options available
54 | if opt == nil {
55 | opt = &ClientOptions{
56 | Debug: false,
57 | ProxyURL: "",
58 | EnableCookies: true,
59 | EnableInsecureTLS: true,
60 | Timeout: 1 * time.Hour,
61 | }
62 | }
63 |
64 | // build default client if not available
65 | if c == nil {
66 | client := req.C()
67 | client.SetUserAgent(DefaultUserAgent)
68 |
69 | c = &ClientWrapper{
70 | Client: client,
71 | UploadCallback: nil,
72 | }
73 | }
74 |
75 | if opt.EnableInsecureTLS {
76 | c.Client.EnableInsecureSkipVerify()
77 | }
78 |
79 | if opt.Timeout != 0 {
80 | c.Client.SetTimeout(opt.Timeout)
81 | }
82 |
83 | if opt.ProxyURL != "" {
84 | _ = c.Client.SetProxyURL(opt.ProxyURL)
85 | }
86 | // cookie is available by default in v3
87 | if opt.EnableCookies == false {
88 | c.Client.SetCookieJar(nil)
89 | }
90 |
91 | pdc := &PixelDrainClient{
92 | Client: c,
93 | Debug: opt.Debug,
94 | }
95 |
96 | return pdc
97 | }
98 |
99 | func (pd *PixelDrainClient) SetUploadCallback(callback func(info req.UploadInfo)) {
100 | pd.Client.UploadCallback = callback
101 | }
102 |
103 | // UploadPOST POST /api/file
104 | // curl -X POST -i -H "Authorization: Basic " -F "file=@cat.jpg" https://pixeldrain.com/api/file
105 | func (pd *PixelDrainClient) UploadPOST(r *RequestUpload) (*ResponseUpload, error) {
106 | if r.PathToFile == "" && r.File == nil {
107 | return nil, errors.New(ErrMissingPathToFile)
108 | }
109 |
110 | if r.URL == "" {
111 | r.URL = fmt.Sprint(APIURL + "/file")
112 | }
113 |
114 | if r.File != nil {
115 | if r.FileName == "" {
116 | return nil, errors.New(ErrMissingFilename)
117 | }
118 | } else {
119 | file, err := os.Open(r.PathToFile)
120 | defer file.Close()
121 | if err != nil {
122 | return nil, err
123 | }
124 | }
125 |
126 | headers := map[string]string{}
127 |
128 | // pixeldrain want an empty username and the APIKey as password
129 | if r.Auth.IsAuthAvailable() && !r.Anonymous {
130 | addBasicAuthHeader(headers, "", r.Auth.APIKey)
131 | }
132 |
133 | var uploadRsp ResponseUpload
134 | var errMsg ErrorMessage
135 | rsp, err := pd.Client.Client.R().
136 | SetHeaders(headers).
137 | SetQueryParam("anonymous", strconv.FormatBool(r.Anonymous)).
138 | SetSuccessResult(&uploadRsp).
139 | SetErrorResult(&errMsg).
140 | // currently a bug - https://github.com/imroc/req/issues/352
141 | // SetFileReader("file", r.GetFileName(), r.File).
142 | SetFile("file", r.PathToFile).
143 | SetUploadCallback(pd.Client.UploadCallback).
144 | Post(r.URL)
145 | if pd.Debug && rsp != nil {
146 | log.Println(rsp.Dump())
147 | }
148 | if err != nil {
149 | return nil, err
150 | }
151 |
152 | if rsp != nil && rsp.IsErrorState() { // Status code >= 400.
153 | err = errors.New(errMsg.ErrorMessage)
154 | return nil, err
155 | }
156 |
157 | uploadRsp.StatusCode = rsp.GetStatusCode()
158 |
159 | return &uploadRsp, nil
160 | }
161 |
162 | // UploadPUT PUT /api/file/{name}
163 | // curl -X PUT -i -H "Authorization: Basic " --upload-file cat.jpg https://pixeldrain.com/api/file/test_cat.jpg
164 | func (pd *PixelDrainClient) UploadPUT(r *RequestUpload) (*ResponseUpload, error) {
165 | if r.PathToFile == "" && r.File == nil {
166 | return nil, errors.New(ErrMissingPathToFile)
167 | }
168 |
169 | if r.File == nil && r.FileName == "" {
170 | return nil, errors.New(ErrMissingFilename)
171 | }
172 |
173 | file, err := os.Open(r.PathToFile)
174 | defer file.Close()
175 | if err != nil {
176 | return nil, err
177 | }
178 | r.File = file
179 |
180 | if r.URL == "" {
181 | r.URL = fmt.Sprintf(APIURL+"/file/%s", r.GetFileName())
182 | }
183 |
184 | headers := map[string]string{}
185 |
186 | // pixeldrain want an empty username and the APIKey as password
187 | if r.Auth.IsAuthAvailable() && !r.Anonymous {
188 | addBasicAuthHeader(headers, "", r.Auth.APIKey)
189 | }
190 |
191 | var uploadRsp ResponseUpload
192 | var errMsg ErrorMessage
193 | rsp, err := pd.Client.Client.R().
194 | SetHeaders(headers).
195 | // SetQueryParam("anonymous", strconv.FormatBool(r.Anonymous)).
196 | SetSuccessResult(&uploadRsp).
197 | SetErrorResult(&errMsg).
198 | SetBody(r.File).
199 | SetUploadCallback(pd.Client.UploadCallback).
200 | Put(r.URL)
201 | if pd.Debug && rsp != nil {
202 | log.Println(rsp.Dump())
203 | }
204 | if err != nil {
205 | return nil, err
206 | }
207 |
208 | if rsp != nil && rsp.IsErrorState() { // Status code >= 400.
209 | err = errors.New(errMsg.ErrorMessage)
210 | return nil, err
211 | }
212 |
213 | uploadRsp.StatusCode = rsp.GetStatusCode()
214 |
215 | return &uploadRsp, nil
216 | }
217 |
218 | // Download GET /api/file/{id}
219 | func (pd *PixelDrainClient) Download(r *RequestDownload) (*ResponseDownload, error) {
220 | if r.PathToSave == "" {
221 | return nil, errors.New(ErrMissingPathToFile)
222 | }
223 |
224 | if r.ID == "" {
225 | return nil, errors.New(ErrMissingFileID)
226 | }
227 |
228 | if r.URL == "" {
229 | r.URL = fmt.Sprintf(APIURL+"/file/%s", r.ID)
230 | }
231 |
232 | headers := map[string]string{}
233 | // pixeldrain want an empty username and the APIKey as password
234 | if r.Auth.IsAuthAvailable() {
235 | addBasicAuthHeader(headers, "", r.Auth.APIKey)
236 | }
237 |
238 | var errMsg ErrorMessage
239 | rsp, err := pd.Client.Client.R().
240 | SetHeaders(headers).
241 | SetErrorResult(&errMsg).
242 | SetOutputFile(r.PathToSave).
243 | SetRetryCount(5).
244 | SetRetryFixedInterval(3 * time.Second).
245 | Get(r.URL)
246 | if pd.Debug && rsp != nil {
247 | log.Println(rsp.Dump())
248 | }
249 | if err != nil {
250 | return nil, err
251 | }
252 |
253 | if rsp != nil && rsp.IsErrorState() { // Status code >= 400.
254 | err = errors.New(errMsg.ErrorMessage)
255 | return nil, err
256 | }
257 |
258 | if rsp.GetStatusCode() != 200 {
259 | defaultRsp := &ResponseDefault{}
260 | defaultRsp.StatusCode = rsp.GetStatusCode()
261 | defaultRsp.Success = false
262 | downloadRsp := &ResponseDownload{
263 | ResponseDefault: *defaultRsp,
264 | }
265 |
266 | return downloadRsp, nil
267 | }
268 |
269 | fInfo, err := os.Stat(r.PathToSave)
270 | if err != nil {
271 | return nil, err
272 | }
273 |
274 | downloadRsp := &ResponseDownload{
275 | FilePath: r.PathToSave,
276 | FileName: fInfo.Name(),
277 | FileSize: fInfo.Size(),
278 | ResponseDefault: ResponseDefault{
279 | StatusCode: rsp.GetStatusCode(),
280 | Success: true,
281 | },
282 | }
283 |
284 | return downloadRsp, nil
285 | }
286 |
287 | // GetFileInfo GET /api/file/{id}/info
288 | func (pd *PixelDrainClient) GetFileInfo(r *RequestFileInfo) (*ResponseFileInfo, error) {
289 | if r.ID == "" {
290 | return nil, errors.New(ErrMissingFileID)
291 | }
292 |
293 | if r.URL == "" {
294 | r.URL = fmt.Sprintf(APIURL+"/file/%s/info", r.ID)
295 | }
296 |
297 | headers := map[string]string{}
298 | // pixeldrain want an empty username and the APIKey as password
299 | if r.Auth.IsAuthAvailable() {
300 | addBasicAuthHeader(headers, "", r.Auth.APIKey)
301 | }
302 |
303 | var fileInfoRsp ResponseFileInfo
304 | var errMsg ErrorMessage
305 | rsp, err := pd.Client.Client.R().
306 | SetHeaders(headers).
307 | SetSuccessResult(&fileInfoRsp).
308 | SetErrorResult(&errMsg).
309 | Get(r.URL)
310 | if pd.Debug && rsp != nil {
311 | log.Println(rsp.Dump())
312 | }
313 | if err != nil {
314 | return nil, err
315 | }
316 |
317 | if rsp != nil && rsp.IsErrorState() { // Status code >= 400.
318 | err = errors.New(errMsg.ErrorMessage)
319 | return nil, err
320 | }
321 |
322 | fileInfoRsp.StatusCode = rsp.GetStatusCode()
323 | if fileInfoRsp.StatusCode == http.StatusOK {
324 | fileInfoRsp.Success = true
325 | }
326 |
327 | return &fileInfoRsp, nil
328 | }
329 |
330 | // DownloadThumbnail GET /api/file/{id}/thumbnail?width=x&height=x
331 | func (pd *PixelDrainClient) DownloadThumbnail(r *RequestThumbnail) (*ResponseThumbnail, error) {
332 | if r.PathToSave == "" {
333 | return nil, errors.New(ErrMissingPathToFile)
334 | }
335 |
336 | if r.ID == "" {
337 | return nil, errors.New(ErrMissingFileID)
338 | }
339 |
340 | if r.URL == "" {
341 | r.URL = fmt.Sprintf(APIURL+"/file/%s/thumbnail", r.ID)
342 | }
343 |
344 | queryParams := map[string]string{}
345 | if r.Width != "" {
346 | queryParams["width"] = r.Width
347 | }
348 | if r.Height != "" {
349 | queryParams["height"] = r.Height
350 | }
351 |
352 | headers := map[string]string{}
353 | // pixeldrain want an empty username and the APIKey as password
354 | if r.Auth.IsAuthAvailable() {
355 | addBasicAuthHeader(headers, "", r.Auth.APIKey)
356 | }
357 |
358 | var errMsg ErrorMessage
359 | rsp, err := pd.Client.Client.R().
360 | SetQueryParams(queryParams).
361 | SetHeaders(headers).
362 | SetErrorResult(&errMsg).
363 | SetOutputFile(r.PathToSave).
364 | Get(r.URL)
365 | if pd.Debug && rsp != nil {
366 | log.Println(rsp.Dump())
367 | }
368 | if err != nil {
369 | return nil, err
370 | }
371 |
372 | if rsp != nil && rsp.IsErrorState() { // Status code >= 400.
373 | err = errors.New(errMsg.ErrorMessage)
374 | return nil, err
375 | }
376 |
377 | fInfo, err := os.Stat(r.PathToSave)
378 | if err != nil {
379 | return nil, err
380 | }
381 |
382 | rspStruct := &ResponseThumbnail{
383 | FilePath: r.PathToSave,
384 | FileName: fInfo.Name(),
385 | FileSize: fInfo.Size(),
386 | ResponseDefault: ResponseDefault{
387 | StatusCode: rsp.GetStatusCode(),
388 | Success: true,
389 | },
390 | }
391 |
392 | return rspStruct, nil
393 | }
394 |
395 | // Delete DELETE /api/file/{id}
396 | func (pd *PixelDrainClient) Delete(r *RequestDelete) (*ResponseDelete, error) {
397 | if r.ID == "" {
398 | return nil, errors.New(ErrMissingFileID)
399 | }
400 |
401 | if r.URL == "" {
402 | r.URL = fmt.Sprintf(APIURL+"/file/%s", r.ID)
403 | }
404 |
405 | headers := map[string]string{}
406 | // pixeldrain want an empty username and the APIKey as password
407 | if r.Auth.IsAuthAvailable() {
408 | addBasicAuthHeader(headers, "", r.Auth.APIKey)
409 | }
410 |
411 | var rspStruct ResponseDelete
412 | var errMsg ErrorMessage
413 | rsp, err := pd.Client.Client.R().
414 | SetHeaders(headers).
415 | SetSuccessResult(&rspStruct).
416 | SetErrorResult(&errMsg).
417 | Delete(r.URL)
418 | if pd.Debug && rsp != nil {
419 | log.Println(rsp.Dump())
420 | }
421 | if err != nil {
422 | return nil, err
423 | }
424 |
425 | if rsp != nil && rsp.IsErrorState() { // Status code >= 400.
426 | err = errors.New(errMsg.ErrorMessage)
427 | return nil, err
428 | }
429 |
430 | rspStruct.StatusCode = rsp.GetStatusCode()
431 |
432 | return &rspStruct, nil
433 | }
434 |
435 | // CreateList POST /api/list
436 | func (pd *PixelDrainClient) CreateList(r *RequestCreateList) (*ResponseCreateList, error) {
437 | if r.URL == "" {
438 | r.URL = APIURL + "/list"
439 | }
440 |
441 | headers := map[string]string{}
442 | // pixeldrain want an empty username and the APIKey as password
443 | if r.Auth.IsAuthAvailable() {
444 | addBasicAuthHeader(headers, "", r.Auth.APIKey)
445 | }
446 |
447 | data, err := json.Marshal(r)
448 | if err != nil {
449 | return nil, err
450 | }
451 |
452 | var rspStruct ResponseCreateList
453 | var errMsg ErrorMessage
454 | rsp, err := pd.Client.Client.R().
455 | SetHeaders(headers).
456 | SetBodyJsonBytes(data).
457 | SetSuccessResult(&rspStruct).
458 | SetErrorResult(&errMsg).
459 | Post(r.URL)
460 | if pd.Debug && rsp != nil {
461 | log.Println(rsp.Dump())
462 | }
463 | if err != nil {
464 | return nil, err
465 | }
466 |
467 | if rsp != nil && rsp.IsErrorState() { // Status code >= 400.
468 | err = errors.New(errMsg.ErrorMessage)
469 | return nil, err
470 | }
471 |
472 | rspStruct.StatusCode = rsp.GetStatusCode()
473 |
474 | return &rspStruct, nil
475 | }
476 |
477 | // GetList GET /api/list/{id}
478 | func (pd *PixelDrainClient) GetList(r *RequestGetList) (*ResponseGetList, error) {
479 | if r.ID == "" {
480 | return nil, errors.New(ErrMissingFileID)
481 | }
482 |
483 | if r.URL == "" {
484 | r.URL = fmt.Sprintf(APIURL+"/list/%s", r.ID)
485 | }
486 |
487 | headers := map[string]string{}
488 | // pixeldrain want an empty username and the APIKey as password
489 | if r.Auth.IsAuthAvailable() {
490 | addBasicAuthHeader(headers, "", r.Auth.APIKey)
491 | }
492 |
493 | var rspStruct ResponseGetList
494 | var errMsg ErrorMessage
495 | rsp, err := pd.Client.Client.R().
496 | SetHeaders(headers).
497 | SetSuccessResult(&rspStruct).
498 | SetErrorResult(&errMsg).
499 | Get(r.URL)
500 | if pd.Debug && rsp != nil {
501 | log.Println(rsp.Dump())
502 | }
503 | if err != nil {
504 | return nil, err
505 | }
506 |
507 | if rsp != nil && rsp.IsErrorState() { // Status code >= 400.
508 | err = errors.New(errMsg.ErrorMessage)
509 | return nil, err
510 | }
511 |
512 | rspStruct.StatusCode = rsp.GetStatusCode()
513 |
514 | return &rspStruct, nil
515 | }
516 |
517 | // GetUser GET /api/user
518 | func (pd *PixelDrainClient) GetUser(r *RequestGetUser) (*ResponseGetUser, error) {
519 | if r.URL == "" {
520 | r.URL = APIURL + "/user"
521 | }
522 |
523 | headers := map[string]string{}
524 | // pixeldrain want an empty username and the APIKey as password
525 | if r.Auth.IsAuthAvailable() {
526 | addBasicAuthHeader(headers, "", r.Auth.APIKey)
527 | }
528 |
529 | var rspStruct ResponseGetUser
530 | var errMsg ErrorMessage
531 | rsp, err := pd.Client.Client.R().
532 | SetHeaders(headers).
533 | SetSuccessResult(&rspStruct).
534 | SetErrorResult(&errMsg).
535 | Get(r.URL)
536 | if pd.Debug && rsp != nil {
537 | log.Println(rsp.Dump())
538 | }
539 | if err != nil {
540 | return nil, err
541 | }
542 |
543 | if rsp != nil && rsp.IsErrorState() { // Status code >= 400.
544 | err = errors.New(errMsg.ErrorMessage)
545 | return nil, err
546 | }
547 |
548 | status := false
549 | if rsp.GetStatusCode() == http.StatusOK {
550 | status = true
551 | }
552 |
553 | rspStruct.Success = status
554 | rspStruct.StatusCode = rsp.GetStatusCode()
555 |
556 | return &rspStruct, nil
557 | }
558 |
559 | // GetUserFiles GET /api/user/files
560 | func (pd *PixelDrainClient) GetUserFiles(r *RequestGetUserFiles) (*ResponseGetUserFiles, error) {
561 | if r.URL == "" {
562 | r.URL = APIURL + "/user/files"
563 | }
564 |
565 | headers := map[string]string{}
566 | // pixeldrain want an empty username and the APIKey as password
567 | if r.Auth.IsAuthAvailable() {
568 | addBasicAuthHeader(headers, "", r.Auth.APIKey)
569 | }
570 |
571 | var rspStruct ResponseGetUserFiles
572 | var errMsg ErrorMessage
573 | rsp, err := pd.Client.Client.R().
574 | SetHeaders(headers).
575 | SetSuccessResult(&rspStruct).
576 | SetErrorResult(&errMsg).
577 | Get(r.URL)
578 | if pd.Debug && rsp != nil {
579 | log.Println(rsp.Dump())
580 | }
581 | if err != nil {
582 | return nil, err
583 | }
584 |
585 | if rsp != nil && rsp.IsErrorState() { // Status code >= 400.
586 | err = errors.New(errMsg.ErrorMessage)
587 | return nil, err
588 | }
589 |
590 | status := false
591 | if rsp.GetStatusCode() == http.StatusOK {
592 | status = true
593 | }
594 |
595 | rspStruct.Success = status
596 | rspStruct.StatusCode = rsp.GetStatusCode()
597 |
598 | return &rspStruct, nil
599 | }
600 |
601 | // GetUserLists GET /api/user/lists
602 | func (pd *PixelDrainClient) GetUserLists(r *RequestGetUserLists) (*ResponseGetUserLists, error) {
603 | if r.URL == "" {
604 | r.URL = APIURL + "/user/lists"
605 | }
606 |
607 | headers := map[string]string{}
608 | // pixeldrain want an empty username and the APIKey as password
609 | if r.Auth.IsAuthAvailable() {
610 | addBasicAuthHeader(headers, "", r.Auth.APIKey)
611 | }
612 |
613 | var rspStruct ResponseGetUserLists
614 | var errMsg ErrorMessage
615 | rsp, err := pd.Client.Client.R().
616 | SetHeaders(headers).
617 | SetSuccessResult(&rspStruct).
618 | SetErrorResult(&errMsg).
619 | Get(r.URL)
620 | if pd.Debug && rsp != nil {
621 | log.Println(rsp.Dump())
622 | }
623 | if err != nil {
624 | return nil, err
625 | }
626 |
627 | if rsp != nil && rsp.IsErrorState() { // Status code >= 400.
628 | err = errors.New(errMsg.ErrorMessage)
629 | return nil, err
630 | }
631 |
632 | status := false
633 | if rsp.GetStatusCode() == http.StatusOK {
634 | status = true
635 | }
636 |
637 | rspStruct.Success = status
638 | rspStruct.StatusCode = rsp.GetStatusCode()
639 |
640 | return &rspStruct, nil
641 | }
642 |
643 | // pixeldrain want an empty username and the APIKey as password
644 | // addBasicAuthHeader create a http basic auth header from username and password
645 | func addBasicAuthHeader(h map[string]string, u string, p string) map[string]string {
646 | h["Authorization"] = "Basic " + generateBasicAuthToken(u, p)
647 |
648 | return h
649 | }
650 |
651 | // generateBasicAuthToken generate string for basic auth header
652 | func generateBasicAuthToken(u string, p string) string {
653 | auth := u + ":" + p
654 |
655 | return base64.StdEncoding.EncodeToString([]byte(auth))
656 | }
657 |
--------------------------------------------------------------------------------
/pkg/pd/pd_test.go:
--------------------------------------------------------------------------------
1 | package pd_test
2 |
3 | import (
4 | "fmt"
5 | "os"
6 | "testing"
7 |
8 | "github.com/ManuelReschke/go-pd/pkg/pd"
9 | "github.com/joho/godotenv"
10 | "github.com/stretchr/testify/assert"
11 | )
12 |
13 | const SkipIntegrationTest = "skipping integration test"
14 |
15 | var fileIDPost string
16 | var fileIDPut string
17 | var listID string
18 |
19 | // TestPD_UploadPOST is a unit test for the POST upload method
20 | func TestPD_UploadPOST(t *testing.T) {
21 | server := pd.MockFileUploadServer()
22 | defer server.Close()
23 | testURL := server.URL + "/file"
24 |
25 | rq := &pd.RequestUpload{
26 | PathToFile: "testdata/cat.jpg",
27 | FileName: "test_post_cat.jpg",
28 | Anonymous: true,
29 | URL: testURL,
30 | }
31 |
32 | c := pd.New(nil, nil)
33 | rsp, err := c.UploadPOST(rq)
34 | if err != nil {
35 | t.Error(err)
36 | }
37 |
38 | assert.Equal(t, 201, rsp.StatusCode)
39 | assert.NotEmpty(t, rsp.ID)
40 | assert.Equal(t, "https://pixeldrain.com/u/123456", rsp.GetFileURL())
41 | fmt.Println("POST Req: " + rsp.GetFileURL())
42 | }
43 |
44 | // TestPD_UploadPOST_Integration run a real integration test against the service
45 | func TestPD_UploadPOST_Integration(t *testing.T) {
46 | if testing.Short() {
47 | t.Skip(SkipIntegrationTest)
48 | }
49 |
50 | rq := &pd.RequestUpload{
51 | PathToFile: "testdata/cat.jpg",
52 | FileName: "test_post_cat.jpg",
53 | }
54 |
55 | rq.Auth = setAuthFromEnv()
56 |
57 | c := pd.New(nil, nil)
58 | rsp, err := c.UploadPOST(rq)
59 | if err != nil {
60 | t.Error(err)
61 | }
62 |
63 | assert.Equal(t, 201, rsp.StatusCode)
64 | assert.NotEmpty(t, rsp.ID)
65 | assert.True(t, rsp.Success)
66 | fileIDPost = rsp.ID
67 | fmt.Println("POST Req: " + rsp.GetFileURL())
68 | }
69 |
70 | // currently not supported
71 | //
72 | // // TestPD_UploadPOST_WithReadCloser_Integration run a real integration test against the service
73 | // func TestPD_UploadPOST_WithReadCloser_Integration(t *testing.T) {
74 | // if testing.Short() {
75 | // t.Skip(SkipIntegrationTest)
76 | // }
77 | //
78 | // // ReadCloser
79 | // file, _ := os.Open("testdata/cat.jpg")
80 | //
81 | // req := &pd.RequestUpload{
82 | // File: file,
83 | // FileName: "test_post_cat.jpg",
84 | // }
85 | //
86 | // req.Auth = setAuthFromEnv()
87 | //
88 | // c := pd.New(nil, nil)
89 | // rsp, err := c.UploadPOST(req)
90 | // if err != nil {
91 | // t.Error(err)
92 | // }
93 | //
94 | // assert.Equal(t, 201, rsp.StatusCode)
95 | // assert.NotEmpty(t, rsp.ID)
96 | // fmt.Println("POST Req: " + rsp.GetFileURL())
97 | // }
98 |
99 | // TestPD_UploadPUT is a unit test for the PUT upload method
100 | func TestPD_UploadPUT(t *testing.T) {
101 | server := pd.MockFileUploadServer()
102 | defer server.Close()
103 | testURL := server.URL + "/file/"
104 |
105 | req := &pd.RequestUpload{
106 | PathToFile: "testdata/cat.jpg",
107 | FileName: "test_put_cat.jpg",
108 | Anonymous: true,
109 | URL: testURL + "test_put_cat.jpg",
110 | }
111 |
112 | c := pd.New(nil, nil)
113 | rsp, err := c.UploadPUT(req)
114 | if err != nil {
115 | t.Error(err)
116 | }
117 |
118 | assert.Equal(t, 201, rsp.StatusCode)
119 | assert.NotEmpty(t, rsp.ID)
120 | assert.Equal(t, "https://pixeldrain.com/u/123456", rsp.GetFileURL())
121 | fmt.Println("PUT Req: " + rsp.GetFileURL())
122 | }
123 |
124 | // TestPD_UploadPUT_Integration run a real integration test against the service
125 | func TestPD_UploadPUT_Integration(t *testing.T) {
126 | if testing.Short() {
127 | t.Skip(SkipIntegrationTest)
128 | }
129 |
130 | req := &pd.RequestUpload{
131 | PathToFile: "testdata/cat.jpg",
132 | FileName: "test_put_cat.jpg",
133 | }
134 |
135 | req.Auth = setAuthFromEnv()
136 |
137 | c := pd.New(nil, nil)
138 | rsp, err := c.UploadPUT(req)
139 | if err != nil {
140 | t.Error(err)
141 | }
142 |
143 | assert.Equal(t, 201, rsp.StatusCode)
144 | assert.NotEmpty(t, rsp.ID)
145 | fileIDPut = rsp.ID
146 | fmt.Println("PUT Req: " + rsp.GetFileURL())
147 | }
148 |
149 | // TestPD_Download is a unit test for the GET "download" method
150 | func TestPD_Download(t *testing.T) {
151 | server := pd.MockFileUploadServer()
152 | defer server.Close()
153 | testURL := server.URL + "/file/K1dA8U5W"
154 |
155 | req := &pd.RequestDownload{
156 | PathToSave: "testdata/cat_download.jpg",
157 | ID: "K1dA8U5W",
158 | URL: testURL,
159 | }
160 |
161 | c := pd.New(nil, nil)
162 | rsp, err := c.Download(req)
163 | if err != nil {
164 | t.Error(err)
165 | }
166 |
167 | assert.Equal(t, 200, rsp.StatusCode)
168 | assert.Equal(t, true, rsp.Success)
169 | }
170 |
171 | // TestPD_Download_Integration run a real integration test against the service
172 | func TestPD_Download_Integration(t *testing.T) {
173 | if testing.Short() {
174 | t.Skip(SkipIntegrationTest)
175 | }
176 |
177 | req := &pd.RequestDownload{
178 | PathToSave: "testdata/cat_download.jpg",
179 | ID: fileIDPost,
180 | }
181 |
182 | req.Auth = setAuthFromEnv()
183 |
184 | c := pd.New(nil, nil)
185 | rsp, err := c.Download(req)
186 | if err != nil {
187 | t.Error(err)
188 | }
189 |
190 | assert.Equal(t, 200, rsp.StatusCode)
191 | assert.Equal(t, "cat_download.jpg", rsp.FileName)
192 | assert.Equal(t, int64(37621), rsp.FileSize)
193 | }
194 |
195 | // TestPD_GetFileInfo is a unit test for the GET "file info" method
196 | func TestPD_GetFileInfo(t *testing.T) {
197 | server := pd.MockFileUploadServer()
198 | defer server.Close()
199 | testURL := server.URL + "/file/K1dA8U5W/info"
200 |
201 | req := &pd.RequestFileInfo{
202 | ID: "K1dA8U5W",
203 | URL: testURL,
204 | }
205 |
206 | c := pd.New(nil, nil)
207 | rsp, err := c.GetFileInfo(req)
208 | if err != nil {
209 | t.Error(err)
210 | }
211 |
212 | assert.Equal(t, 200, rsp.StatusCode)
213 | assert.Equal(t, true, rsp.Success)
214 | assert.Equal(t, "K1dA8U5W", rsp.ID)
215 | assert.Equal(t, int64(37621), rsp.Size)
216 | assert.Equal(t, "1af93d68009bdfd52e1da100a019a30b5fe083d2d1130919225ad0fd3d1fed0b", rsp.HashSha256)
217 | }
218 |
219 | // TestPD_GetFileInfo_Integration run a real integration test against the service
220 | func TestPD_GetFileInfo_Integration(t *testing.T) {
221 | if testing.Short() {
222 | t.Skip(SkipIntegrationTest)
223 | }
224 |
225 | req := &pd.RequestFileInfo{
226 | ID: fileIDPost,
227 | }
228 |
229 | req.Auth = setAuthFromEnv()
230 |
231 | c := pd.New(nil, nil)
232 | rsp, err := c.GetFileInfo(req)
233 | if err != nil {
234 | t.Error(err)
235 | }
236 |
237 | assert.Equal(t, 200, rsp.StatusCode)
238 | assert.Equal(t, true, rsp.Success)
239 | assert.Equal(t, fileIDPost, rsp.ID)
240 | assert.Equal(t, int64(37621), rsp.Size)
241 | assert.Equal(t, "1af93d68009bdfd52e1da100a019a30b5fe083d2d1130919225ad0fd3d1fed0b", rsp.HashSha256)
242 | }
243 |
244 | // TestPD_DownloadThumbnail is a unit test for the GET "download thumbnail" method
245 | func TestPD_DownloadThumbnail(t *testing.T) {
246 | server := pd.MockFileUploadServer()
247 | defer server.Close()
248 | testURL := server.URL + "/file/K1dA8U5W/thumbnail?width=64&height=64"
249 |
250 | req := &pd.RequestThumbnail{
251 | ID: "K1dA8U5W",
252 | Height: "64",
253 | Width: "64",
254 | PathToSave: "testdata/cat_download_thumbnail.jpg",
255 | URL: testURL,
256 | }
257 |
258 | req.Auth = setAuthFromEnv()
259 |
260 | c := pd.New(nil, nil)
261 | rsp, err := c.DownloadThumbnail(req)
262 | if err != nil {
263 | t.Error(err)
264 | }
265 |
266 | assert.Equal(t, 200, rsp.StatusCode)
267 | assert.Equal(t, "cat_download_thumbnail.jpg", rsp.FileName)
268 | assert.Equal(t, int64(7056), rsp.FileSize)
269 | }
270 |
271 | // TestPD_DownloadThumbnail_Integration run a real integration test against the service
272 | func TestPD_DownloadThumbnail_Integration(t *testing.T) {
273 | if testing.Short() {
274 | t.Skip(SkipIntegrationTest)
275 | }
276 |
277 | req := &pd.RequestThumbnail{
278 | ID: fileIDPost,
279 | Height: "64",
280 | Width: "64",
281 | PathToSave: "testdata/cat_download_thumbnail.jpg",
282 | }
283 |
284 | req.Auth = setAuthFromEnv()
285 |
286 | c := pd.New(nil, nil)
287 | rsp, err := c.DownloadThumbnail(req)
288 | if err != nil {
289 | t.Error(err)
290 | }
291 |
292 | assert.Equal(t, 200, rsp.StatusCode)
293 | assert.Equal(t, "cat_download_thumbnail.jpg", rsp.FileName)
294 | assert.Equal(t, int64(7056), rsp.FileSize)
295 | }
296 |
297 | // TestPD_CreateList is a unit test for the POST "list" method
298 | func TestPD_CreateList(t *testing.T) {
299 | server := pd.MockFileUploadServer()
300 | defer server.Close()
301 | testURL := server.URL + "/list"
302 |
303 | // files to add
304 | files := []pd.ListFile{
305 | {ID: "K1dA8U5W", Description: "Hallo Welt"},
306 | {ID: "bmrc4iyD", Description: "Hallo Welt 2"},
307 | }
308 |
309 | // create list request
310 | req := &pd.RequestCreateList{
311 | Title: "Test List",
312 | Anonymous: false,
313 | Files: files,
314 | URL: testURL,
315 | }
316 |
317 | req.Auth = setAuthFromEnv()
318 |
319 | c := pd.New(nil, nil)
320 | rsp, err := c.CreateList(req)
321 | if err != nil {
322 | t.Error(err)
323 | }
324 |
325 | assert.Equal(t, 200, rsp.StatusCode)
326 | assert.Equal(t, true, rsp.Success)
327 | assert.NotEmpty(t, rsp.ID)
328 | }
329 |
330 | // TestPD_Delete_Integration run a real integration test against the service
331 | func TestPD_CreateList_Integration(t *testing.T) {
332 | if testing.Short() {
333 | t.Skip(SkipIntegrationTest)
334 | }
335 |
336 | // files to add
337 | files := []pd.ListFile{
338 | {ID: fileIDPost, Description: "Hallo Welt"},
339 | {ID: fileIDPut, Description: "Hallo Welt 2"},
340 | }
341 |
342 | // create list request
343 | req := &pd.RequestCreateList{
344 | Title: "Test List",
345 | Anonymous: false,
346 | Files: files,
347 | }
348 |
349 | req.Auth = setAuthFromEnv()
350 |
351 | c := pd.New(nil, nil)
352 | rsp, err := c.CreateList(req)
353 | if err != nil {
354 | t.Error(err)
355 | }
356 |
357 | assert.Equal(t, 201, rsp.StatusCode)
358 | assert.Equal(t, true, rsp.Success)
359 | listID = rsp.ID
360 | }
361 |
362 | // TestPD_GetList is a unit test for the GET "list/{id}" method
363 | func TestPD_GetList(t *testing.T) {
364 | server := pd.MockFileUploadServer()
365 | defer server.Close()
366 | testURL := server.URL + "/list/123"
367 |
368 | req := &pd.RequestGetList{
369 | ID: "123",
370 | URL: testURL,
371 | }
372 |
373 | req.Auth = setAuthFromEnv()
374 |
375 | c := pd.New(nil, nil)
376 | rsp, err := c.GetList(req)
377 | if err != nil {
378 | t.Error(err)
379 | }
380 |
381 | assert.Equal(t, 200, rsp.StatusCode)
382 | assert.Equal(t, true, rsp.Success)
383 | assert.NotEmpty(t, rsp.ID)
384 | assert.Equal(t, "Rust in Peace", rsp.Title)
385 | assert.Equal(t, int64(123456), rsp.Files[0].Size)
386 | }
387 |
388 | // TestPD_GetList_Integration run a real integration test against the service
389 | func TestPD_GetList_Integration(t *testing.T) {
390 | if testing.Short() {
391 | t.Skip(SkipIntegrationTest)
392 | }
393 |
394 | req := &pd.RequestGetList{
395 | ID: listID,
396 | }
397 |
398 | req.Auth = setAuthFromEnv()
399 |
400 | c := pd.New(nil, nil)
401 | rsp, err := c.GetList(req)
402 | if err != nil {
403 | t.Error(err)
404 | }
405 |
406 | assert.Equal(t, 200, rsp.StatusCode)
407 | assert.Equal(t, true, rsp.Success)
408 | assert.NotEmpty(t, rsp.ID)
409 | assert.Equal(t, "Test List", rsp.Title)
410 | assert.Equal(t, int64(37621), rsp.Files[0].Size)
411 | }
412 |
413 | // TestPD_GetUser is a unit test for the GET "/user" method
414 | func TestPD_GetUser(t *testing.T) {
415 | server := pd.MockFileUploadServer()
416 | defer server.Close()
417 | testURL := server.URL + "/user"
418 |
419 | req := &pd.RequestGetUser{
420 | URL: testURL,
421 | }
422 |
423 | req.Auth = setAuthFromEnv()
424 |
425 | c := pd.New(nil, nil)
426 | rsp, err := c.GetUser(req)
427 | if err != nil {
428 | t.Error(err)
429 | }
430 |
431 | assert.Equal(t, 200, rsp.StatusCode)
432 | assert.Equal(t, true, rsp.Success)
433 | assert.Equal(t, "TestTest", rsp.Username)
434 | assert.Equal(t, "Free", rsp.Subscription.Name)
435 | }
436 |
437 | // TestPD_GetUser_Integration run a real integration test against the service
438 | func TestPD_GetUser_Integration(t *testing.T) {
439 | if testing.Short() {
440 | t.Skip(SkipIntegrationTest)
441 | }
442 |
443 | req := &pd.RequestGetUser{}
444 |
445 | req.Auth = setAuthFromEnv()
446 |
447 | c := pd.New(nil, nil)
448 | rsp, err := c.GetUser(req)
449 | if err != nil {
450 | t.Error(err)
451 | }
452 |
453 | assert.Equal(t, 200, rsp.StatusCode)
454 | assert.Equal(t, true, rsp.Success)
455 | assert.Equal(t, "ManuelReschke", rsp.Username)
456 | assert.Equal(t, "Free", rsp.Subscription.Name)
457 | }
458 |
459 | // TestPD_GetUserFiles is a unit test for the GET "/user/files" method
460 | func TestPD_GetUserFiles(t *testing.T) {
461 | server := pd.MockFileUploadServer()
462 | defer server.Close()
463 | testURL := server.URL + "/user/files"
464 |
465 | req := &pd.RequestGetUserFiles{
466 | URL: testURL,
467 | }
468 |
469 | req.Auth = setAuthFromEnv()
470 |
471 | c := pd.New(nil, nil)
472 | rsp, err := c.GetUserFiles(req)
473 | if err != nil {
474 | t.Error(err)
475 | }
476 |
477 | assert.Equal(t, 200, rsp.StatusCode)
478 | assert.Equal(t, true, rsp.Success)
479 | assert.Equal(t, "tUxgDCoQ", rsp.Files[0].ID)
480 | assert.Equal(t, "test_post_cat.jpg", rsp.Files[0].Name)
481 | }
482 |
483 | // TestPD_GetUserFiles_Integration run a real integration test against the service
484 | func TestPD_GetUserFiles_Integration(t *testing.T) {
485 | if testing.Short() {
486 | t.Skip(SkipIntegrationTest)
487 | }
488 |
489 | req := &pd.RequestGetUserFiles{}
490 |
491 | req.Auth = setAuthFromEnv()
492 |
493 | c := pd.New(nil, nil)
494 | rsp, err := c.GetUserFiles(req)
495 | if err != nil {
496 | t.Error(err)
497 | }
498 |
499 | assert.Equal(t, 200, rsp.StatusCode)
500 | assert.Equal(t, true, rsp.Success)
501 |
502 | if len(rsp.Files) >= 2 {
503 | assert.True(t, true)
504 | }
505 |
506 | for _, file := range rsp.Files {
507 | if file.ID == fileIDPost {
508 | assert.Equal(t, fileIDPost, file.ID)
509 | }
510 |
511 | if file.ID == fileIDPut {
512 | assert.Equal(t, fileIDPut, file.ID)
513 | }
514 | }
515 | }
516 |
517 | // TestPD_GetUserLists is a unit test for the GET "/user/files" method
518 | func TestPD_GetUserLists(t *testing.T) {
519 | server := pd.MockFileUploadServer()
520 | defer server.Close()
521 | testURL := server.URL + "/user/lists"
522 |
523 | req := &pd.RequestGetUserLists{
524 | URL: testURL,
525 | }
526 |
527 | req.Auth = setAuthFromEnv()
528 |
529 | c := pd.New(nil, nil)
530 | rsp, err := c.GetUserLists(req)
531 | if err != nil {
532 | t.Error(err)
533 | }
534 |
535 | assert.Equal(t, 200, rsp.StatusCode)
536 | assert.Equal(t, true, rsp.Success)
537 | assert.Equal(t, "Test List", rsp.Lists[0].Title)
538 | }
539 |
540 | // TestPD_GetUserLists_Integration run a real integration test against the service
541 | func TestPD_GetUserLists_Integration(t *testing.T) {
542 | if testing.Short() {
543 | t.Skip(SkipIntegrationTest)
544 | }
545 |
546 | req := &pd.RequestGetUserLists{}
547 |
548 | req.Auth = setAuthFromEnv()
549 |
550 | c := pd.New(nil, nil)
551 | rsp, err := c.GetUserLists(req)
552 | if err != nil {
553 | t.Error(err)
554 | }
555 |
556 | assert.Equal(t, 200, rsp.StatusCode)
557 | assert.Equal(t, true, rsp.Success)
558 | assert.Equal(t, "Test List", rsp.Lists[0].Title)
559 | }
560 |
561 | // TestPD_Delete is a unit test for the DELETE "delete" method
562 | func TestPD_Delete(t *testing.T) {
563 | server := pd.MockFileUploadServer()
564 | defer server.Close()
565 | testURL := server.URL + "/file/K1dA8U5W"
566 |
567 | req := &pd.RequestDelete{
568 | ID: "K1dA8U5W",
569 | URL: testURL,
570 | }
571 |
572 | req.Auth = setAuthFromEnv()
573 |
574 | c := pd.New(nil, nil)
575 | rsp, err := c.Delete(req)
576 | if err != nil {
577 | t.Error(err)
578 | }
579 |
580 | assert.Equal(t, true, rsp.Success)
581 | assert.Equal(t, "file_deleted", rsp.Value)
582 | assert.Equal(t, "The file has been deleted.", rsp.Message)
583 | }
584 |
585 | // TestPD_Delete_Integration run a real integration test against the service
586 | func TestPD_Delete_Integration(t *testing.T) {
587 | if testing.Short() {
588 | t.Skip(SkipIntegrationTest)
589 | }
590 |
591 | req := &pd.RequestDelete{
592 | ID: fileIDPost,
593 | }
594 |
595 | req.Auth = setAuthFromEnv()
596 |
597 | c := pd.New(nil, nil)
598 | rsp, err := c.Delete(req)
599 | if err != nil {
600 | t.Error(err)
601 | }
602 |
603 | assert.Equal(t, true, rsp.Success)
604 | assert.Equal(t, "ok", rsp.Value)
605 | assert.Equal(t, "The requested action was successfully performed", rsp.Message)
606 |
607 | req = &pd.RequestDelete{
608 | ID: fileIDPut,
609 | }
610 |
611 | req.Auth = setAuthFromEnv()
612 |
613 | c = pd.New(nil, nil)
614 | rsp, err = c.Delete(req)
615 | if err != nil {
616 | t.Error(err)
617 | }
618 |
619 | assert.Equal(t, true, rsp.Success)
620 | assert.Equal(t, "ok", rsp.Value)
621 | assert.Equal(t, "The requested action was successfully performed", rsp.Message)
622 | }
623 |
624 | func setAuthFromEnv() pd.Auth {
625 | // load api key from .env_test file
626 | currentWorkDirectory, _ := os.Getwd()
627 | _ = godotenv.Load(currentWorkDirectory + "/.env_test")
628 | apiKey := os.Getenv("API_KEY")
629 |
630 | return pd.Auth{
631 | APIKey: apiKey,
632 | }
633 | }
634 |
--------------------------------------------------------------------------------
/pkg/pd/request.go:
--------------------------------------------------------------------------------
1 | package pd
2 |
3 | import (
4 | "io"
5 | "path/filepath"
6 | )
7 |
8 | // Auth hold the auth information
9 | type Auth struct {
10 | APIKey string // if you have an account you can enter here your API Key for uploading in your account
11 | }
12 |
13 | // IsAuthAvailable checks if an API Key available
14 | func (a *Auth) IsAuthAvailable() bool {
15 | auth := false
16 | if a.APIKey != "" {
17 | auth = true
18 | }
19 |
20 | return auth
21 | }
22 |
23 | // RequestUpload container for the upload information
24 | type RequestUpload struct {
25 | File io.ReadCloser
26 | PathToFile string // path to the file "/home/user/cat.jpg"
27 | FileName string // just the filename "test.jpg"
28 | Anonymous bool // if the upload is anonymous or with auth
29 | Auth Auth
30 | URL string // specific the upload endpoint, is set by default with the correct values
31 | }
32 |
33 | // GetFileName return the filename from the path if no specific filename in the params
34 | func (r *RequestUpload) GetFileName() string {
35 | if r.FileName == "" {
36 | if r.PathToFile != "" {
37 | r.FileName = filepath.Base(r.PathToFile)
38 | }
39 | }
40 |
41 | return r.FileName
42 | }
43 |
44 | // RequestDownload container for the file download
45 | type RequestDownload struct {
46 | ID string
47 | PathToSave string
48 | Auth Auth
49 | URL string // specific the API endpoint, is set by default with the correct values
50 | }
51 |
52 | // RequestFileInfo the FileInfo request needs only an ID
53 | type RequestFileInfo struct {
54 | ID string
55 | Auth Auth
56 | URL string
57 | }
58 |
59 | // RequestThumbnail the Thumbnail request needs the ID and width and height
60 | type RequestThumbnail struct {
61 | ID string
62 | Width string
63 | Height string
64 | PathToSave string
65 | Auth Auth
66 | URL string
67 | }
68 |
69 | // RequestDelete delete the file if you are the owner with the given ID
70 | type RequestDelete struct {
71 | ID string
72 | Auth Auth
73 | URL string
74 | }
75 |
76 | // RequestCreateList parameters for creating new list
77 | type RequestCreateList struct {
78 | Title string `json:"title"`
79 | Anonymous bool `json:"anonymous"`
80 | Files []ListFile `json:"files"`
81 | Auth Auth
82 | URL string
83 | }
84 |
85 | // ListFile a file inside a CreateList request
86 | type ListFile struct {
87 | ID string `json:"id"`
88 | Description string `json:"description"`
89 | }
90 |
91 | // RequestGetList request to a retrieve a list
92 | type RequestGetList struct {
93 | ID string `json:"id"`
94 | Auth Auth
95 | URL string
96 | }
97 |
98 | // RequestGetUser ...
99 | type RequestGetUser struct {
100 | Auth Auth
101 | URL string
102 | }
103 |
104 | // RequestGetUserFiles ...
105 | type RequestGetUserFiles struct {
106 | Auth Auth
107 | URL string
108 | }
109 |
110 | // RequestGetUserLists ...
111 | type RequestGetUserLists struct {
112 | Auth Auth
113 | URL string
114 | }
115 |
--------------------------------------------------------------------------------
/pkg/pd/request_test.go:
--------------------------------------------------------------------------------
1 | package pd_test
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/stretchr/testify/assert"
7 |
8 | "github.com/ManuelReschke/go-pd/pkg/pd"
9 | )
10 |
11 | func TestPD_RequestUpload(t *testing.T) {
12 | r := &pd.RequestUpload{
13 | PathToFile: "/test/path/file.data",
14 | Anonymous: true,
15 | FileName: "test123",
16 | URL: "http://example.url",
17 | Auth: pd.Auth{APIKey: "test-key"},
18 | }
19 |
20 | assert.Equal(t, "/test/path/file.data", r.PathToFile)
21 | assert.Equal(t, true, r.Anonymous)
22 | assert.Equal(t, "test123", r.FileName)
23 | assert.Equal(t, "http://example.url", r.URL)
24 | assert.Equal(t, "test-key", r.Auth.APIKey)
25 | }
26 |
27 | func TestPD_RequestUpload_GetFileName(t *testing.T) {
28 | ru := &pd.RequestUpload{
29 | PathToFile: "/test/path/file.data",
30 | }
31 |
32 | assert.Equal(t, "file.data", ru.GetFileName())
33 | }
34 |
35 | func TestPD_RequestDownload(t *testing.T) {
36 | r := &pd.RequestDownload{
37 | ID: "123",
38 | URL: "http://example.url",
39 | Auth: pd.Auth{APIKey: "test-key"},
40 | }
41 |
42 | assert.Equal(t, "123", r.ID)
43 | assert.Equal(t, "http://example.url", r.URL)
44 | assert.Equal(t, "test-key", r.Auth.APIKey)
45 | }
46 |
47 | func TestPD_RequestThumbnail(t *testing.T) {
48 | r := &pd.RequestThumbnail{
49 | ID: "123",
50 | Width: "16",
51 | Height: "16",
52 | URL: "http://example.url",
53 | Auth: pd.Auth{APIKey: "test-key"},
54 | }
55 |
56 | assert.Equal(t, "123", r.ID)
57 | assert.Equal(t, "16", r.Width)
58 | assert.Equal(t, "16", r.Height)
59 | assert.Equal(t, "http://example.url", r.URL)
60 | assert.Equal(t, "test-key", r.Auth.APIKey)
61 | }
62 |
63 | func TestPD_RequestDelete(t *testing.T) {
64 | r := &pd.RequestDelete{
65 | ID: "123",
66 | URL: "http://example.url",
67 | Auth: pd.Auth{APIKey: "test-key"},
68 | }
69 |
70 | assert.Equal(t, "123", r.ID)
71 | assert.Equal(t, "http://example.url", r.URL)
72 | assert.Equal(t, "test-key", r.Auth.APIKey)
73 | }
74 |
75 | func TestPD_RequestCreateList(t *testing.T) {
76 | r := &pd.RequestCreateList{
77 | Title: "test",
78 | Anonymous: true,
79 | Files: []pd.ListFile{
80 | {ID: "123", Description: "Test Description"},
81 | {ID: "456", Description: "Test Description"},
82 | },
83 | URL: "http://example.url",
84 | Auth: pd.Auth{APIKey: "test-key"},
85 | }
86 |
87 | assert.Equal(t, "test", r.Title)
88 | assert.Equal(t, true, r.Anonymous)
89 | assert.Equal(t, 2, len(r.Files))
90 | assert.Equal(t, "123", r.Files[0].ID)
91 | assert.Equal(t, "Test Description", r.Files[0].Description)
92 | assert.Equal(t, "http://example.url", r.URL)
93 | assert.Equal(t, "test-key", r.Auth.APIKey)
94 | }
95 |
96 | func TestPD_RequestGetList(t *testing.T) {
97 | r := &pd.RequestGetList{
98 | ID: "123",
99 | URL: "http://example.url",
100 | Auth: pd.Auth{APIKey: "test-key"},
101 | }
102 |
103 | assert.Equal(t, "123", r.ID)
104 | assert.Equal(t, "http://example.url", r.URL)
105 | assert.Equal(t, "test-key", r.Auth.APIKey)
106 | }
107 |
108 | func TestPD_RequestGetUserFiles(t *testing.T) {
109 | r := &pd.RequestGetUserFiles{
110 | URL: "http://example.url",
111 | Auth: pd.Auth{APIKey: "test-key"},
112 | }
113 |
114 | assert.Equal(t, "http://example.url", r.URL)
115 | assert.Equal(t, "test-key", r.Auth.APIKey)
116 | }
117 |
118 | func TestPD_RequestGetUserLists(t *testing.T) {
119 | r := &pd.RequestGetUserLists{
120 | URL: "http://example.url",
121 | Auth: pd.Auth{APIKey: "test-key"},
122 | }
123 |
124 | assert.Equal(t, "http://example.url", r.URL)
125 | assert.Equal(t, "test-key", r.Auth.APIKey)
126 | }
127 |
--------------------------------------------------------------------------------
/pkg/pd/response.go:
--------------------------------------------------------------------------------
1 | package pd
2 |
3 | import (
4 | "fmt"
5 | "time"
6 | )
7 |
8 | type ResponseDefault struct {
9 | StatusCode int `json:"status_code"`
10 | Success bool `json:"success"`
11 | Value string `json:"value,omitempty"`
12 | Message string `json:"message,omitempty"`
13 | }
14 |
15 | type ResponseUpload struct {
16 | ID string `json:"id,omitempty"`
17 | ResponseDefault
18 | }
19 |
20 | // GetFileURL return the full URl to the uploaded file
21 | func (rsp *ResponseUpload) GetFileURL() string {
22 | return fmt.Sprintf("%su/%s", BaseURL, rsp.ID)
23 | }
24 |
25 | type ResponseDownload struct {
26 | FilePath string `json:"file_path"`
27 | FileName string `json:"file_name"`
28 | FileSize int64 `json:"file_size"`
29 | ResponseDefault
30 | }
31 |
32 | type ResponseFileInfo struct {
33 | ID string `json:"id"`
34 | Name string `json:"name"`
35 | Size int64 `json:"size"`
36 | Views int64 `json:"views"`
37 | BandwidthUsed int64 `json:"bandwidth_used"`
38 | BandwidthUsedPaid int64 `json:"bandwidth_used_paid"`
39 | Downloads int64 `json:"downloads"`
40 | DateUpload time.Time `json:"date_upload"`
41 | DateLastView time.Time `json:"date_last_view"`
42 | MimeType string `json:"mime_type"`
43 | ThumbnailHref string `json:"thumbnail_href"`
44 | HashSha256 string `json:"hash_sha256"`
45 | CanEdit bool `json:"can_edit"`
46 | ResponseDefault
47 | }
48 |
49 | type ResponseThumbnail struct {
50 | FilePath string `json:"file_path"`
51 | FileName string `json:"file_name"`
52 | FileSize int64 `json:"file_size"`
53 | ResponseDefault
54 | }
55 |
56 | type ResponseDelete struct {
57 | ResponseDefault
58 | }
59 |
60 | type ResponseCreateList struct {
61 | ID string `json:"id"`
62 | ResponseDefault
63 | }
64 |
65 | type FileGetList struct {
66 | DetailHref string `json:"detail_href"`
67 | Description string `json:"description"`
68 | Success bool `json:"success"`
69 | ID string `json:"id"`
70 | Name string `json:"name"`
71 | Size int64 `json:"size"`
72 | DateCreated time.Time `json:"date_created"`
73 | DateLastView time.Time `json:"date_last_view"`
74 | MimeType string `json:"mime_type"`
75 | Views int64 `json:"views"`
76 | BandwidthUsed int64 `json:"bandwidth_used"`
77 | ThumbnailHref string `json:"thumbnail_href"`
78 | }
79 |
80 | type ResponseGetList struct {
81 | ID string `json:"id"`
82 | Title string `json:"title"`
83 | DateCreated time.Time `json:"date_created"`
84 | Files []FileGetList `json:"files"`
85 | ResponseDefault
86 | }
87 |
88 | type ResponseGetUser struct {
89 | Username string `json:"username"`
90 | Email string `json:"email"`
91 | Subscription GetUserSubscription `json:"subscription"`
92 | StorageSpaceUsed int64 `json:"storage_space_used"`
93 | IsAdmin bool `json:"is_admin"`
94 | BalanceMicroEur int64 `json:"balance_micro_eur"`
95 | HotlinkingEnabled bool `json:"hotlinking_enabled"`
96 | MonthlyTransferCap int64 `json:"monthly_transfer_cap"`
97 | MonthlyTransferUsed int64 `json:"monthly_transfer_used"`
98 | FileViewerBranding interface{} `json:"file_viewer_branding"`
99 | FileEmbedDomains string `json:"file_embed_domains"`
100 | SkipFileViewer bool `json:"skip_file_viewer"`
101 | ResponseDefault
102 | }
103 |
104 | type GetUserSubscription struct {
105 | ID string `json:"id"`
106 | Name string `json:"name"`
107 | Type string `json:"type"`
108 | FileSizeLimit int64 `json:"file_size_limit"`
109 | FileExpiryDays int64 `json:"file_expiry_days"`
110 | StorageSpace int64 `json:"storage_space"`
111 | PricePerTbStorage int64 `json:"price_per_tb_storage"`
112 | PricePerTbBandwidth int64 `json:"price_per_tb_bandwidth"`
113 | MonthlyTransferCap int64 `json:"monthly_transfer_cap"`
114 | FileViewerBranding bool `json:"file_viewer_branding"`
115 | }
116 |
117 | type FileGetUser struct {
118 | ID string `json:"id"`
119 | Name string `json:"name"`
120 | Size int64 `json:"size"`
121 | Views int64 `json:"views"`
122 | BandwidthUsed int64 `json:"bandwidth_used"`
123 | BandwidthUsedPaid int64 `json:"bandwidth_used_paid"`
124 | Downloads int64 `json:"downloads"`
125 | DateUpload time.Time `json:"date_upload"`
126 | DateLastView time.Time `json:"date_last_view"`
127 | MimeType string `json:"mime_type"`
128 | ThumbnailHref string `json:"thumbnail_href"`
129 | HashSha256 string `json:"hash_sha256"`
130 | Availability string `json:"availability"`
131 | AvailabilityMessage string `json:"availability_message"`
132 | AbuseType string `json:"abuse_type"`
133 | AbuseReporterName string `json:"abuse_reporter_name"`
134 | CanEdit bool `json:"can_edit"`
135 | ShowAds bool `json:"show_ads"`
136 | AllowVideoPlayer bool `json:"allow_video_player"`
137 | DownloadSpeedLimit int64 `json:"download_speed_limit"`
138 | }
139 |
140 | type ResponseGetUserFiles struct {
141 | Files []FileGetUser `json:"files"`
142 | ResponseDefault
143 | }
144 |
145 | type ListsGetUser struct {
146 | ID string `json:"id"`
147 | Title string `json:"title"`
148 | DateCreated time.Time `json:"date_created"`
149 | FileCount int64 `json:"file_count"`
150 | Files interface{} `json:"files"`
151 | CanEdit bool `json:"can_edit"`
152 | }
153 |
154 | type ResponseGetUserLists struct {
155 | Lists []ListsGetUser `json:"lists"`
156 | ResponseDefault
157 | }
158 |
--------------------------------------------------------------------------------
/pkg/pd/response_test.go:
--------------------------------------------------------------------------------
1 | package pd_test
2 |
3 | import (
4 | "testing"
5 | "time"
6 |
7 | "github.com/stretchr/testify/assert"
8 |
9 | "github.com/ManuelReschke/go-pd/pkg/pd"
10 | )
11 |
12 | func TestPD_ResponseDefault(t *testing.T) {
13 | rsp := &pd.ResponseDefault{}
14 | rsp.Success = true
15 | rsp.Value = "test"
16 | rsp.Message = "test message"
17 |
18 | assert.Equal(t, true, rsp.Success)
19 | assert.Equal(t, "test", rsp.Value)
20 | assert.Equal(t, "test message", rsp.Message)
21 | }
22 |
23 | func TestPD_ResponseUpload(t *testing.T) {
24 | rsp := &pd.ResponseUpload{}
25 | rsp.StatusCode = 201
26 | rsp.ID = "test123"
27 | rsp.Success = true
28 | rsp.Value = "test"
29 | rsp.Message = "test message"
30 |
31 | assert.Equal(t, 201, rsp.StatusCode)
32 | assert.Equal(t, "test123", rsp.ID)
33 | assert.Equal(t, true, rsp.Success)
34 | assert.Equal(t, "test", rsp.Value)
35 | assert.Equal(t, "test message", rsp.Message)
36 | }
37 |
38 | func TestPD_ResponseDownload(t *testing.T) {
39 | rsp := &pd.ResponseDownload{}
40 | rsp.StatusCode = 200
41 | rsp.Success = true
42 | rsp.Value = "test"
43 | rsp.Message = "test message"
44 | rsp.FileName = "filename"
45 | rsp.FileSize = 123123
46 | rsp.FilePath = "/my/path/file.jpg"
47 |
48 | assert.Equal(t, 200, rsp.StatusCode)
49 | assert.Equal(t, true, rsp.Success)
50 | assert.Equal(t, "test", rsp.Value)
51 | assert.Equal(t, "test message", rsp.Message)
52 | assert.Equal(t, "filename", rsp.FileName)
53 | assert.Equal(t, int64(123123), rsp.FileSize)
54 | assert.Equal(t, "/my/path/file.jpg", rsp.FilePath)
55 | }
56 |
57 | func TestPD_ResponseThumbnail(t *testing.T) {
58 | rsp := &pd.ResponseThumbnail{}
59 | rsp.StatusCode = 200
60 | rsp.Success = true
61 | rsp.Value = "test"
62 | rsp.Message = "test message"
63 | rsp.FileName = "filename"
64 | rsp.FileSize = 123123
65 | rsp.FilePath = "/my/path/thumbnail.jpg"
66 |
67 | assert.Equal(t, 200, rsp.StatusCode)
68 | assert.Equal(t, true, rsp.Success)
69 | assert.Equal(t, "test", rsp.Value)
70 | assert.Equal(t, "test message", rsp.Message)
71 | assert.Equal(t, "filename", rsp.FileName)
72 | assert.Equal(t, int64(123123), rsp.FileSize)
73 | assert.Equal(t, "/my/path/thumbnail.jpg", rsp.FilePath)
74 | }
75 |
76 | func TestPD_ResponseDelete(t *testing.T) {
77 | rsp := &pd.ResponseDelete{}
78 | rsp.StatusCode = 200
79 | rsp.Success = true
80 | rsp.Value = "test"
81 | rsp.Message = "test message"
82 |
83 | assert.Equal(t, 200, rsp.StatusCode)
84 | assert.Equal(t, true, rsp.Success)
85 | assert.Equal(t, "test", rsp.Value)
86 | assert.Equal(t, "test message", rsp.Message)
87 | }
88 |
89 | func TestPD_ResponseCreateList(t *testing.T) {
90 | rsp := &pd.ResponseCreateList{}
91 | rsp.StatusCode = 200
92 | rsp.Success = true
93 | rsp.Value = "test"
94 | rsp.Message = "test message"
95 | rsp.ID = "123"
96 |
97 | assert.Equal(t, 200, rsp.StatusCode)
98 | assert.Equal(t, true, rsp.Success)
99 | assert.Equal(t, "test", rsp.Value)
100 | assert.Equal(t, "test message", rsp.Message)
101 | assert.Equal(t, "123", rsp.ID)
102 | }
103 |
104 | func TestPD_ResponseGetList(t *testing.T) {
105 | rsp := &pd.ResponseGetList{}
106 | rsp.StatusCode = 200
107 | rsp.Success = true
108 | rsp.Value = "test"
109 | rsp.Message = "test message"
110 | rsp.ID = "123"
111 | rsp.Title = "Test Title"
112 | layout := "2014-09-12T11:45:26.371Z"
113 | timeStr := "2020-02-04T18:34:13.466276Z"
114 | rsp.DateCreated, _ = time.Parse(layout, timeStr)
115 | //@todo
116 | rsp.Files = []pd.FileGetList{{
117 | DetailHref: "",
118 | Description: "",
119 | Success: false,
120 | ID: "",
121 | Name: "",
122 | Size: 0,
123 | DateCreated: time.Time{},
124 | DateLastView: time.Time{},
125 | MimeType: "",
126 | Views: 0,
127 | BandwidthUsed: 0,
128 | ThumbnailHref: "",
129 | }}
130 |
131 | assert.Equal(t, 200, rsp.StatusCode)
132 | assert.Equal(t, true, rsp.Success)
133 | assert.Equal(t, "test", rsp.Value)
134 | assert.Equal(t, "test message", rsp.Message)
135 | assert.Equal(t, "123", rsp.ID)
136 | }
137 |
138 | func TestPD_ResponseGetUserFiles(t *testing.T) {
139 | rsp := &pd.ResponseGetUserFiles{}
140 | rsp.StatusCode = 200
141 | rsp.Success = true
142 | rsp.Value = "test"
143 | rsp.Message = "test message"
144 |
145 | assert.Equal(t, 200, rsp.StatusCode)
146 | assert.Equal(t, true, rsp.Success)
147 | assert.Equal(t, "test", rsp.Value)
148 | assert.Equal(t, "test message", rsp.Message)
149 | }
150 |
151 | func TestPD_ResponseGetUserLists(t *testing.T) {
152 | rsp := &pd.ResponseGetUserLists{}
153 | rsp.StatusCode = 200
154 | rsp.Success = true
155 | rsp.Value = "test"
156 | rsp.Message = "test message"
157 |
158 | assert.Equal(t, 200, rsp.StatusCode)
159 | assert.Equal(t, true, rsp.Success)
160 | assert.Equal(t, "test", rsp.Value)
161 | assert.Equal(t, "test message", rsp.Message)
162 | }
163 |
--------------------------------------------------------------------------------
/pkg/pd/testdata/cat.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ManuelReschke/go-pd/471b70b89daca049586be995aebf24ab5fc94819/pkg/pd/testdata/cat.jpg
--------------------------------------------------------------------------------
/pkg/pd/testdata/cat_thumbnail.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ManuelReschke/go-pd/471b70b89daca049586be995aebf24ab5fc94819/pkg/pd/testdata/cat_thumbnail.jpg
--------------------------------------------------------------------------------