jeffreydwalter / arlo-go

WIP - (BETA) - Go package for interacting with Netgear's Arlo camera system.
MIT License
43 stars 8 forks source link

Downloading recordings from library results in 404 errors #3

Closed jryd closed 5 years ago

jryd commented 5 years ago

I'm using a slightly modified version of the example script in the readme:

package main

import (
    "fmt"
    "log"
    "os"
    "time"

    "github.com/jeffreydwalter/arlo-go"
)

const (
    USERNAME = "me@my-email.com"
    PASSWORD = "secret"
)

func main() {

    // Instantiating the Arlo object automatically calls Login(), which returns an oAuth token that gets cached.
    // Subsequent successful calls to login will update the oAuth token.
    arlo, err := arlo.Login(USERNAME, PASSWORD)
    if err != nil {
        log.Fatal("Failed to login: %s\n", err)
        return
    }
    // At this point you're logged into Arlo.

    now := time.Now()
    start := now.Add(-1 * 24 * time.Hour) // Minus 1 day

    // Get all of the recordings for a date range.
    library, err := arlo.GetLibrary(start, now)
    if err != nil {
        log.Fatal(err)
        return
    }

    for _, recording := range *library {

        fileToWrite, err := os.Create(fmt.Sprintf("./recordings/%s_%s.mp4", time.Unix(0, recording.UtcCreatedDate*int64(time.Millisecond)).Format(("2006-01-02_15.04.05")), recording.UniqueId))

        if err != nil {
            log.Fatal(err)
        }

        if err := arlo.DownloadFile(recording.PresignedContentUrl, fileToWrite); err != nil {
            log.Println(err)
        } else {
            log.Printf("Downloaded video %s from %s", recording.CreatedDate)
        }

        log.Println("Downloaded", recording.UniqueId)

    }
}

However, when I run it, it creates the recording file, but then I get a 404 error:

2018/12/21 18:52:08 failed to download file (https://arlos3-prod-z3.s3.ap-southeast-2.amazonaws.com/d9c79688abb443b092c13918d6217da2/DJ3T3VJ-100-47906081/52M1837HCAD6E/recordings/1545368045228.mp4?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20181221T085039Z&X-Amz-SignedHeaders=host&X-Amz-Expires=86400&X-Amz-Credential=AKIAICS2UAC4WFSD6C2A%2F20181221%2Fap-southeast-2%2Fs3%2Faws4_request&X-Amz-Signature=a83ab526f0a3ae50e40836d1353fd1124432920f415447961bf4e00b946fxxxx): http request failed with status: 404 Not Found

NOTE: I have edited the signature to make the recording URL invalid (privacy reasons) - however opening the link in my browser downloads the file.

Am I missing something here? All the videos result in a 404.

dougnd commented 5 years ago

I noticed this problem too when I tried the library. I did not look long, but suspected that it was because a.get set's a bunch of headers (that aren't needed -- we are now fetching directly from an S3 bucket not Arlo) including (I believe) a wrong content type header.

jryd commented 5 years ago

@dougnd spot on. I used a generic http.Get() with the presigned content URL and it works perfectly. I've submitted a pull request to fix this, however if you want to get this going in the meantime, here's my fix in action with the library in its current state (just replace arlo.DownloadFile with this:

// Create the file
out, err := os.Create(fmt.Sprintf("%s_%s.mp4", time.Unix(0, recording.UtcCreatedDate*int64(time.Millisecond)).Format(("2006-01-02_15.04.05")), recording.UniqueId))
if err != nil {
    log.Fatal(err)
}
defer out.Close()

// Get the data
resp, err := http.Get(recording.PresignedContentUrl)
if err != nil {
    log.Fatal(err)
}
defer resp.Body.Close()

// Write the body to file
_, err = io.Copy(out, resp.Body)
if err != nil {
    log.Fatal(err)
}