aboutsummaryrefslogtreecommitdiffstats
path: root/ff2mpv.go
blob: 7f0c939061253f3717303e83557d8f4456b45906 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
package main

import (
	"encoding/binary"
	"encoding/json"
	"fmt"
	"io"
	"os"
	"os/exec"
)

var mpvCmd = []string{"mpv", "--player-operation-mode=pseudo-gui", "--"}

type ffRequest struct {
	URL string `json:"url"`
}

type ffManifest struct {
	Name              string   `json:"name"`
	Description       string   `json:"description"`
	Path              string   `json:"path"`
	Type              string   `json:"type"`
	AllowedExtensions []string `json:"allowed_extensions"`
}

func ff2mpv() {
	// extract message length from the first 4 bytes
	var l uint32
	// Go does not have an easy way to do sutff with native endianness without
	// using usafe. Blame stupid WebExtension spec that uses *native* endianness in
	// a *protocol*. Seriously, who designed that‽
	if err := binary.Read(os.Stdin, endianness, &l); err != nil {
		panic(err)
	}
	if l > 1024*1024 {
		panic(fmt.Sprintf("native messaging message length too large: %d", l))
	}

	// read raw message
	buf := make([]byte, l)
	if n, err := os.Stdin.Read(buf); err != nil {
		panic(err)
	} else if n != len(buf) {
		panic(fmt.Sprintf("read message length %d does not match expected length %d", n, l))
	}

	// decode JSON
	var data ffRequest
	if err := json.Unmarshal(buf, &data); err != nil {
		panic(err)
	}

	// run mpv
	args := append(mpvCmd, data.URL)
	cmd := exec.Command(args[0], args[1:]...)
	if err := cmd.Start(); err != nil {
		panic(err)
	}

	// respond
	outmsg := []byte("{}")
	outlen := uint32(len(outmsg))
	binary.Write(os.Stdout, endianness, outlen)
	os.Stdout.Write(outmsg)
}

func manifest() {
	exe, err := os.Executable()
	if err != nil {
		panic(err)
	}
	data, err := json.MarshalIndent(ffManifest{
		Name:              "ff2mpv",
		Description:       "ff2mpv's extenal manifest (ff2mpv-go)",
		Path:              exe,
		Type:              "stdio",
		AllowedExtensions: []string{"ff2mpv@yossarian.net"},
	}, "", "\t")
	if err != nil {
		panic(err)
	}
	os.Stdout.Write(data)
}

func usage(w io.Writer) {
	fmt.Fprintf(os.Stderr, "args: %#v\n", os.Args)
	fmt.Fprintf(w, "usage: %s [--manifest]\n", os.Args[0])
}

func main() {
	arg := ""
	if len(os.Args) == 2 {
		arg = os.Args[1]
	}
	switch arg {
	case "--manifest":
		manifest()
	case "--help":
		usage(os.Stdout)
	default:
		ff2mpv()
	}
}