Advertisement
Guest User

Rclone Uptobox Beta 0.4 [FOLDER HOTFIX]

a guest
Mar 23rd, 2017
370
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Go 27.18 KB | None | 0 0
  1. package uptobox
  2.  
  3. import (
  4.     "github.com/ncw/rclone/fs"
  5.     "github.com/pkg/errors"
  6.     "net/http"
  7.     "net/http/cookiejar"
  8.     "net/url"
  9.     "encoding/json"
  10.     "time"
  11.     "io"
  12.     "github.com/ncw/rclone/dircache"
  13.     "path"
  14.     "strings"
  15.     "github.com/PuerkitoBio/goquery"
  16.     "regexp"
  17.     "strconv"
  18.     "mime/multipart"
  19.     "bytes"
  20.     "io/ioutil"
  21. )
  22.  
  23. func init() {
  24.     fs.Register(&fs.RegInfo{
  25.         Name:        "Uptobox",
  26.         Description: "Uptobox Drive",
  27.         NewFs:       NewFs,
  28.         Options: []fs.Option{
  29.             {
  30.                 Name:     "name",
  31.                 Help:     "Uptobox username",
  32.                 Optional: false,
  33.             },
  34.             {
  35.                 Name:       "pass",
  36.                 Help:       "Uptobox password",
  37.                 Optional:   false,
  38.                 IsPassword: true,
  39.             },
  40.             {
  41.                 Name:     "preferedServer",
  42.                 Help:     "Prefered uptobox servers to upload (None/OVH/Online)",
  43.                 Optional: true,
  44.             },
  45.         },
  46.     })
  47. }
  48.  
  49. type Fs struct {
  50.     name       string
  51.     root       string
  52.     features   *fs.Features // optional features
  53.     token      string
  54.     dirCache   *dircache.DirCache
  55.     trueRootID string
  56.     httpClient *http.Client
  57. }
  58.  
  59. type Object struct {
  60.     fs     *Fs
  61.     remote string
  62.     id     string
  63.     size   int64
  64.     date   time.Time
  65.     numId  string
  66. }
  67.  
  68. type loginResponse struct {
  69.     Error   string `json:"error"`
  70.     Success string `json:"success"`
  71.     Msg     string `json:"msg"`
  72. }
  73.  
  74. type fileUploadResponse struct {
  75.     Name      string `json:"name"`
  76.     DeleteUrl string `json:"deleteUrl"`
  77.     Size      int    `json:"size"`
  78.     Url       string `json:"url"`
  79. }
  80.  
  81. type uploadResponse struct {
  82.     Files []fileUploadResponse `json:"files"`
  83. }
  84.  
  85. // NewFs constructs an Fs from the path, container:path
  86. func NewFs(name, root string) (fs.Fs, error) {
  87.     //TODO Defer body close
  88.     //TODO Replace Each EachWithBreak
  89.     root = strings.Trim(root, "/")
  90.     user := fs.ConfigFileGet(name, "name")
  91.     pass := fs.ConfigFileGet(name, "pass")
  92.  
  93.     if user == "" {
  94.         return nil, errors.New("No username specified")
  95.     }
  96.     if pass == "" {
  97.         return nil, errors.New("No password speciefied")
  98.     }
  99.     pass, err := fs.Reveal(pass)
  100.     if err != nil {
  101.         return nil, err
  102.     }
  103.  
  104.     // Get auth cookie
  105.     resp, err := http.PostForm("https://login.uptobox.com/logarithme",
  106.         url.Values{"login": {user}, "password": {pass}, "op": {"login"}})
  107.  
  108.     if err != nil || resp.StatusCode != 200 {
  109.         return nil, errors.New("Can't login")
  110.     }
  111.  
  112.     var jsonResponse loginResponse
  113.     err = json.NewDecoder(resp.Body).Decode(&jsonResponse)
  114.  
  115.     if err != nil {
  116.         return nil, err
  117.     }
  118.     if jsonResponse.Error != "" {
  119.         return nil, errors.New(jsonResponse.Error)
  120.     }
  121.  
  122.     // Get Cookie
  123.     cookie := ""
  124.     for _, ck := range resp.Cookies() {
  125.         if ck.Name == "xfss" {
  126.             cookie = ck.Value
  127.             break
  128.         }
  129.     }
  130.     if cookie == "" {
  131.         return nil, errors.New("Invalid authentification cookie")
  132.     }
  133.  
  134.     // Create http client with auth cookie
  135.     u, _ := url.Parse("https://uptobox.com")
  136.     jar, _ := cookiejar.New(nil)
  137.     jar.SetCookies(u, []*http.Cookie{{
  138.         Name:   "xfss",
  139.         Value:  cookie,
  140.         Path:   "/",
  141.         Domain: ".uptobox.com",
  142.     }})
  143.  
  144.     // FS structure
  145.     f := &Fs{
  146.         name:       name,
  147.         root:       root,
  148.         token:      "",
  149.         trueRootID: "0",
  150.         httpClient: &http.Client{
  151.             Jar: jar,
  152.             CheckRedirect: func(req *http.Request, via []*http.Request) error {
  153.                 return http.ErrUseLastResponse
  154.             },
  155.         },
  156.     }
  157.  
  158.     //Retrieve Uptobox Token
  159.     resp, err = f.httpClient.Get("https://uptobox.com/?op=my_files")
  160.     defer resp.Body.Close()
  161.  
  162.     doc, err := goquery.NewDocumentFromReader(resp.Body)
  163.     if err != nil {
  164.         return nil, err
  165.     }
  166.  
  167.     // Extract token
  168.     // Todo : Optimize
  169.     doc.Find(".input_append input[name=token]").Each(func(idx int, sel *goquery.Selection) {
  170.         for _, a := range sel.Nodes[0].Attr {
  171.             if a.Key == "value" {
  172.                 f.token = a.Val
  173.             }
  174.         }
  175.     })
  176.  
  177.     // Set features
  178.     f.features = (&fs.Features{}).Fill(f)
  179.  
  180.     // Init dircache
  181.     f.dirCache = dircache.New(root, "0", f)
  182.     err = f.dirCache.FindRoot(false)
  183.     if err != nil {
  184.         // Assume it is a file
  185.         newRoot, remote := dircache.SplitPath(root)
  186.         newF := *f
  187.         newF.dirCache = dircache.New(newRoot, f.trueRootID, &newF)
  188.         newF.root = newRoot
  189.         // Make new Fs which is the parent
  190.         err = newF.dirCache.FindRoot(false)
  191.         if err != nil {
  192.             // No root so return old f
  193.             return f, nil
  194.         }
  195.         //Find File
  196.         _, err := f.FindFile(newF.dirCache.RootID(), remote, 1)
  197.         if err != nil {
  198.             if err == fs.ErrorObjectNotFound {
  199.                 // File doesn't exist so return old f
  200.                 return f, nil
  201.             }
  202.             return nil, err
  203.         }
  204.         // return an error with an fs which points to the parent
  205.         return &newF, fs.ErrorIsFile
  206.     }
  207.     // Return fs
  208.     return f, nil
  209. }
  210.  
  211. func getDir(remote string) (string) {
  212.     dirPath := path.Dir(remote)
  213.     if dirPath == "." {
  214.         return ""
  215.     }
  216.     return dirPath
  217. }
  218.  
  219. // Name of the remote (as passed into NewFs)
  220. func (f *Fs) Name() string {
  221.     return f.name
  222. }
  223.  
  224. // Root of the remote (as passed into NewFs)
  225. func (f *Fs) Root() string {
  226.     return f.root
  227. }
  228.  
  229. // String converts this Fs to a string
  230. func (f *Fs) String() string {
  231.     return "Uptobox"
  232. }
  233.  
  234. // Precision return the precision of this Fs
  235. func (f *Fs) Precision() time.Duration {
  236.     return time.Second
  237. }
  238.  
  239. // Hashes returns the supported hash sets.
  240. func (f *Fs) Hashes() fs.HashSet {
  241.     return fs.HashSet(fs.HashNone)
  242. }
  243.  
  244. // Features returns the optional features of this Fs
  245. func (f *Fs) Features() *fs.Features {
  246.     return f.features
  247. }
  248.  
  249. //List files page per page
  250. func (f *Fs) ListFiles(out fs.ListOpts, job dircache.ListDirJob, page int) (error) {
  251.     maxTries := fs.Config.LowLevelRetries
  252.  
  253.     for tries := 1; tries <= maxTries; tries++ {
  254.         resp, err := f.httpClient.Get("https://uptobox.com/?op=my_files&fld_id=" + job.DirID + "&page=" + strconv.Itoa(page))
  255.  
  256.         if err != nil || resp.StatusCode != 200 {
  257.             time.Sleep(time.Duration(tries*500) * time.Millisecond)
  258.             fs.Debugf(f, "Directory listing failed for %q, low level retry %d/%d", job.Path, tries, maxTries)
  259.             continue
  260.         }
  261.  
  262.         doc, _ := goquery.NewDocumentFromReader(resp.Body)
  263.  
  264.         // Extract Files
  265.         doc.Find("table.files .cell_files").Each(func(idx int, sel *goquery.Selection) {
  266.             name, _ := sel.Find("td:nth-child(2) a").Html()
  267.             fileUrl, _ := sel.Find("td:nth-child(2) a").Attr("href")
  268.             id := path.Base(fileUrl)
  269.  
  270.             // Only for real files
  271.             if name != "&nbsp;" && name != "" && name != " " {
  272.  
  273.                 //Get The file informations
  274.                 fullfile, err := f.GetFile(id, job.Path)
  275.                 if err != nil {
  276.                     return
  277.                 }
  278.  
  279.                 //Save the numId
  280.                 fullfile.numId, _ = sel.Find("td:nth-child(1) input").Attr("value")
  281.  
  282.                 out.Add(fullfile)
  283.             }
  284.         })
  285.         resp.Body.Close()
  286.  
  287.         //If there is a next page, go for it
  288.         nextLink := doc.Find("div.paging:nth-child(1) a").Last()
  289.         if nextLink.Text() == "Next ยป" {
  290.             return f.ListFiles(out, job, page + 1)
  291.         }
  292.  
  293.         return nil
  294.     }
  295.     return errors.New("Failed to read directory " + job.Path)
  296. }
  297.  
  298. // ListDir reads the directory specified by the job into out, returning any more jobs
  299. func (f *Fs) ListDir(out fs.ListOpts, job dircache.ListDirJob) (jobs []dircache.ListDirJob, err error) {
  300.  
  301.     // Get max tries value
  302.     maxTries := fs.Config.LowLevelRetries
  303.  
  304.     // Try
  305.     for tries := 1; tries <= maxTries; tries++ {
  306.  
  307.         // Send request
  308.         resp, err := f.httpClient.Get("https://uptobox.com/?op=my_files&fld_id=" + job.DirID)
  309.  
  310.         // Check http code and retry
  311.         if err != nil || resp.StatusCode != 200 {
  312.             time.Sleep(time.Duration(tries*500) * time.Millisecond)
  313.             fs.Debugf(f, "Directory listing failed for %q, low level retry %d/%d", job.Path, tries, maxTries)
  314.             continue
  315.         }
  316.  
  317.         // Parse HTML
  318.         doc, _ := goquery.NewDocumentFromReader(resp.Body)
  319.  
  320.         // Extract Folders
  321.         doc.Find("table.files td:not([style='max-width:1000px;']):nth-child(1) a").Each(func(idx int, sel *goquery.Selection) {
  322.             reg, _ := regexp.Compile("(.*) \\((.*)$")
  323.             name := reg.ReplaceAllString(sel.Text(), "$1")
  324.             dirlink, _ := sel.Attr("href")
  325.             dirid := strings.Replace(dirlink, "?op=my_files&fld_id=", "", 1)
  326.  
  327.             if out.IncludeDirectory(job.Path + name) {
  328.  
  329.                 // Only for reals paths
  330.                 if name != "&nbsp;" && name != "" && name != " " {
  331.  
  332.                     // Create dir item
  333.                     dir := &fs.Dir{
  334.                         Name:  job.Path + name,
  335.                         Bytes: -1,
  336.                         Count: -1,
  337.                     }
  338.  
  339.                     // Add directory
  340.                     if out.AddDir(dir) {
  341.                         return
  342.                     }
  343.  
  344.                     // Recursive path
  345.                     if job.Depth > 0 {
  346.                         jobs = append(jobs, dircache.ListDirJob{DirID: dirid, Path: job.Path + name + "/", Depth: job.Depth - 1})
  347.                     }
  348.                 }
  349.             }
  350.         })
  351.  
  352.         // Close HTML Request
  353.         resp.Body.Close()
  354.  
  355.         //Get Files
  356.         err = f.ListFiles(out, job, 1)
  357.         if err != nil {
  358.             return nil, err
  359.         }
  360.  
  361.         // Return directory
  362.         return jobs, nil
  363.     }
  364.  
  365.     // Error
  366.     return nil, errors.New("Failed to read directory " + job.Path)
  367. }
  368.  
  369. // List walks the path returning files and directories into out
  370. func (f *Fs) List(out fs.ListOpts, dir string) {
  371.     f.dirCache.List(f, out, dir)
  372. }
  373.  
  374. func (f *Fs) NewObject(remote string) (fs.Object, error) {
  375.     return f.FindFile(f.dirCache.RootID(), remote, 1)
  376. }
  377.  
  378. func (f *Fs) getNumId(srcObj *Object, dirId string, page int) (string, error) {
  379.     if srcObj.numId != "" {
  380.         return srcObj.numId, nil
  381.     }
  382.  
  383.     maxTries := fs.Config.LowLevelRetries
  384.  
  385.     for tries := 1; tries <= maxTries; tries++ {
  386.         // Send request
  387.         resp, err := f.httpClient.Get("https://uptobox.com/?op=my_files&fld_id=" + dirId + "&page=" + strconv.Itoa(page))
  388.  
  389.         // Check http code and retry
  390.         if err != nil || resp.StatusCode != 200 {
  391.             time.Sleep(time.Duration(tries*500) * time.Millisecond)
  392.             fs.Debugf(f, "Directory listing failed for id %q, low level retry %d/%d", 0, tries, maxTries)
  393.             if tries+1 >= maxTries {
  394.                 return "", errors.New("Failed to request directory")
  395.             }
  396.             continue
  397.         }
  398.  
  399.         doc, _ := goquery.NewDocumentFromReader(resp.Body)
  400.         var numId string = ""
  401.  
  402.         doc.Find("table.files .cell_files").EachWithBreak(func(idx int, sel *goquery.Selection) (bool) {
  403.             fileUrl, _ := sel.Find("td:nth-child(2) a").Attr("href")
  404.             id := path.Base(fileUrl)
  405.  
  406.             if srcObj.id == id {
  407.                 numId, _ = sel.Find("td:nth-child(1) input").Attr("value")
  408.                 return false
  409.             }
  410.             return true
  411.         })
  412.         resp.Body.Close()
  413.  
  414.         if numId != "" {
  415.             return numId, nil
  416.         }
  417.  
  418.         //If there is a next page, go for it
  419.         nextLink := doc.Find("div.paging:nth-child(1) a").Last()
  420.         if nextLink.Text() == "Next ยป" {
  421.             return f.getNumId(srcObj, dirId, page + 1)
  422.         }
  423.  
  424.         break
  425.     }
  426.     return "", errors.New("File not found")
  427. }
  428.  
  429. func (f *Fs) Put(in io.Reader, src fs.ObjectInfo) (fs.Object, error) {
  430.     //Create upload dir
  431.     f.dirCache.FindRoot(true)
  432.  
  433.     //Get upload url
  434.     var uploadUrl string = ""
  435.     maxTries := fs.Config.LowLevelRetries
  436.     reg, _ := regexp.Compile(".*www(.*)\\.uptobox.*")
  437.     preferedServer := strings.ToLower(fs.ConfigFileGet(f.name, "preferedServer", "None"))
  438.  
  439.     for tries := 1; tries <= maxTries; tries++ {
  440.         resp, err := f.httpClient.Get("https://uptobox.com/")
  441.  
  442.         //Request failed
  443.         if err != nil || resp.StatusCode != 200 {
  444.             time.Sleep(time.Duration(tries*500) * time.Millisecond)
  445.             fs.Debugf(f, "Finding upload url failed, low level retry %d/%d", tries, maxTries)
  446.             continue
  447.         }
  448.  
  449.         doc, _ := goquery.NewDocumentFromReader(resp.Body)
  450.         tmpUrl, _ := doc.Find("form#fileupload").Attr("action")
  451.         resp.Body.Close()
  452.  
  453.         nb, _ := strconv.Atoi(reg.ReplaceAllString(tmpUrl, "$1"))
  454.         if (preferedServer == "online" && nb >= 50) ||
  455.             (preferedServer == "ovh" && nb < 50) ||
  456.             (preferedServer != "online" && preferedServer != "ovh") {
  457.             uploadUrl = tmpUrl
  458.             break
  459.         }
  460.         if uploadUrl == "" {
  461.             uploadUrl = tmpUrl
  462.         }
  463.         fs.Debugf(f, "Server found retrying, to find a better one. %d/%d", tries, maxTries)
  464.     }
  465.  
  466.     //TODO Retry upload ???
  467.     var bodyReader io.Reader
  468.     bodyReader, bodyWriter := io.Pipe()
  469.     writer := multipart.NewWriter(bodyWriter)
  470.     contentType := writer.FormDataContentType()
  471.     contentLength := int64(-1)
  472.  
  473.     buf := make([]byte, 1)
  474.     n, err := io.ReadFull(in, buf)
  475.     isZeroLength := err == io.EOF
  476.     if !isZeroLength && err != nil {
  477.         return nil, err
  478.     }
  479.     in = io.MultiReader(bytes.NewReader(buf[:n]), in)
  480.  
  481.     errChan := make(chan error, 1)
  482.     go func() {
  483.         defer bodyWriter.Close()
  484.         var err error
  485.  
  486.         part, err := writer.CreateFormFile("files[]", path.Base(src.Remote()))
  487.         if err != nil {
  488.             errChan <- err
  489.             return
  490.         }
  491.         if _, err := io.Copy(part, in); err != nil {
  492.             errChan <- err
  493.             return
  494.         }
  495.         errChan <- writer.Close()
  496.     }()
  497.  
  498.     if isZeroLength {
  499.         buf, err := ioutil.ReadAll(bodyReader)
  500.         if err != nil {
  501.             return nil, err
  502.         }
  503.         bodyReader = bytes.NewReader(buf)
  504.         contentLength = int64(len(buf))
  505.     }
  506.  
  507.     req, err := http.NewRequest("POST", uploadUrl, bodyReader)
  508.  
  509.     if err != nil {
  510.         return nil, err
  511.     }
  512.  
  513.     req.ContentLength = contentLength
  514.     req.Header.Add("Content-Type", contentType)
  515.     resp, err := f.httpClient.Do(req)
  516.     defer resp.Body.Close()
  517.  
  518.     if err != nil || resp.StatusCode != 200 {
  519.         err.Error()
  520.         return nil, errors.New("Failed to upload: bad response")
  521.     }
  522.  
  523.     var jsonResponse uploadResponse
  524.     err = json.NewDecoder(resp.Body).Decode(&jsonResponse)
  525.  
  526.     if err != nil || len(jsonResponse.Files) == 0 {
  527.         return nil, errors.New("Failed to upload: json deserialization")
  528.     }
  529.  
  530.     uploadId := path.Base(jsonResponse.Files[0].Url)
  531.  
  532.     //Find the numId to move file
  533.     numId, err := f.getNumId(&Object{id: uploadId}, "0", 1)
  534.     if err != nil {
  535.         return nil, errors.Wrap(err,"Upload failed")
  536.     }
  537.  
  538.     //Find the uploaded file and move it to the good location
  539.     //Get the id of the upload destination
  540.     uploadDir, err := f.dirCache.FindDir(getDir(src.Remote()), true)
  541.     if err != nil {
  542.         return nil, errors.Wrap(err, "Failed to find upload dir")
  543.     }
  544.  
  545.     //Move it
  546.     err = f.MoveToDir("0", uploadDir, numId)
  547.     if err != nil {
  548.         return nil, errors.Wrap(err, "Failed to upload, failed to move file")
  549.     }
  550.  
  551.     //Get the new object
  552.     obj, err := f.GetFile(uploadId, getDir(src.Remote()))
  553.     if err != nil {
  554.         return nil, errors.Wrap(err, "Failed to upload, failed to retrieve file")
  555.     }
  556.     obj.numId = numId
  557.     return obj, nil
  558.  
  559.     return nil, errors.New("Failed to upload")
  560. }
  561.  
  562. func (f *Fs) Mkdir(dir string) error {
  563.     err := f.dirCache.FindRoot(true)
  564.     if err != nil {
  565.         return err
  566.     }
  567.     if dir != "" {
  568.         _, err = f.dirCache.FindDir(dir, true)
  569.     }
  570.     return err
  571. }
  572.  
  573. // Rmdir deletes the root folder
  574. func (f *Fs) Rmdir(dir string) error {
  575.     // Get directory
  576.     dirId, err := f.dirCache.FindDir(dir, false)
  577.  
  578.     // If get directory failed
  579.     if err != nil {
  580.         return err
  581.     }
  582.  
  583.     // Get max tries value
  584.     maxTries := fs.Config.LowLevelRetries
  585.  
  586.     // Try
  587.     for tries := 1; tries <= maxTries; tries++ {
  588.  
  589.         // Send request
  590.         resp, _ := f.httpClient.Get("https://uptobox.com/?op=my_files&fld_id=0&del_folder=" + dirId + "&token=" + f.token)
  591.  
  592.         // Check success
  593.         if resp.StatusCode == 302 {
  594.             return nil
  595.         }
  596.     }
  597.     return errors.New("Directory deletion failed id:" + dirId + " " + dir)
  598. }
  599.  
  600. // Get Files informations from uid
  601. func (f *Fs) GetFile(fileuid string, basepath string) (*Object, error) {
  602.  
  603.     // Get max tries value
  604.     maxTries := fs.Config.LowLevelRetries
  605.  
  606.     // Try
  607.     for tries := 1; tries <= maxTries; tries++ {
  608.  
  609.         // Get advanced informations
  610.         fileInfo, err := f.httpClient.Get("https://uptobox.com/" + fileuid)
  611.  
  612.         // Check http code and retry
  613.         if err != nil || (fileInfo.StatusCode != 200 && fileInfo.StatusCode != 302) {
  614.             time.Sleep(time.Duration(tries*500) * time.Millisecond)
  615.             fs.Debugf(f, "Advanced file informations error for %q, low level retry %d/%d", fileuid, tries, maxTries)
  616.             continue
  617.         }
  618.  
  619.         // Parse HTML
  620.         fileHTML, _ := goquery.NewDocumentFromReader(fileInfo.Body)
  621.         fileSize, _ := fileHTML.Find("input[name='file_size_real']").Attr("value")
  622.         fullName, _ := fileHTML.Find("input[name='fname']").Attr("value")
  623.         rsize, _ := strconv.ParseInt(fileSize, 10, 64)
  624.  
  625.         // Close HTTP
  626.         fileInfo.Body.Close()
  627.  
  628.         // Return Object
  629.         return &Object{
  630.             fs:     f,
  631.             remote: path.Join(basepath, fullName),
  632.             id:     fileuid,
  633.             size:   rsize,
  634.             date:   time.Now(),
  635.         }, nil
  636.  
  637.         // TODO : Get Upload time from HEAD request on file download link
  638.         // TODO : Cache File request and File HEAD requests
  639.     }
  640.     return nil, fs.ErrorObjectNotFound
  641. }
  642.  
  643. func (f *Fs) FindFile(pathID string, filename string, page int) (*Object, error) {
  644.     maxTries := fs.Config.LowLevelRetries
  645.  
  646.     // Try
  647.     for tries := 1; tries <= maxTries; tries++ {
  648.         // Send request
  649.         resp, err := f.httpClient.Get("https://uptobox.com/?op=my_files&fld_id=" + pathID + "&page=" + strconv.Itoa(page))
  650.  
  651.         // Check http code and retry
  652.         if err != nil || resp.StatusCode != 200 {
  653.             time.Sleep(time.Duration(tries*500) * time.Millisecond)
  654.             fs.Debugf(f, "Directory listing failed for id %q, low level retry %d/%d", pathID, tries, maxTries)
  655.             continue
  656.         }
  657.  
  658.         doc, _ := goquery.NewDocumentFromReader(resp.Body)
  659.  
  660.         var obj *Object = nil
  661.  
  662.         doc.Find("table.files .cell_files").Each(func(idx int, sel *goquery.Selection) {
  663.             name, _ := sel.Find("td:nth-child(2) a").Html()
  664.             fileUrl, _ := sel.Find("td:nth-child(2) a").Attr("href")
  665.             id := path.Base(fileUrl)
  666.  
  667.             if name != "&nbsp;" && name != "" && name != " " {
  668.                 fullfile, err := f.GetFile(id, "")
  669.                 fullfile.numId, _ = sel.Find("td:nth-child(1) input").Attr("value")
  670.                 if err == nil && path.Base(fullfile.remote) == filename {
  671.                     obj = fullfile
  672.                 }
  673.             }
  674.         })
  675.  
  676.         if obj != nil {
  677.             return obj, nil
  678.         }
  679.  
  680.         //If there is a next page, go for it
  681.         nextLink := doc.Find("div.paging:nth-child(1) a").Last()
  682.         if nextLink.Text() == "Next ยป" {
  683.             return f.FindFile(pathID, filename, page + 1)
  684.         }
  685.  
  686.         return nil, fs.ErrorObjectNotFound
  687.     }
  688.     return nil, errors.New("Failed to resolve uptobox")
  689. }
  690.  
  691. // FindLeaf finds a directory of name leaf in the folder with ID pathID
  692. func (f *Fs) FindLeaf(pathID, leaf string) (pathIDOut string, found bool, err error) {
  693.  
  694.     // Get max tries value
  695.     maxTries := fs.Config.LowLevelRetries
  696.  
  697.     // Try
  698.     for tries := 1; tries <= maxTries; tries++ {
  699.  
  700.         // Send request
  701.         resp, err := f.httpClient.Get("https://uptobox.com/?op=my_files&fld_id=" + pathID)
  702.  
  703.         // Check http code and retry
  704.         if err != nil || resp.StatusCode != 200 {
  705.             time.Sleep(time.Duration(tries*500) * time.Millisecond)
  706.             fs.Debugf(f, "Directory listing failed for id %q, low level retry %d/%d", pathID, tries, maxTries)
  707.             continue
  708.         }
  709.  
  710.         // Parse HTML
  711.         doc, _ := goquery.NewDocumentFromReader(resp.Body)
  712.  
  713.         // Out ID
  714.         outID := ""
  715.  
  716.         // Extract Folders
  717.         doc.Find("table.files td:not([style='max-width:1000px;']):nth-child(1) a").Each(func(idx int, sel *goquery.Selection) {
  718.             reg, _ := regexp.Compile("(.*) \\((.*)$")
  719.             name := reg.ReplaceAllString(sel.Text(), "$1")
  720.             dirlink, _ := sel.Attr("href")
  721.             dirid := strings.Replace(dirlink, "?op=my_files&fld_id=", "", 1)
  722.  
  723.             if name == leaf {
  724.                 outID = dirid
  725.             }
  726.         })
  727.  
  728.         // Close HTML Request
  729.         resp.Body.Close()
  730.  
  731.         // Return directory
  732.         if outID == "" {
  733.             return "", false, nil
  734.         }
  735.  
  736.         // Return id
  737.         return outID, true, nil
  738.     }
  739.  
  740.     // Error
  741.     return "", false, nil
  742. }
  743.  
  744. // CreateDir makes a directory with pathID as parent and name leaf
  745. func (f *Fs) CreateDir(pathID, leaf string) (newID string, err error) {
  746.     resp, err := f.httpClient.PostForm("https://uptobox.com/", url.Values{
  747.         "op":                {"my_files"},
  748.         "create_new_folder": {leaf},
  749.         "fld_id":            {pathID},
  750.         "key":               {""},
  751.         "pub":               {"1"},
  752.         "to_folder":         {"0"},
  753.         "token":             {f.token},
  754.     })
  755.     if err != nil {
  756.         return "", err
  757.     }
  758.     if resp.StatusCode != 302 {
  759.         return "", errors.New("Could not create dir")
  760.     }
  761.     childID, found, err := f.FindLeaf(pathID, leaf)
  762.     if found != true {
  763.         return "", errors.New("Failed to create directory")
  764.     }
  765.     return childID, err
  766. }
  767.  
  768. // Return a string version
  769. func (o *Object) String() string {
  770.     if o == nil {
  771.         return "<nil>"
  772.     }
  773.     return o.remote
  774. }
  775.  
  776. // Remote returns the remote path
  777. func (o *Object) Remote() string {
  778.     return o.remote
  779. }
  780.  
  781. // ModTime returns the modification time of the object
  782. func (o *Object) ModTime() time.Time {
  783.  
  784.     /*
  785.     // Get max tries value
  786.     maxTries := fs.Config.LowLevelRetries
  787.  
  788.     // Time
  789.     filetime := ""
  790.  
  791.     for tries := 1; tries <= maxTries; tries++ {
  792.  
  793.         // Send request
  794.         resp, err := o.fs.httpClient.Head("http://www59.uptobox.com/d/tqy2g7wsh7dnpxkqdkhjgwj3moaakjwgztax7ex2cwfjviss2vubxn6l7g6caxyq42oyrbhm6qo6c2snk4/Bricks%20in%20Motion.mkv")
  795.  
  796.         // Check http code and retry
  797.         if err != nil || resp.StatusCode != 200 {
  798.             time.Sleep(time.Duration(tries * 500) * time.Millisecond)
  799.             fs.Debugf(o.fs, "Get modtime failed for id %q, low level retry %d/%d", o.id, tries, maxTries)
  800.             continue
  801.         }
  802.  
  803.         // Set time
  804.         filetime = resp.Header.Get("last-date-modified")
  805.  
  806.         // Close HTTP request
  807.         resp.Body.Close()
  808.  
  809.         // Return
  810.         break;
  811.     }*/
  812.  
  813.     return time.Now()
  814. }
  815.  
  816. // Size returns the size of an object in bytes
  817. func (o *Object) Size() int64 {
  818.     return o.size
  819. }
  820.  
  821. func (o *Object) Fs() fs.Info {
  822.     return o.fs
  823. }
  824.  
  825. // Hash returns nothing, not supported
  826. func (o *Object) Hash(fs.HashType) (string, error) {
  827.     return "", nil
  828. }
  829.  
  830. // Storable returns a boolean showing whether this object storable
  831. func (o *Object) Storable() bool {
  832.     return true
  833. }
  834.  
  835. // SetModTime return an error, not supported
  836. func (o *Object) SetModTime(time.Time) error {
  837.     return fs.ErrorCantSetModTime
  838. }
  839.  
  840. // Get download URL from UID
  841. func (f *Fs) GetDownloadURL(fileuid string) (string, error) {
  842.  
  843.     // Get max tries value
  844.     maxTries := fs.Config.LowLevelRetries
  845.  
  846.     // Try
  847.     for tries := 1; tries <= maxTries; tries++ {
  848.  
  849.         // Get advanced informations
  850.         fileInfo, err := f.httpClient.Get("https://uptobox.com/" + fileuid)
  851.  
  852.         // Check http code and retry
  853.         if err != nil || (fileInfo.StatusCode != 200 && fileInfo.StatusCode != 302) {
  854.             time.Sleep(time.Duration(tries*500) * time.Millisecond)
  855.             fs.Debugf(f, "Download-link generation failed (%q), low level retry %d/%d", fileuid, tries, maxTries)
  856.             continue
  857.         }
  858.  
  859.         // Get 302 redirect
  860.         if fileInfo.StatusCode == 302 {
  861.             return string(fileInfo.Header.Get("Location")), nil
  862.         }
  863.  
  864.         // Parse values
  865.         fileHTML, _ := goquery.NewDocumentFromReader(fileInfo.Body)
  866.         fileSize, _ := fileHTML.Find("input[name='file_size_real']").Attr("value")
  867.         fullName, _ := fileHTML.Find("input[name='fname']").Attr("value")
  868.         rand, _ := fileHTML.Find("input[name='rand']").Attr("value")
  869.  
  870.         // Close HTTP
  871.         fileInfo.Body.Close()
  872.  
  873.         // If Auto 302 is disabled, execute second request
  874.         fileDownload, err := f.httpClient.PostForm("https://uptobox.com/"+fileuid, url.Values{
  875.             "op":             {"download2"},
  876.             "id":             {fileuid},
  877.             "fname":          {fullName},
  878.             "file_size_real": {fileSize},
  879.             "rand":           {rand},
  880.             "referer":        {"https://uptobox.com/?op=my_files"},
  881.             "method_free":    {""},
  882.             "method_premium": {""},
  883.             "down_direct":    {"1"},
  884.         })
  885.  
  886.         // Check http code and retry
  887.         if err != nil || (fileInfo.StatusCode != 200) {
  888.             time.Sleep(time.Duration(tries*500) * time.Millisecond)
  889.             fs.Debugf(f, "Download-link generation failed (%q), low level retry %d/%d", fileuid, tries, maxTries)
  890.             continue
  891.         }
  892.  
  893.         // Extract link
  894.         fileHTML, _ = goquery.NewDocumentFromReader(fileDownload.Body)
  895.         downloadUrl, _ := fileHTML.Find(".bg_page div div:nth-child(2) a").Attr("href")
  896.  
  897.         // Close HTTP
  898.         fileDownload.Body.Close()
  899.  
  900.         // Return url
  901.         return downloadUrl, nil
  902.     }
  903.  
  904.     // Return error
  905.     return "", errors.New("Download-link generation failed")
  906. }
  907.  
  908. // Open an object for read
  909. func (o *Object) Open(options ...fs.OpenOption) (in io.ReadCloser, err error) {
  910.     fileUrl, err := o.fs.GetDownloadURL(o.id)
  911.     if err != nil {
  912.         return nil, err
  913.     }
  914.     resp, err := o.fs.httpClient.Get(fileUrl)
  915.     if err != nil {
  916.         return nil, err
  917.     }
  918.     return resp.Body, err
  919. }
  920.  
  921. func (o *Object) Update(in io.Reader, src fs.ObjectInfo) error {
  922.     //upload new file
  923.     newFsObj, err := o.fs.Put(in, src)
  924.     if err != nil {
  925.         return errors.Wrap(err, "Failed to update object")
  926.     }
  927.     o.Remove()
  928.  
  929.     //Set values to this
  930.     newObj, _ := newFsObj.(*Object)
  931.     o.numId = newObj.id
  932.     o.id = newObj.id
  933.     o.size = newObj.size
  934.     o.remote = newObj.remote
  935.     o.date = newObj.date
  936.     return nil
  937. }
  938.  
  939. func (o *Object) Remove() error {
  940.  
  941.     // Get max tries value
  942.     maxTries := fs.Config.LowLevelRetries
  943.  
  944.     // Try
  945.     for tries := 1; tries <= maxTries; tries++ {
  946.  
  947.         // Send request
  948.         resp, _ := o.fs.httpClient.Get("https://uptobox.com/?op=my_files&del_code=" + o.id + "&token=" + o.fs.token)
  949.  
  950.         // Check success
  951.         if resp.StatusCode == 302 || resp.StatusCode == 200 {
  952.             return nil
  953.         }
  954.     }
  955.     return errors.New("File deletion failed")
  956. }
  957.  
  958. func (f *Fs) MoveToDir(srcFolderId string, dstFolderId string, fileId string) (error) {
  959.     //Don't do if in same folder
  960.     if srcFolderId == dstFolderId {
  961.         return nil
  962.     }
  963.  
  964.     // Get max tries value
  965.     maxTries := fs.Config.LowLevelRetries
  966.  
  967.     for tries := 1; tries <= maxTries; tries++ {
  968.         // Send request
  969.         resp, err := f.httpClient.PostForm("https://uptobox.com/", url.Values{
  970.             "create_new_folder": {""},
  971.             "op":                {"my_files"},
  972.             "token":             {f.token},
  973.             "fld_id":            {srcFolderId},
  974.             "key":               {""},
  975.             "file_id":           {fileId},
  976.             "pub":               {"1"},
  977.             "to_folder":         {dstFolderId},
  978.             "to_folder_move":    {"Move files"},
  979.         })
  980.  
  981.         if err != nil || (resp.StatusCode != 302) {
  982.             time.Sleep(time.Duration(tries*500) * time.Millisecond)
  983.             fs.Debugf(f, "Moving file failed (%q), low level retry %d/%d", fileId, tries, maxTries)
  984.             continue
  985.         }
  986.         return nil
  987.     }
  988.     return errors.New("Failed to move file")
  989. }
  990.  
  991. func (f *Fs) Move(src fs.Object, remote string) (fs.Object, error) {
  992.     srcObj, ok := src.(*Object)
  993.     if !ok {
  994.         fs.Debugf(src, "Can't move - not same remote type")
  995.         return nil, fs.ErrorCantMove
  996.     }
  997.  
  998.     err := f.dirCache.FindRoot(true)
  999.     if err != nil {
  1000.         return nil, err
  1001.     }
  1002.     // Get max tries value
  1003.     maxTries := fs.Config.LowLevelRetries
  1004.  
  1005.     dstDir, err := f.dirCache.FindDir(getDir(remote), true)
  1006.     if err != nil {
  1007.         return nil, errors.Wrap(err, "Failed to find move destination dir")
  1008.     }
  1009.  
  1010.     srcDir, err := f.dirCache.FindDir(getDir(srcObj.remote), true)
  1011.     if err != nil {
  1012.         return nil, errors.Wrap(err, "Failed to find move destination dir")
  1013.     }
  1014.  
  1015.     //Get the numId of the file
  1016.     srcObj.numId, err = f.getNumId(srcObj, srcDir, 1)
  1017.     if err != nil {
  1018.         return nil, err
  1019.     }
  1020.     err = f.MoveToDir(srcDir, dstDir, srcObj.numId)
  1021.     if err != nil {
  1022.         return nil, err
  1023.     }
  1024.  
  1025.     //Rename file
  1026.     //TODO Create func
  1027.     if path.Base(srcObj.remote) != path.Base(remote) {
  1028.         for tries := 1; tries <= maxTries; tries++ {
  1029.             // Send request
  1030.             resp, err := f.httpClient.PostForm("https://uptobox.com/", url.Values{
  1031.                 "op":            {"file_edit"},
  1032.                 "file_code":     {srcObj.id},
  1033.                 "file_name":     {path.Base(remote)},
  1034.                 "file_descr":    {""},
  1035.                 "file_password": {""},
  1036.                 "file_public":   {"1"},
  1037.                 "save":          {"Submit"},
  1038.             })
  1039.  
  1040.             // Check http code and retry
  1041.             if err != nil || (resp.StatusCode != 302 && resp.StatusCode != 200) {
  1042.                 time.Sleep(time.Duration(tries*500) * time.Millisecond)
  1043.                 fs.Debugf(f, "Moving file failed (%q), low level retry %d/%d", srcObj.id, tries, maxTries)
  1044.                 if tries+1 >= maxTries {
  1045.                     return nil, errors.New("Renaming file failed")
  1046.                 }
  1047.                 continue
  1048.             }
  1049.             break
  1050.         }
  1051.     }
  1052.  
  1053.     // Get new file
  1054.     newFileObj, errObj := f.GetFile(srcObj.id, "")
  1055.  
  1056.     // Check success
  1057.     if errObj == nil {
  1058.         return newFileObj, nil
  1059.     }
  1060.  
  1061.     // Error break
  1062.     return nil, errors.New("Moving file failed")
  1063. }
  1064.  
  1065. var (
  1066.     _ fs.Fs     = &Fs{}
  1067.     _ fs.Mover  = &Fs{}
  1068.     _ fs.Object = &Object{}
  1069. )
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement