├── README.md ├── go.mod ├── go.sum ├── hosts ├── anonfiles │ ├── anonfiles.go │ └── structs.go ├── catbox │ └── catbox.go ├── fileio │ ├── fileio.go │ └── structs.go ├── filemail │ ├── filemail.go │ └── structs.go ├── ftp │ ├── ftp.go │ └── structs.go ├── gofile │ ├── gofile.go │ └── structs.go ├── krakenfiles │ ├── krakenfiles.go │ └── structs.go ├── letsupload │ ├── letsupload.go │ └── structs.go ├── megaup │ ├── megaup.go │ └── structs.go ├── mixdrop │ ├── mixdrop.go │ └── structs.go ├── onefichier │ ├── 1fichier.go │ └── structs.go ├── pixeldrain │ ├── pixeldrain.go │ └── structs.go ├── racaty │ ├── racaty.go │ └── structs.go ├── transfersh │ └── transfersh.go ├── uguu │ ├── structs.go │ └── uguu.go ├── wetransfer │ ├── structs.go │ └── wetransfer.go ├── workupload │ ├── structs.go │ └── workupload.go └── zippyshare │ └── zippyshare.go ├── main.go └── utils ├── maps.go ├── structs.go └── utils.go /README.md: -------------------------------------------------------------------------------- 1 | # go-upload 2 | File uploader with support for multiple hosts and progress reporting written in Go. Large file-friendly. 3 |  4 | [Windows, Linux, macOS and Android binaries](https://github.com/Sorrow446/go-upload/releases) 5 | 6 | ## Usage 7 | Upload single file to anonfiles: 8 | `go-ul_x64.exe anonfiles -f G:\file.bin` 9 | 10 | Upload two files to anonfiles and catbox and write output template: 11 | `go-ul_x64.exe anonfiles catbox -f G:\file.bin G:\file2.bin -o urls.txt` 12 | 13 | Upload all files in `G:\stuff` to zippyshare recursively with a 500 kB/s limit and write output template: 14 | `go-ul_x64.exe zippyshare -d G:\stuff -r -o urls.txt -l 0.5` 15 | 16 | Upload a single file to FTP server to /x/y/ and overwrite it if it already exists. 17 | `go-ul_x64.exe ftp -f G:\file.bin -U ftp://myusername:mypassword@ftp.server.com:21/x/y/ -O` 18 | 19 | ``` 20 | Usage: go-ul_x64.exe [--outpath OUTPATH] [--wipe] [--files FILES] [--private] [--template TEMPLATE] [--overwrite] [--user USER] [--directories DIRECTORIES] [--recursive] [--speedlimit SPEEDLIMIT] HOSTS [HOSTS ...] 21 | 22 | Positional arguments: 23 | HOSTS Which hosts to upload to. 24 | 25 | Options: 26 | --outpath OUTPATH, -o OUTPATH 27 | Path of text file to write template to. It will be created if it doesn't already exist. 28 | --wipe, -w Wipe output text file on startup. 29 | --files FILES, -f FILES 30 | --private, -P *Set upload as private. 31 | --template TEMPLATE, -t TEMPLATE 32 | Output text file template. Vars: filename, filePath, fileUrl [default: # {{.filename}}\n{{.fileUrl}}\n] 33 | --overwrite, -O *Overwrite file on host if it already exists. 34 | --user USER, -u USER *User form for FTP. Folders will be created recursively if they don't already exist. 35 | --directories DIRECTORIES, -d DIRECTORIES 36 | --recursive, -r Include subdirectories. 37 | --speedlimit SPEEDLIMIT, -l SPEEDLIMIT 38 | *Upload speed limit in megabytes. Example: 0.5 = 500 kB/s, 1 = 1 MB/s, 1.5 = 1.5 MB/s. [default: -1] 39 | --joboutpath JOBOUTPATH, -j JOBOUTPATH 40 | Path of JSON to write jobs to. 41 | --help, -h display this help and exit 42 | ``` 43 | \* = Not supported for all hosts. 44 | 45 | ### Template 46 | 47 | Default: `# {{.filename}}\n{{.fileUrl}}\n` 48 | Output with the default template: 49 | ``` 50 | # 2.jpg 51 | https://anonfiles.com/Hde2H4F5ue/2_jpg 52 | ``` 53 | Vars: filename, filePath, fileUrl 54 | 55 | ## Supported hosts 56 | |Host|Argument|Size Limit| 57 | | --- | --- | --- | 58 | |[anonfiles](https://anonfiles.com/)|anonfiles|20 GB 59 | |[Catbox](https://catbox.moe/)|catbox|200 MB 60 | |[file.io](https://www.file.io/)|fileio|2 GB 61 | |[Filemail](https://www.filemail.com/)|filemail|5 GB 62 | |FTP|ftp|- 63 | |[Gofile](https://gofile.io/)|gofile|unlim 64 | |[KrakenFiles](https://krakenfiles.com/)|krakenfiles|1 GB 65 | |[LetsUpload](https://letsupload.io/)|letsupload|10 GB 66 | |[MegaUp](https://megaup.net/)|megaup|5 GB 67 | |[MixDrop](https://mixdrop.co/)|mixdrop|unlim 68 | |[pixeldrain](https://pixeldrain.com/)|pixeldrain|10 GB 69 | |[Racaty](https://racaty.net/)|racaty|10 GB 70 | |[transfer.sh](https://transfer.sh/)|transfersh|unlim 71 | |[Uguu](https://uguu.se/)|uguu|128 MB 72 | |[WeTransfer](https://wetransfer.com/)|wetransfer|2 GB 73 | |[workupload](https://workupload.com/)|workupload|2 GB 74 | |[zippyshare](https://www.zippyshare.com/)|zippyshare|500 MB 75 | 76 | Host arguments are case insensitive. 77 | 78 | ## For developers 79 | If you would like to use go-upload with your software, you can use the `-j` arg to have it write a jobs JSON to a specified path. 80 | 81 | It will only panic and return an exit code 1 if: 82 | 1. Setup fails (arg parsing, output text or job file setup). 83 | 2. A job fails to write. 84 | 85 | Example output: 86 | ```json 87 | { 88 | "jobs": [ 89 | { 90 | "url": "https://anonfiles.com/La53h1l3ye/1_gif", 91 | "host": "anonfiles", 92 | "filename": "1.gif", 93 | "file_path": "G:\\go\\ul_5\\1.gif", 94 | "ok": true, 95 | "error_text": "" 96 | }, 97 | { 98 | "url": "https://we.tl/t-tNBYrFyQhH", 99 | "host": "wetransfer", 100 | "filename": "1.gif", 101 | "file_path": "G:\\go\\ul_5\\1.gif", 102 | "ok": true, 103 | "error_text": "" 104 | } 105 | ] 106 | } 107 | ``` 108 | If a job file with the same path already exists, it will be wiped. 109 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module main 2 | 3 | go 1.18 4 | 5 | require ( 6 | github.com/alexflint/go-arg v1.4.3 7 | github.com/dustin/go-humanize v1.0.0 8 | github.com/jlaffaye/ftp v0.1.0 9 | ) 10 | 11 | require ( 12 | github.com/alexflint/go-scalar v1.1.0 // indirect 13 | github.com/hashicorp/errwrap v1.0.0 // indirect 14 | github.com/hashicorp/go-multierror v1.1.1 // indirect 15 | ) 16 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/alexflint/go-arg v1.4.3 h1:9rwwEBpMXfKQKceuZfYcwuc/7YY7tWJbFsgG5cAU/uo= 2 | github.com/alexflint/go-arg v1.4.3/go.mod h1:3PZ/wp/8HuqRZMUUgu7I+e1qcpUbvmS258mRXkFH4IA= 3 | github.com/alexflint/go-scalar v1.1.0 h1:aaAouLLzI9TChcPXotr6gUhq+Scr8rl0P9P4PnltbhM= 4 | github.com/alexflint/go-scalar v1.1.0/go.mod h1:LoFvNMqS1CPrMVltza4LvnGKhaSpc3oyLEBUZVhhS2o= 5 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 6 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 7 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 8 | github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= 9 | github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= 10 | github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= 11 | github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= 12 | github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= 13 | github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= 14 | github.com/jlaffaye/ftp v0.1.0 h1:DLGExl5nBoSFoNshAUHwXAezXwXBvFdx7/qwhucWNSE= 15 | github.com/jlaffaye/ftp v0.1.0/go.mod h1:hhq4G4crv+nW2qXtNYcuzLeOudG92Ps37HEKeg2e3lE= 16 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 17 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 18 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 19 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 20 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 21 | github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= 22 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 23 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 24 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 25 | -------------------------------------------------------------------------------- /hosts/anonfiles/anonfiles.go: -------------------------------------------------------------------------------- 1 | package anonfiles 2 | 3 | import ( 4 | "encoding/json" 5 | "errors" 6 | "main/utils" 7 | ) 8 | 9 | const ( 10 | uploadUrl = "https://api.anonfiles.com/upload" 11 | referer = "https://anonfiles.com/" 12 | ) 13 | 14 | func upload(path string, size, byteLimit int64, headers map[string]string) (string, error) { 15 | respBody, err := utils.MultipartUpload(uploadUrl, path, "file", size, byteLimit, nil, nil, headers) 16 | if err != nil { 17 | return "", err 18 | } 19 | defer respBody.Close() 20 | var obj Upload 21 | err = json.NewDecoder(respBody).Decode(&obj) 22 | if err != nil { 23 | return "", err 24 | } 25 | if !obj.Status { 26 | return "", errors.New("Bad response. " + obj.Error.Type) 27 | } else if obj.Data.File.Metadata.Size.Bytes != size { 28 | return "", errors.New("Byte count mismatch.") 29 | } 30 | return obj.Data.File.URL.Full, nil 31 | } 32 | 33 | func Run(args *utils.Args, path string) (string, error) { 34 | size, err := utils.CheckSize(path, "20GB") 35 | if err != nil { 36 | return "", err 37 | } 38 | headers := map[string]string{ 39 | "Referer": referer, 40 | } 41 | fileUrl, err := upload(path, size, args.ByteLimit, headers) 42 | return fileUrl, err 43 | } 44 | -------------------------------------------------------------------------------- /hosts/anonfiles/structs.go: -------------------------------------------------------------------------------- 1 | package anonfiles 2 | 3 | type Upload struct { 4 | Status bool `json:"status"` 5 | Data struct { 6 | File struct { 7 | URL struct { 8 | Full string `json:"full"` 9 | Short string `json:"short"` 10 | } `json:"url"` 11 | Metadata struct { 12 | ID string `json:"id"` 13 | Name string `json:"name"` 14 | Size struct { 15 | Bytes int64 `json:"bytes"` 16 | Readable string `json:"readable"` 17 | } `json:"size"` 18 | } `json:"metadata"` 19 | } `json:"file"` 20 | } `json:"data"` 21 | Error struct { 22 | Message string `json:"message"` 23 | Type string `json:"type"` 24 | Code int `json:"code"` 25 | } `json:"error"` 26 | } 27 | -------------------------------------------------------------------------------- /hosts/catbox/catbox.go: -------------------------------------------------------------------------------- 1 | package catbox 2 | 3 | import ( 4 | "io" 5 | "main/utils" 6 | ) 7 | 8 | const ( 9 | uploadUrl = "https://catbox.moe/user/api.php" 10 | referer = "https://catbox.moe/" 11 | ) 12 | 13 | func upload(path string, size, byteLimit int64, formMap, headers map[string]string) (string, error) { 14 | respBody, err := utils.MultipartUpload(uploadUrl, path, "fileToUpload", size, byteLimit, formMap, nil, headers) 15 | if err != nil { 16 | return "", err 17 | } 18 | defer respBody.Close() 19 | bodyBytes, err := io.ReadAll(respBody) 20 | return string(bodyBytes), err 21 | } 22 | 23 | func Run(args *utils.Args, path string) (string, error) { 24 | size, err := utils.CheckSize(path, "200MB") 25 | if err != nil { 26 | return "", err 27 | } 28 | formMap := map[string]string{ 29 | "userhash": "", 30 | "reqtype": "fileupload", 31 | } 32 | headers := map[string]string{ 33 | "Referer": referer, 34 | } 35 | fileUrl, err := upload(path, size, args.ByteLimit, formMap, headers) 36 | return fileUrl, err 37 | } 38 | -------------------------------------------------------------------------------- /hosts/fileio/fileio.go: -------------------------------------------------------------------------------- 1 | package fileio 2 | 3 | import ( 4 | "encoding/json" 5 | "errors" 6 | "main/utils" 7 | ) 8 | 9 | const ( 10 | uploadUrl = "https://file.io/" 11 | referer = "https://www.file.io/" 12 | ) 13 | 14 | func upload(path string, size, byteLimit int64, headers map[string]string) (string, error) { 15 | respBody, err := utils.MultipartUpload(uploadUrl, path, "file", size, byteLimit, nil, nil, headers) 16 | if err != nil { 17 | return "", err 18 | } 19 | defer respBody.Close() 20 | var obj Upload 21 | err = json.NewDecoder(respBody).Decode(&obj) 22 | if err != nil { 23 | return "", err 24 | } 25 | if !obj.Success { 26 | return "", errors.New("Bad response.") 27 | } else if obj.Size != size { 28 | return "", errors.New("Byte count mismatch.") 29 | } 30 | return obj.Link, nil 31 | } 32 | 33 | func Run(args *utils.Args, path string) (string, error) { 34 | size, err := utils.CheckSize(path, "2GB") 35 | if err != nil { 36 | return "", err 37 | } 38 | headers := map[string]string{ 39 | "Referer": referer, 40 | } 41 | fileUrl, err := upload(path, size, args.ByteLimit, headers) 42 | return fileUrl, err 43 | } 44 | -------------------------------------------------------------------------------- /hosts/fileio/structs.go: -------------------------------------------------------------------------------- 1 | package fileio 2 | 3 | import "time" 4 | 5 | type Upload struct { 6 | Success bool `json:"success"` 7 | Status int `json:"status"` 8 | ID string `json:"id"` 9 | Key string `json:"key"` 10 | Name string `json:"name"` 11 | Link string `json:"link"` 12 | Private bool `json:"private"` 13 | Expires time.Time `json:"expires"` 14 | Downloads int `json:"downloads"` 15 | MaxDownloads int `json:"maxDownloads"` 16 | AutoDelete bool `json:"autoDelete"` 17 | Size int64 `json:"size"` 18 | MimeType string `json:"mimeType"` 19 | Created time.Time `json:"created"` 20 | Modified time.Time `json:"modified"` 21 | } 22 | -------------------------------------------------------------------------------- /hosts/filemail/filemail.go: -------------------------------------------------------------------------------- 1 | package filemail 2 | 3 | import ( 4 | "encoding/json" 5 | "errors" 6 | "main/utils" 7 | "strconv" 8 | ) 9 | 10 | const ( 11 | apiBase = "https://www.filemail.com/api/transfer/" 12 | referer = "https://www.filemail.com/" 13 | ) 14 | 15 | func initUpload(size int64, headers map[string]string) (*Initialize, error) { 16 | initUrl := apiBase + "initialize" 17 | params := map[string]string{ 18 | "sourcedetails": "fupload4.0 @ https://www.filemail.com/", 19 | "days": "7", 20 | "confirmation": "true", 21 | "transfersize": strconv.FormatInt(size, 10), 22 | } 23 | respBody, err := utils.DoPost(initUrl, params, headers, nil) 24 | if err != nil { 25 | return nil, err 26 | } 27 | defer respBody.Close() 28 | var obj Initialize 29 | err = json.NewDecoder(respBody).Decode(&obj) 30 | if err != nil { 31 | return nil, err 32 | } 33 | if obj.Responsestatus != "OK" { 34 | return nil, errors.New("Bad response.") 35 | } 36 | return &obj, nil 37 | } 38 | 39 | func upload(uploadUrl, path string, size, byteLimit int64, params, headers map[string]string) error { 40 | respBody, err := utils.MultipartUpload(uploadUrl, path, "file", size, byteLimit, nil, params, headers) 41 | if err != nil { 42 | return err 43 | } 44 | respBody.Close() 45 | return nil 46 | } 47 | 48 | func finalizeUpload(params, headers map[string]string) (string, error) { 49 | finalizeUrl := apiBase + "complete" 50 | params["failed"] = "false" 51 | respBody, err := utils.DoPost(finalizeUrl, params, headers, nil) 52 | if err != nil { 53 | return "", err 54 | } 55 | defer respBody.Close() 56 | var obj Finalize 57 | err = json.NewDecoder(respBody).Decode(&obj) 58 | if err != nil { 59 | return "", err 60 | } 61 | if obj.Responsestatus != "OK" { 62 | return "", errors.New("Bad response.") 63 | } 64 | return obj.Downloadurl, nil 65 | } 66 | 67 | func Run(args *utils.Args, path string) (string, error) { 68 | size, err := utils.CheckSize(path, "5GB") 69 | if err != nil { 70 | return "", err 71 | } 72 | headers := map[string]string{ 73 | "Referer": referer, 74 | "Source": "Web", 75 | } 76 | initMeta, err := initUpload(size, headers) 77 | if err != nil { 78 | return "", err 79 | } 80 | params := map[string]string{ 81 | "transferid": initMeta.Transferid, 82 | "transferkey": initMeta.Transferkey, 83 | } 84 | err = upload(initMeta.Transferurl, path, size, args.ByteLimit, params, headers) 85 | if err != nil { 86 | return "", err 87 | } 88 | fileUrl, err := finalizeUpload(params, headers) 89 | return fileUrl, err 90 | } 91 | -------------------------------------------------------------------------------- /hosts/filemail/structs.go: -------------------------------------------------------------------------------- 1 | package filemail 2 | 3 | type Initialize struct { 4 | Transferid string `json:"transferid"` 5 | Transferkey string `json:"transferkey"` 6 | Transferurl string `json:"transferurl"` 7 | Transferip string `json:"transferip"` 8 | Udpport int `json:"udpport"` 9 | Udpthreshold int `json:"udpthreshold"` 10 | Responsestatus string `json:"responsestatus"` 11 | } 12 | 13 | type Finalize struct { 14 | Downloadurl string `json:"downloadurl"` 15 | Responsestatus string `json:"responsestatus"` 16 | } 17 | -------------------------------------------------------------------------------- /hosts/ftp/ftp.go: -------------------------------------------------------------------------------- 1 | package ftp 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "io" 7 | "main/utils" 8 | "net/url" 9 | "os" 10 | "path/filepath" 11 | "strings" 12 | "time" 13 | 14 | "github.com/dustin/go-humanize" 15 | "github.com/jlaffaye/ftp" 16 | _ftp "github.com/jlaffaye/ftp" 17 | ) 18 | 19 | func auth(host, username, password string) (*_ftp.ServerConn, error) { 20 | c, err := _ftp.Dial(host, _ftp.DialWithTimeout(time.Second*30)) 21 | if err != nil { 22 | return nil, err 23 | } 24 | err = c.Login(username, password) 25 | if err != nil { 26 | c.Quit() 27 | return nil, err 28 | } 29 | return c, nil 30 | } 31 | 32 | func fileExists(c *_ftp.ServerConn, path, filename string) (bool, error) { 33 | entries, err := c.List(path) 34 | if err != nil { 35 | return false, err 36 | } 37 | for _, entry := range entries { 38 | if entry.Type == _ftp.EntryTypeFile && entry.Name == filename { 39 | return true, nil 40 | } 41 | } 42 | return false, nil 43 | } 44 | 45 | func dirExists(c *ftp.ServerConn, directory string) (bool, error) { 46 | entries, err := c.List("") 47 | if err != nil { 48 | return false, err 49 | } 50 | for _, entry := range entries { 51 | if entry.Type == ftp.EntryTypeFolder && entry.Name == directory { 52 | return true, nil 53 | } 54 | } 55 | return false, nil 56 | } 57 | 58 | func upload(c *_ftp.ServerConn, path, filename string) error { 59 | defer fmt.Println("") 60 | f, err := os.Open(path) 61 | if err != nil { 62 | return err 63 | } 64 | defer f.Close() 65 | stat, err := f.Stat() 66 | if err != nil { 67 | return err 68 | } 69 | size := stat.Size() 70 | counter := &utils.WriteCounter{ 71 | Total: size, 72 | TotalStr: humanize.Bytes(uint64(size)), 73 | StartTime: time.Now().UnixMilli(), 74 | } 75 | err = c.Stor(filename, io.TeeReader(f, counter)) 76 | return err 77 | } 78 | 79 | func parseUrl(userString string) (*User, error) { 80 | if !strings.HasPrefix(userString, "ftp://") { 81 | userString = "ftp://" + userString 82 | } 83 | u, err := url.Parse(userString) 84 | if err != nil { 85 | return nil, err 86 | } 87 | host := u.Host 88 | path := u.Path 89 | userInfo := u.User 90 | username := userInfo.Username() 91 | password, _ := userInfo.Password() 92 | if host == "" { 93 | return nil, errors.New("Host required.") 94 | } else if username == "" { 95 | return nil, errors.New("Username required.") 96 | } else if password == "" { 97 | return nil, errors.New("Password required.") 98 | } 99 | if path == "/" { 100 | path = "" 101 | } 102 | user := &User{ 103 | Host: host, 104 | Username: username, 105 | Password: password, 106 | Path: path, 107 | } 108 | return user, nil 109 | } 110 | 111 | func makeDirRecur(c *ftp.ServerConn, path string) error { 112 | path = strings.Trim(path, "/") 113 | splitPath := strings.Split(path, "/") 114 | for _, dir := range splitPath { 115 | exists, err := dirExists(c, dir) 116 | if err != nil { 117 | return err 118 | } 119 | if !exists { 120 | err := c.MakeDir(dir) 121 | if err != nil { 122 | return err 123 | } 124 | } 125 | err = c.ChangeDir(dir) 126 | if err != nil { 127 | return err 128 | } 129 | } 130 | return nil 131 | } 132 | 133 | func Run(args *utils.Args, path string) (string, error) { 134 | filename := filepath.Base(path) 135 | if args.User == "" { 136 | return "", errors.New("User required (host, port, username and password).") 137 | } 138 | u, err := parseUrl(args.User) 139 | if err != nil { 140 | return "", err 141 | } 142 | c, err := auth(u.Host, u.Username, u.Password) 143 | if err != nil { 144 | return "", err 145 | } 146 | defer c.Quit() 147 | if u.Path != "" { 148 | err = makeDirRecur(c, u.Path) 149 | if err != nil { 150 | return "", err 151 | } 152 | } 153 | if !args.Overwrite { 154 | exists, err := fileExists(c, u.Path, filename) 155 | if err != nil { 156 | return "", err 157 | } 158 | if exists { 159 | return "", errors.New("File already exists on FTP. Use the -O flag to overwrite.") 160 | } 161 | } 162 | err = upload(c, path, filename) 163 | if err != nil { 164 | return "", err 165 | } 166 | outPath := u.Path + "/" + filename 167 | return outPath, nil 168 | } 169 | -------------------------------------------------------------------------------- /hosts/ftp/structs.go: -------------------------------------------------------------------------------- 1 | package ftp 2 | 3 | type User struct { 4 | Host string 5 | Username string 6 | Password string 7 | Path string 8 | } 9 | -------------------------------------------------------------------------------- /hosts/gofile/gofile.go: -------------------------------------------------------------------------------- 1 | package gofile 2 | 3 | import ( 4 | "encoding/json" 5 | "errors" 6 | "main/utils" 7 | ) 8 | 9 | const ( 10 | referer = "https://gofile.io/" 11 | serverUrl = "https://api.gofile.io/getServer" 12 | ) 13 | 14 | func getServer() (string, error) { 15 | respBody, err := utils.DoGet(serverUrl, nil, nil) 16 | if err != nil { 17 | return "", err 18 | } 19 | defer respBody.Close() 20 | var obj GetServer 21 | err = json.NewDecoder(respBody).Decode(&obj) 22 | if err != nil { 23 | return "", err 24 | } 25 | if obj.Status != "ok" { 26 | return "", errors.New("Bad response.") 27 | } 28 | return obj.Data.Server, nil 29 | } 30 | 31 | func upload(uploadUrl, path string, size, byteLimit int64, headers map[string]string) (string, error) { 32 | respBody, err := utils.MultipartUpload(uploadUrl, path, "file", size, byteLimit, nil, nil, headers) 33 | if err != nil { 34 | return "", err 35 | } 36 | defer respBody.Close() 37 | var obj Upload 38 | err = json.NewDecoder(respBody).Decode(&obj) 39 | if err != nil { 40 | return "", err 41 | } 42 | if obj.Status != "ok" { 43 | return "", errors.New("Bad response.") 44 | } 45 | return obj.Data.DownloadPage, nil 46 | } 47 | 48 | func Run(args *utils.Args, path string) (string, error) { 49 | size, err := utils.CheckSize(path, "unlim") 50 | if err != nil { 51 | return "", err 52 | } 53 | server, err := getServer() 54 | if err != nil { 55 | return "", err 56 | } 57 | uploadUrl := "https://" + server + ".gofile.io/uploadFile" 58 | headers := map[string]string{ 59 | "Referer": referer, 60 | } 61 | url, err := upload(uploadUrl, path, size, args.ByteLimit, headers) 62 | return url, err 63 | } 64 | -------------------------------------------------------------------------------- /hosts/gofile/structs.go: -------------------------------------------------------------------------------- 1 | package gofile 2 | 3 | type GetServer struct { 4 | Status string `json:"status"` 5 | Data struct { 6 | Server string `json:"server"` 7 | } `json:"data"` 8 | } 9 | 10 | type Upload struct { 11 | Status string `json:"status"` 12 | Data struct { 13 | DownloadPage string `json:"downloadPage"` 14 | Code string `json:"code"` 15 | ParentFolder string `json:"parentFolder"` 16 | FileID string `json:"fileId"` 17 | FileName string `json:"fileName"` 18 | Md5 string `json:"md5"` 19 | DirectLink string `json:"directLink"` 20 | Info string `json:"info"` 21 | } `json:"data"` 22 | } 23 | -------------------------------------------------------------------------------- /hosts/krakenfiles/krakenfiles.go: -------------------------------------------------------------------------------- 1 | package krakenfiles 2 | 3 | import ( 4 | "encoding/json" 5 | "errors" 6 | "fmt" 7 | "main/utils" 8 | ) 9 | 10 | const ( 11 | referer = "https://krakenfiles.com/" 12 | uloadUrlRegexStr = `url: "([^"]+)"` 13 | ) 14 | 15 | func getUploadUrl() (string, error) { 16 | match, err := utils.FindHtmlSubmatch(referer, uloadUrlRegexStr) 17 | if err != nil { 18 | return "", err 19 | } 20 | if match == nil { 21 | return "", errors.New("No regex match.") 22 | } 23 | return match[1], nil 24 | } 25 | func upload(uploadUrl, path string, size, ByteLimit int64, headers map[string]string) (string, error) { 26 | respBody, err := utils.MultipartUpload(uploadUrl, path, "files[]", size, ByteLimit, nil, nil, headers) 27 | if err != nil { 28 | return "", err 29 | } 30 | defer respBody.Close() 31 | var obj Upload 32 | err = json.NewDecoder(respBody).Decode(&obj) 33 | if err != nil { 34 | return "", err 35 | } 36 | file := obj.Files[0] 37 | if file.Error != "" { 38 | return "", errors.New("Bad response: " + file.Error) 39 | } 40 | return referer + file.URL[1:], nil 41 | } 42 | 43 | func Run(args *utils.Args, path string) (string, error) { 44 | size, err := utils.CheckSize(path, "1GB") 45 | if err != nil { 46 | return "", err 47 | } 48 | uploadUrl, err := getUploadUrl() 49 | if err != nil { 50 | fmt.Println("Failed to get upload URL.") 51 | return "", err 52 | } 53 | headers := map[string]string{ 54 | "Referer": referer, 55 | } 56 | fileUrl, err := upload(uploadUrl, path, size, args.ByteLimit, headers) 57 | return fileUrl, err 58 | } 59 | -------------------------------------------------------------------------------- /hosts/krakenfiles/structs.go: -------------------------------------------------------------------------------- 1 | package krakenfiles 2 | 3 | type Upload struct { 4 | Files []struct { 5 | Name string `json:"name"` 6 | Size string `json:"size"` 7 | Error string `json:"error"` 8 | URL string `json:"url"` 9 | Hash string `json:"hash"` 10 | } `json:"files"` 11 | } 12 | -------------------------------------------------------------------------------- /hosts/letsupload/letsupload.go: -------------------------------------------------------------------------------- 1 | package letsupload 2 | 3 | import ( 4 | "encoding/json" 5 | "errors" 6 | "fmt" 7 | "main/utils" 8 | "strconv" 9 | "time" 10 | ) 11 | 12 | const ( 13 | referer = "https://letsupload.io/" 14 | uploaderUrl = referer + "assets/js/uploader.js" 15 | uploadUrlRegexStr = `url: '([^']+)'` 16 | formDataRegexStr = `data.formData = {_sessionid: '([^']+)', cTracker: '([^']+)'` 17 | ) 18 | 19 | func getEpochStr() string { 20 | epoch := strconv.FormatInt(time.Now().Unix(), 10) 21 | return epoch 22 | } 23 | 24 | func extractMeta() (*Meta, error) { 25 | epoch := getEpochStr() 26 | html, err := utils.GetHtml(uploaderUrl + "?r=" + epoch) 27 | if err != nil { 28 | return nil, err 29 | } 30 | uploadUrlMatch := utils.FindStringSubmatch(html, uploadUrlRegexStr) 31 | if uploadUrlMatch == nil { 32 | return nil, errors.New("No regex match for upload URL.") 33 | } 34 | formDataMatch := utils.FindStringSubmatch(html, formDataRegexStr) 35 | if formDataMatch == nil { 36 | return nil, errors.New("No regex match for form data.") 37 | } 38 | meta := &Meta{ 39 | UploadURL: uploadUrlMatch[1], 40 | SessionID: formDataMatch[1], 41 | Tracker: formDataMatch[2], 42 | } 43 | return meta, nil 44 | } 45 | 46 | func upload(uploadUrl, path string, size, byteLimit int64, headers, formMap map[string]string) (string, error) { 47 | respBody, err := utils.MultipartUpload(uploadUrl, path, "files[]", size, byteLimit, formMap, nil, headers) 48 | if err != nil { 49 | return "", err 50 | } 51 | defer respBody.Close() 52 | var obj UploadResp 53 | err = json.NewDecoder(respBody).Decode(&obj) 54 | if err != nil { 55 | return "", err 56 | } 57 | file := obj[0] 58 | fileErr := file.Error 59 | if fileErr != nil { 60 | return "", errors.New("Bad response: " + fileErr.(string)) 61 | } 62 | if int64(file.Size) != size { 63 | return "", errors.New("Byte count mismatch.") 64 | } 65 | return file.URL, nil 66 | } 67 | 68 | func Run(args *utils.Args, path string) (string, error) { 69 | size, err := utils.CheckSize(path, "10GB") 70 | if err != nil { 71 | return "", err 72 | } 73 | meta, err := extractMeta() 74 | if err != nil { 75 | fmt.Println("Failed to extract meta.") 76 | return "", err 77 | } 78 | headers := map[string]string{ 79 | "Referer": referer, 80 | } 81 | formMap := map[string]string{ 82 | "_sessionid": meta.SessionID, 83 | "cTracker": meta.Tracker, 84 | "maxChunkSize": "100000000", 85 | "folderId": "-1", 86 | "uploadSource": "file_manager", 87 | } 88 | fileUrl, err := upload(meta.UploadURL, path, size, args.ByteLimit, headers, formMap) 89 | return fileUrl, err 90 | } 91 | -------------------------------------------------------------------------------- /hosts/letsupload/structs.go: -------------------------------------------------------------------------------- 1 | package letsupload 2 | 3 | type Meta struct { 4 | UploadURL string 5 | SessionID string 6 | Tracker string 7 | } 8 | 9 | type UploadResp []struct { 10 | Name string `json:"name"` 11 | Size int `json:"size"` 12 | Type string `json:"type"` 13 | Error interface{} `json:"error"` 14 | URL string `json:"url"` 15 | DeleteURL string `json:"delete_url"` 16 | InfoURL string `json:"info_url"` 17 | DeleteType string `json:"delete_type"` 18 | DeleteHash string `json:"delete_hash"` 19 | Hash string `json:"hash"` 20 | StatsURL string `json:"stats_url"` 21 | ShortURL string `json:"short_url"` 22 | FileID string `json:"file_id"` 23 | UniqueHash string `json:"unique_hash"` 24 | URLHTML string `json:"url_html"` 25 | URLBbcode string `json:"url_bbcode"` 26 | SuccessResultHTML string `json:"success_result_html"` 27 | } 28 | -------------------------------------------------------------------------------- /hosts/megaup/megaup.go: -------------------------------------------------------------------------------- 1 | package megaup 2 | 3 | import ( 4 | "encoding/json" 5 | "errors" 6 | "main/utils" 7 | "strconv" 8 | ) 9 | 10 | const ( 11 | referer = "https://megaup.net/" 12 | urlRegexString = `https://f\d{1,3}.megaup.net/core/page/ajax/file_upload_handler.ajax.php\?` + 13 | `r=megaup.net&p=https&csaKey1=[a-z\d]{64}&csaKey2=[a-z\d]{64}` 14 | sessTrackRegexString = `_sessionid: '([a-z\d]{26})'. cTracker: '([a-z\d]{32})'` 15 | ) 16 | 17 | func getUploadUrl() (string, string, string, error) { 18 | 19 | html, err := utils.GetHtml(referer) 20 | if err != nil { 21 | return "", "", "", err 22 | } 23 | match := utils.FindStringSubmatch(html, urlRegexString) 24 | if err != nil { 25 | return "", "", "", err 26 | } 27 | if match == nil { 28 | return "", "", "", errors.New("No regex match.") 29 | } 30 | 31 | match = utils.FindStringSubmatch(html, sessTrackRegexString) 32 | if err != nil { 33 | return "", "", "", err 34 | } 35 | if match == nil { 36 | return "", "", "", errors.New("No regex match.") 37 | } 38 | return match[0], match[1], match[2], nil 39 | } 40 | 41 | func upload(uploadUrl, path string, size, byteLimit int64, formMap, headers map[string]string) (string, error) { 42 | respBody, err := utils.MultipartUpload(uploadUrl, path, "files[]", size, byteLimit, formMap, nil, headers) 43 | if err != nil { 44 | return "", err 45 | } 46 | defer respBody.Close() 47 | var obj Upload 48 | err = json.NewDecoder(respBody).Decode(&obj) 49 | if err != nil { 50 | return "", err 51 | } 52 | returnedSize, err := strconv.ParseInt(obj[0].Size, 10, 64) 53 | if err != nil { 54 | return "", err 55 | } 56 | if obj[0].Error != nil { 57 | return "", errors.New("Bad response.") 58 | } else if returnedSize != size { 59 | return "", errors.New("Byte count mismatch.") 60 | } 61 | return obj[0].URL, nil 62 | } 63 | 64 | func Run(args *utils.Args, path string) (string, error) { 65 | uploadUrl, sessionId, tracker, err := getUploadUrl() 66 | if err != nil { 67 | return "", err 68 | } 69 | size, err := utils.CheckSize(path, "5GB") 70 | if err != nil { 71 | return "", err 72 | } 73 | formMap := map[string]string{ 74 | "_sessionid": sessionId, 75 | "cTracker": tracker, 76 | "folderId": "", 77 | "maxChunkSize": "100000000", 78 | } 79 | headers := map[string]string{ 80 | "Referer": referer, 81 | } 82 | fileUrl, err := upload(uploadUrl, path, size, args.ByteLimit, formMap, headers) 83 | return fileUrl, err 84 | } 85 | -------------------------------------------------------------------------------- /hosts/megaup/structs.go: -------------------------------------------------------------------------------- 1 | package megaup 2 | 3 | type Upload []struct { 4 | Name string `json:"name"` 5 | Size string `json:"size"` 6 | Type string `json:"type"` 7 | Error interface{} `json:"error"` 8 | URL string `json:"url"` 9 | DeleteURL string `json:"delete_url"` 10 | InfoURL string `json:"info_url"` 11 | DeleteType string `json:"delete_type"` 12 | DeleteHash string `json:"delete_hash"` 13 | Hash string `json:"hash"` 14 | StatsURL string `json:"stats_url"` 15 | ShortURL string `json:"short_url"` 16 | FileID string `json:"file_id"` 17 | UniqueHash string `json:"unique_hash"` 18 | URLHTML string `json:"url_html"` 19 | URLBbcode string `json:"url_bbcode"` 20 | SuccessResultHTML string `json:"success_result_html"` 21 | } 22 | -------------------------------------------------------------------------------- /hosts/mixdrop/mixdrop.go: -------------------------------------------------------------------------------- 1 | package mixdrop 2 | 3 | import ( 4 | "encoding/json" 5 | "main/utils" 6 | ) 7 | 8 | const ( 9 | referer = "https://mixdrop.co/" 10 | uploadUrl = "https://ul.mixdrop.co/up" 11 | ) 12 | 13 | func upload(path string, size, byteLimit int64, headers, formMap map[string]string) (string, error) { 14 | respBody, err := utils.MultipartUpload(uploadUrl, path, "files", size, byteLimit, formMap, nil, nil) 15 | if err != nil { 16 | return "", err 17 | } 18 | defer respBody.Close() 19 | var obj UploadResp 20 | err = json.NewDecoder(respBody).Decode(&obj) 21 | if err != nil { 22 | return "", err 23 | } 24 | return referer + "f/" + obj.File.Ref, nil 25 | } 26 | 27 | func Run(args *utils.Args, path string) (string, error) { 28 | size, err := utils.CheckSize(path, "unlim") 29 | if err != nil { 30 | return "", err 31 | } 32 | headers := map[string]string{ 33 | "Referer": referer, 34 | } 35 | formMap := map[string]string{ 36 | "upload": "1", 37 | } 38 | fileUrl, err := upload(path, size, args.ByteLimit, headers, formMap) 39 | return fileUrl, err 40 | } 41 | -------------------------------------------------------------------------------- /hosts/mixdrop/structs.go: -------------------------------------------------------------------------------- 1 | package mixdrop 2 | 3 | type UploadResp struct { 4 | File struct { 5 | Ref string `json:"ref"` 6 | } `json:"file"` 7 | } 8 | -------------------------------------------------------------------------------- /hosts/onefichier/1fichier.go: -------------------------------------------------------------------------------- 1 | // Needs content length header (size of file + form). MultipartUpload func doesn't support this yet. 2 | 3 | package onefichier 4 | 5 | import ( 6 | "encoding/json" 7 | "errors" 8 | "main/utils" 9 | "strconv" 10 | ) 11 | 12 | const apiBase = "https://www.filemail.com/api/transfer/" 13 | 14 | func getServer(headers map[string]string) (string, string, error) { 15 | url := "https://api.1fichier.com/v1/upload/get_upload_server.cgi" 16 | headers["Content-Type"] = "application/json" 17 | respBody, err := utils.DoGet(url, nil, headers) 18 | if err != nil { 19 | return "", "", err 20 | } 21 | defer respBody.Close() 22 | var obj GetServer 23 | err = json.NewDecoder(respBody).Decode(&obj) 24 | if err != nil { 25 | return "", "", err 26 | } 27 | return "https://" + obj.URL, obj.ID, nil 28 | } 29 | 30 | func upload(uploadUrl, path, id string, size int64, headers map[string]string) error { 31 | uploadUrl += "/upload.cgi" 32 | params := map[string]string{ 33 | "id": id, 34 | } 35 | formMap := map[string]string{ 36 | "send_ssl": "on", 37 | "domain": "0", 38 | "mail": "", 39 | "dpass": "", 40 | "user": "", 41 | "mails": "", 42 | "message": "", 43 | "submit": "Send", 44 | } 45 | respBody, err := utils.MultipartUpload(uploadUrl, path, "file[]", size, formMap, params, headers) 46 | if err != nil { 47 | return err 48 | } 49 | respBody.Close() 50 | return nil 51 | } 52 | 53 | func finalizeUpload(finalizeUrl, id string, size int64, headers map[string]string) (string, error) { 54 | params := map[string]string{ 55 | "xid": id, 56 | } 57 | finalizeUrl += "/end.pl" 58 | headers["Content-Type"] = "application/json" 59 | respBody, err := utils.DoGet(finalizeUrl, params, headers) 60 | if err != nil { 61 | return "", err 62 | } 63 | defer respBody.Close() 64 | var obj Finalize 65 | err = json.NewDecoder(respBody).Decode(&obj) 66 | if err != nil { 67 | return "", err 68 | } 69 | returnedSize, err := strconv.ParseInt(obj.Links[0].Size, 10, 64) 70 | if err != nil { 71 | return "", err 72 | } 73 | if returnedSize != size { 74 | return "", errors.New("Byte count mismatch.") 75 | } 76 | return obj.Links[0].Download, nil 77 | } 78 | 79 | func Run(args *utils.Args, path string) (string, error) { 80 | size, err := utils.CheckSize(path, "300GB") 81 | if err != nil { 82 | return "", err 83 | } 84 | headers := map[string]string{ 85 | "Referer": "https://1fichier.com/", 86 | } 87 | server, id, err := getServer(headers) 88 | if err != nil { 89 | return "", err 90 | } 91 | err = upload(server, path, id, size, headers) 92 | if err != nil { 93 | return "", err 94 | } 95 | fileUrl, err := finalizeUpload(server, id, size, headers) 96 | return fileUrl, err 97 | } 98 | -------------------------------------------------------------------------------- /hosts/onefichier/structs.go: -------------------------------------------------------------------------------- 1 | package onefichier 2 | 3 | type GetServer struct { 4 | ID string `json:"id"` 5 | URL string `json:"url"` 6 | } 7 | 8 | type Finalize struct { 9 | Incoming int `json:"incoming"` 10 | Links []struct { 11 | Download string `json:"download"` 12 | Filename string `json:"filename"` 13 | Remove string `json:"remove"` 14 | Size string `json:"size"` 15 | Whirlpool string `json:"whirlpool"` 16 | } `json:"links"` 17 | } 18 | -------------------------------------------------------------------------------- /hosts/pixeldrain/pixeldrain.go: -------------------------------------------------------------------------------- 1 | package pixeldrain 2 | 3 | import ( 4 | "encoding/json" 5 | "errors" 6 | "main/utils" 7 | ) 8 | 9 | const ( 10 | referer = "https://pixeldrain.com/" 11 | uploadUrl = referer + "api/file" 12 | ) 13 | 14 | func upload(path string, size, byteLimit int64, headers map[string]string) (string, error) { 15 | respBody, err := utils.MultipartUpload(uploadUrl, path, "file", size, byteLimit, nil, nil, headers) 16 | if err != nil { 17 | return "", err 18 | } 19 | defer respBody.Close() 20 | var obj Upload 21 | err = json.NewDecoder(respBody).Decode(&obj) 22 | if err != nil { 23 | return "", err 24 | } 25 | if !obj.Success { 26 | return "", errors.New("Bad response.") 27 | } 28 | url := referer + "u/" + obj.ID 29 | return url, nil 30 | } 31 | 32 | func Run(args *utils.Args, path string) (string, error) { 33 | size, err := utils.CheckSize(path, "10GB") 34 | if err != nil { 35 | return "", err 36 | } 37 | headers := map[string]string{ 38 | "Referer": referer, 39 | } 40 | fileUrl, err := upload(path, size, args.ByteLimit, headers) 41 | return fileUrl, err 42 | } 43 | -------------------------------------------------------------------------------- /hosts/pixeldrain/structs.go: -------------------------------------------------------------------------------- 1 | package pixeldrain 2 | 3 | type Upload struct { 4 | Success bool `json:"success"` 5 | ID string `json:"id"` 6 | } 7 | -------------------------------------------------------------------------------- /hosts/racaty/racaty.go: -------------------------------------------------------------------------------- 1 | package racaty 2 | 3 | import ( 4 | "encoding/json" 5 | "errors" 6 | "fmt" 7 | "main/utils" 8 | ) 9 | 10 | const ( 11 | referer = "https://racaty.net/" 12 | uloadUrlRegexStr = `