Skip to content

Instantly share code, notes, and snippets.

@benwaffle
Last active September 29, 2019 01:57
Show Gist options
  • Save benwaffle/e56087c84b767a9ead0b8b00eefd2241 to your computer and use it in GitHub Desktop.
Save benwaffle/e56087c84b767a9ead0b8b00eefd2241 to your computer and use it in GitHub Desktop.
Import watchlist from IMDb to Trakt.tv
package main
import (
"bytes"
"encoding/csv"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net/http"
"os"
"strings"
"time"
)
type DeviceCodeResp struct {
DeviceCode string `json:"device_code"`
UserCode string `json:"user_code"`
VerificationURL string `json:"verification_url"`
ExpiresIn int `json:"expires_in"`
Interval int `json:"interval"`
}
type OauthTokenReq struct {
Code string `json:"code"`
ClientID string `json:"client_id"`
ClientSecret string `json:"client_secret"`
}
type OauthTokenResp struct {
AccessToken string `json:"access_token"`
TokenType string `json:"token_type"`
ExpiresIn int `json:"expires_in"`
RefreshToken string `json:"refresh_token"`
Scope string `json:"scope"`
CreatedAt int `json:"created_at"`
}
const (
ClientID = ""
ClientSecret = ""
)
func getDeviceCode(client *http.Client) DeviceCodeResp {
body := []byte("{\n \"client_id\": \"\"\n}")
req, _ := http.NewRequest("POST", "https://api.trakt.tv/oauth/device/code", bytes.NewBuffer(body))
req.Header.Add("Content-Type", "application/json")
resp, err := client.Do(req)
if err != nil {
panic("Errored when sending request to the server")
}
defer resp.Body.Close()
resp_body, _ := ioutil.ReadAll(resp.Body)
var obj DeviceCodeResp
err = json.Unmarshal(resp_body, &obj)
if err != nil {
fmt.Println(resp.Status)
fmt.Println(string(resp_body))
panic(err)
}
fmt.Println(obj)
return obj
}
func pollAccessToken(deviceCode DeviceCodeResp, client *http.Client) string {
for {
tokenReq := OauthTokenReq{
Code: deviceCode.DeviceCode,
ClientID: ClientID,
ClientSecret: ClientSecret,
}
body, err := json.Marshal(tokenReq)
req, _ := http.NewRequest("POST", "https://api.trakt.tv/oauth/device/token", bytes.NewBuffer(body))
req.Header.Add("Content-Type", "application/json")
resp, err := client.Do(req)
if err != nil {
panic("Errored when sending request to the server")
}
defer resp.Body.Close()
resp_body, _ := ioutil.ReadAll(resp.Body)
if resp.StatusCode == 200 {
var obj OauthTokenResp
err = json.Unmarshal(resp_body, &obj)
if err != nil {
fmt.Println(resp.Status)
fmt.Println(string(resp_body))
panic(err)
}
fmt.Println(obj)
return obj.AccessToken
} else if resp.StatusCode == 400 {
// no-op
} else if resp.StatusCode == 410 {
panic("expired")
} else {
fmt.Printf("unknown status code when polling for token: %d\n", resp.StatusCode)
}
time.Sleep(time.Duration(deviceCode.Interval) * time.Second)
}
}
func main() {
file, _ := os.Open(os.Args[1])
reader := csv.NewReader(file)
movies := make([]string, 0)
tvShows := make([]string, 0)
for {
record, err := reader.Read()
if err == io.EOF {
break
}
id := record[1]
name := record[5]
typ := record[7]
// fmt.Println(id, name, typ)
if typ == "tvSeries" || typ == "tvMiniSeries" || typ == "tvShort" {
tvShows = append(tvShows, fmt.Sprintf("{\"ids\": {\"imdb\": \"%s\"}}", id))
} else if typ == "movie" || typ == "tvMovie" || typ == "video" || typ == "short" {
movies = append(movies, fmt.Sprintf("{\"ids\": {\"imdb\": \"%s\"}}", id))
} else {
fmt.Printf("%s: unknown type %s\n", name, typ)
}
}
client := &http.Client{}
code := getDeviceCode(client)
fmt.Printf("Go to %s and enter %s . Polling...\n", code.VerificationURL, code.UserCode)
accessToken := pollAccessToken(code, client)
fmt.Println(accessToken)
body := fmt.Sprintf("{\"movies\": [%s], \"shows\": [%s]}", strings.Join(movies, ","), strings.Join(tvShows, ","))
req, _ := http.NewRequest("POST", "https://api.trakt.tv/sync/watchlist", bytes.NewBufferString(body))
req.Header.Add("Content-Type", "application/json")
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", accessToken))
req.Header.Add("trakt-api-version", "2")
req.Header.Add("trakt-api-key", ClientID)
resp, err := client.Do(req)
if err != nil {
fmt.Println("Errored when sending request to the server")
return
}
defer resp.Body.Close()
resp_body, _ := ioutil.ReadAll(resp.Body)
fmt.Println(resp.Status)
fmt.Println(string(resp_body))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment