<commit_before>package osdb

import (
	"fmt"
	"io"
	"os"
	"strconv"
	"strings"

	"github.com/kolo/xmlrpc"
)

const (
	OSDBServer       = "http://api.opensubtitles.org/xml-rpc"
	DefaultUserAgent = "OS Test User Agent" // OSDB's test agent
	SearchLimit      = 100
	SuccessStatus    = "200 OK"
)

type Client struct {
	UserAgent string
	Token     string
	Login     string
	Password  string
	Language  string
	*xmlrpc.Client
}

// Search subtitles in `languages` for a file at `path`.
func (c *Client) FileSearch(path string, langs []string) ([]Subtitle, error) {
	// OSDB search params struct
	params, err := c.hashSearchParams(path, langs)
	if err != nil {
		return nil, err
	}
	res := struct {
		Data []Subtitle `xmlrpc:"data"`
	}{}

	if err = c.Call("SearchSubtitles", *params, &res); err != nil {
		return nil, err
	}

	return res.Data, nil
}

// Download subtitles by file ID.
func (c *Client) DownloadSubtitles(ids []int) ([]SubtitleFile, error) {
	params := []interface{}{c.Token, ids}
	res := struct {
		Status string         `xmlrpc:"status"`
		Data   []SubtitleFile `xmlrpc:"data"`
	}{}
	if err := c.Call("DownloadSubtitles", params, &res); err != nil {
		return nil, err
	}

	return res.Data, nil
}

// Save subtitle file to disk, using the OSDB specified name.
func (c *Client) Download(s *Subtitle) error {
	return c.DownloadTo(s, s.SubFileName)
}

// Save subtitle file to disk, using the specified path.
func (c *Client) DownloadTo(s *Subtitle, path string) (err error) {
	id, err := strconv.Atoi(s.IDSubtitleFile)
	if err != nil {
		return
	}

	// Download
	files, err := c.DownloadSubtitles([]int{id})
	if err != nil {
		return err
	}
	if len(files) == 0 {
		return fmt.Errorf("No file match this subtitle ID")
	}

	// Save to disk.
	file := files[0]
	r, err := file.Reader()
	if err != nil {
		return
	}
	defer r.Close()

	w, err := os.Create(path)
	if err != nil {
		return
	}
	defer w.Close()

	_, err = io.Copy(w, r)
	return
}

// Checks wether a subtitle already exists in OSDB. The mandatory fields
// in the received Subtitle map are: subhash, subfilename, moviehash,
// moviebytesize, and moviefilename.
func (c *Client) HasSubtitles(subs map[string]Subtitle) (bool, error) {
	args := []interface{}{c.Token, &subs}
	res := struct {
		Status string     `xmlrpc:"status"`
		Exists bool       `xmlrpc:"alreadyindb"`
		Data   []Subtitle `xmlrpc:"data"`
	}{}
	if err := c.Call("TryUploadSubtitles", args, &res); err != nil {
		return false, err
	}
	return res.Exists, nil
}

// Login to the API, and return a session token.
func (c *Client) LogIn(user string, pass string, lang string) (err error) {
	c.Login = user
	c.Password = <PASSWORD>
	c.Language = lang
	args := []interface{}{user, pass, lang, c.UserAgent}
	res := struct {
		Status string `xmlrpc:"status"`
		Token  string `xmlrpc:"token"`
	}{}
	if err = c.Call("LogIn", args, &res); err != nil {
		return
	}<commit_msg>Use a slice param for HasSubtitles<commit_after>package osdb

import (
	"fmt"
	"io"
	"os"
	"strconv"
	"strings"

	"github.com/kolo/xmlrpc"
)

const (
	OSDBServer       = "http://api.opensubtitles.org/xml-rpc"
	DefaultUserAgent = "OS Test User Agent" // OSDB's test agent
	SearchLimit      = 100
	SuccessStatus    = "200 OK"
)

type Client struct {
	UserAgent string
	Token     string
	Login     string
	Password  string
	Language  string
	*xmlrpc.Client
}

// Search subtitles in `languages` for a file at `path`.
func (c *Client) FileSearch(path string, langs []string) ([]Subtitle, error) {
	// OSDB search params struct
	params, err := c.hashSearchParams(path, langs)
	if err != nil {
		return nil, err
	}
	res := struct {
		Data []Subtitle `xmlrpc:"data"`
	}{}

	if err = c.Call("SearchSubtitles", *params, &res); err != nil {
		return nil, err
	}

	return res.Data, nil
}

// Download subtitles by file ID.
func (c *Client) DownloadSubtitles(ids []int) ([]SubtitleFile, error) {
	params := []interface{}{c.Token, ids}
	res := struct {
		Status string         `xmlrpc:"status"`
		Data   []SubtitleFile `xmlrpc:"data"`
	}{}
	if err := c.Call("DownloadSubtitles", params, &res); err != nil {
		return nil, err
	}

	return res.Data, nil
}

// Save subtitle file to disk, using the OSDB specified name.
func (c *Client) Download(s *Subtitle) error {
	return c.DownloadTo(s, s.SubFileName)
}

// Save subtitle file to disk, using the specified path.
func (c *Client) DownloadTo(s *Subtitle, path string) (err error) {
	id, err := strconv.Atoi(s.IDSubtitleFile)
	if err != nil {
		return
	}

	// Download
	files, err := c.DownloadSubtitles([]int{id})
	if err != nil {
		return err
	}
	if len(files) == 0 {
		return fmt.Errorf("No file match this subtitle ID")
	}

	// Save to disk.
	file := files[0]
	r, err := file.Reader()
	if err != nil {
		return
	}
	defer r.Close()

	w, err := os.Create(path)
	if err != nil {
		return
	}
	defer w.Close()

	_, err = io.Copy(w, r)
	return
}

// Checks wether a subtitle already exists in OSDB. The mandatory fields
// in the received Subtitle map are: subhash, subfilename, moviehash,
// moviebytesize, and moviefilename.
func (c *Client) HasSubtitles(subs []Subtitle) (bool, error) {
	// Convert subs param to map[string]Subtitle, because OSDb.
	subMap := map[string]Subtitle{}
	for i, s := range subs {
		key := "cd" + strconv.Itoa(i+1) // keys are cd1, cd2, ...
		subMap[key] = s
	}

	args := []interface{}{c.Token, &subMap}
	res := struct {
		Status string     `xmlrpc:"status"`
		Exists bool       `xmlrpc:"alreadyindb"`
		Data   []Subtitle `xmlrpc:"data"`
	}{}
	if err := c.Call("TryUploadSubtitles", args, &res); err != nil {
		return false, err
	}

	return res.Exists, nil
}

// Login to the API, and return a session token.
func (c *Client) LogIn(user string, pass string, lang string) (err error) {
	c.Login = user
	c.Password = <PASSWORD>
	c.Language = lang
	args := []interface{}{user, pass, lang, c.UserAgent}
	res := struct {
		Status string `xmlrpc:"status"`
		Token  string `xmlrpc:"token"`
	}{}
	if err = c.Call("LogIn", args, &res); err != nil {
		return
	}
{'fraction_non_alphanumeric': 0.14782753454303313, 'fraction_numerical': 0.003162976527384718, 'mean_word_length': 3.456973293768546, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 22}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 16, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2159375', 'n_tokens_mistral': 2228, 'n_tokens_neox': 2168, 'n_words': 666}