package qbittorrent_util import ( "bytes" "fmt" "github.com/goccy/go-json" "io" "mime/multipart" "net/http" "net/textproto" "seanime/internal/torrent_clients/qbittorrent/model" "strings" ) func GetInto(client *http.Client, target interface{}, url string, body interface{}) (err error) { var buffer bytes.Buffer if body != nil { if err := json.NewEncoder(&buffer).Encode(body); err != nil { return err } } r, err := http.NewRequest("GET", url, &buffer) if err != nil { return err } resp, err := client.Do(r) if err != nil { return err } defer func() { if err2 := resp.Body.Close(); err2 != nil { err = err2 } }() if resp.StatusCode != http.StatusOK { return fmt.Errorf("invalid response status %s", resp.Status) } buf, err := io.ReadAll(resp.Body) if err != nil { return err } if err := json.NewDecoder(bytes.NewReader(buf)).Decode(target); err != nil { if err2 := json.NewDecoder(strings.NewReader(`"` + string(buf) + `"`)).Decode(target); err2 != nil { return err } } return nil } func Post(client *http.Client, url string, body interface{}) (err error) { var buffer bytes.Buffer if err := json.NewEncoder(&buffer).Encode(body); err != nil { return err } r, err := http.NewRequest("POST", url, &buffer) if err != nil { return err } resp, err := client.Do(r) if err != nil { return err } defer func() { if err2 := resp.Body.Close(); err2 != nil { err = err2 } }() if resp.StatusCode != http.StatusOK { return fmt.Errorf("invalid status %s", resp.Status) } return nil } func createFormFileWithHeader(writer *multipart.Writer, name, filename string, headers map[string]string) (io.Writer, error) { header := textproto.MIMEHeader{} header.Add("Content-Disposition", fmt.Sprintf(`form-data; name="%s"; filename="%s"`, name, filename)) for key, value := range headers { header.Add(key, value) } return writer.CreatePart(header) } func PostMultipartLinks(client *http.Client, url string, options *qbittorrent_model.AddTorrentsOptions, links []string) (err error) { var o map[string]interface{} if options != nil { b, err := json.Marshal(options) if err != nil { return err } if err := json.Unmarshal(b, &o); err != nil { return err } } buf := bytes.Buffer{} form := multipart.NewWriter(&buf) if err := form.WriteField("urls", strings.Join(links, "\n")); err != nil { return err } for key, value := range o { if err := form.WriteField(key, fmt.Sprintf("%v", value)); err != nil { return err } } if err := form.Close(); err != nil { return err } req, err := http.NewRequest("POST", url, &buf) if err != nil { return err } req.Header.Add("content-type", "multipart/form-data; boundary="+form.Boundary()) resp, err := client.Do(req) if err != nil { return err } defer func() { if err2 := resp.Body.Close(); err2 != nil { err = err2 } }() if resp.StatusCode != http.StatusOK { return fmt.Errorf("invalid status %s", resp.Status) } return nil } func PostMultipartFiles(client *http.Client, url string, options *qbittorrent_model.AddTorrentsOptions, files map[string][]byte) (err error) { var o map[string]interface{} if options != nil { b, err := json.Marshal(options) if err != nil { return err } if err := json.Unmarshal(b, &o); err != nil { return err } } buf := bytes.Buffer{} form := multipart.NewWriter(&buf) for filename, file := range files { writer, err := createFormFileWithHeader(form, "torrents", filename, map[string]string{ "content-type": "application/x-bittorrent", }) if err != nil { return err } if _, err := writer.Write(file); err != nil { return err } } for key, value := range o { if err := form.WriteField(key, fmt.Sprintf("%v", value)); err != nil { return err } } if err := form.Close(); err != nil { return err } req, err := http.NewRequest("POST", url, &buf) if err != nil { return err } req.Header.Add("content-type", "multipart/form-data; boundary="+form.Boundary()) resp, err := client.Do(req) if err != nil { return err } defer func() { if err2 := resp.Body.Close(); err2 != nil { err = err2 } }() if resp.StatusCode != http.StatusOK { return fmt.Errorf("invalid status %s", resp.Status) } return nil } func PostWithContentType(client *http.Client, url string, body io.Reader, contentType string) (err error) { r, err := http.NewRequest("POST", url, body) if err != nil { return err } r.Header.Add("content-type", contentType) resp, err := client.Do(r) if err != nil { return err } defer func() { if err2 := resp.Body.Close(); err2 != nil { err = err2 } }() if resp.StatusCode != http.StatusOK { return fmt.Errorf("invalid status %s", resp.Status) } return nil } func GetIntoWithContentType(client *http.Client, target interface{}, url string, body io.Reader, contentType string) (err error) { r, err := http.NewRequest("GET", url, body) if err != nil { return err } r.Header.Add("content-type", contentType) resp, err := client.Do(r) if err != nil { return err } defer func() { if err2 := resp.Body.Close(); err2 != nil { err = err2 } }() if resp.StatusCode != http.StatusOK { return fmt.Errorf("invalid response status %s", resp.Status) } buf, err := io.ReadAll(resp.Body) if err != nil { return err } if err := json.NewDecoder(bytes.NewReader(buf)).Decode(target); err != nil { if err2 := json.NewDecoder(strings.NewReader(`"` + string(buf) + `"`)).Decode(target); err2 != nil { return err } } return nil }