package main

import (
	"errors"
	"log"
	"os"

	"github.com/PuerkitoBio/goquery"
	"github.com/robertkrimen/otto"
)

func getMP4URL(id string) string {
	doc, err := goquery.NewDocument("https://vine.co/v/" + id)
	check(err)

	// we want the first <script> tag from the html
	firstScript := doc.Find("script").First()

	vm := otto.New()

	// otherwise window.POST_DATA will raise an reference error `ReferenceError: 'window' is not defined`
	_, err = vm.Run("var window = {};")
	check(err)

	// eval the javascript inside the <script> tag
	_, err = vm.Run(firstScript.Text())
	check(err)

	// traverse down the object path: window > POST_DATA > <videoID> > videoDashURL
	wVal, err := vm.Get("window")
	check(err)

	pdata, err := getValueFromObject(wVal, "POST_DATA")
	check(err)

	videoData, err := getValueFromObject(*pdata, id)
	check(err)

	videoDashUrl, err := getValueFromObject(*videoData, "videoDashUrl")
	check(err)

	// finally the video url...
	videoUrl, err := videoDashUrl.ToString()
	check(err)

	return videoUrl
}

func main() {
	if len(os.Args) != 2 {
		log.Fatalln("Usage: vineUrl <videoID>")
	}

	log.Println("Video URL:", getMP4URL(os.Args[1]))
}

// fatal if there is an error
func check(err error) {
	if err != nil {
		log.Fatal(err)
	}
}

func getValueFromObject(val otto.Value, key string) (*otto.Value, error) {
	if !val.IsObject() {
		return nil, errors.New("passed val is not an Object")
	}

	valObj := val.Object()

	obj, err := valObj.Get(key)
	if err != nil {
		return nil, err
	}

	return &obj, nil
}