├── .github
├── dependabot.yml
└── workflows
│ └── go.yml
├── .gitignore
├── .vscode
└── settings.json
├── LICENSE
├── README.md
├── api
├── api.go
├── bilibili.go
└── server.go
├── browser.go
├── cors
└── cors.go
├── go.mod
├── go.sum
├── main.go
├── utils
└── utils.go
└── wails.json
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | # To get started with Dependabot version updates, you'll need to specify which
2 | # package ecosystems to update and where the package manifests are located.
3 | # Please see the documentation for all configuration options:
4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
5 |
6 | version: 2
7 | updates:
8 | - package-ecosystem: "gomod" # See documentation for possible values
9 | directory: "/" # Location of package manifests
10 | schedule:
11 | interval: "daily"
12 |
--------------------------------------------------------------------------------
/.github/workflows/go.yml:
--------------------------------------------------------------------------------
1 | name: Go
2 |
3 | on:
4 | push:
5 | branches: [ "master" ]
6 | pull_request:
7 | branches: [ "master" ]
8 | workflow_dispatch:
9 |
10 | jobs:
11 |
12 | build:
13 | name: Build
14 | runs-on: ubuntu-latest
15 | steps:
16 | - uses: actions/checkout@v3
17 |
18 | - name: Set up Go
19 | uses: actions/setup-go@v3
20 | with:
21 | go-version: 1.18
22 |
23 | - name: Build dependencies
24 | run: |
25 | git clone https://github.com/xmdhs/player
26 | cd player
27 | git reset --hard 8688cf11d87fbbe67167d0d12b4ada5c88e98c5b
28 | npm install -g pnpm
29 | pnpm install
30 | pnpm run build
31 | mkdir ../frontend
32 | cp -r dist/ ../frontend/
33 |
34 | #- name: Get Wails dependencies
35 | # run: sudo apt update && sudo apt install -y libgtk-3-dev libwebkit2gtk-4.0-dev
36 |
37 | - name: Build
38 | run: |
39 | go install github.com/wailsapp/wails/v2/cmd/wails@latest
40 | go build -trimpath -ldflags="-w -s" -o build/bin/player-linux-browser -tags=browser
41 | CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -trimpath -ldflags="-w -s" -o build/bin/player-windows-browser.exe -tags=browser
42 | wails build -trimpath -ldflags="-w -s" -o player-windows.exe -platform windows/amd64 -upx
43 |
44 | - name: Test
45 | run: go test -tags browser -race -v ./...
46 |
47 | - name: Upload a Build Artifact
48 | uses: actions/upload-artifact@v2
49 | with:
50 | # A file, directory or wildcard pattern that describes what to upload
51 | path: build/bin/player-*
52 | name: ${{ github.run_number }}
53 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | build
2 | frontend
3 | player.db
4 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "gopls": {
3 | "buildFlags": [
4 | "-tags="
5 | ]
6 | },
7 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 xmdhs
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # player-go
2 | 一个简单的播放器,对于 dplayer 的包装。
3 |
4 | 可以加载本地视频、视频直链以及 b 站视频,并且能加载 b 站、巴哈、弹弹play 的弹幕。
5 |
6 | 以及弹幕正则和按用户屏蔽功能。
7 |
8 | ## 下载
9 | https://github.com/xmdhs/player-go/releases
10 |
--------------------------------------------------------------------------------
/api/api.go:
--------------------------------------------------------------------------------
1 | package api
2 |
3 | import (
4 | "io"
5 | "net/http"
6 |
7 | "github.com/julienschmidt/httprouter"
8 | "go.etcd.io/bbolt"
9 | )
10 |
11 | func store(db *bbolt.DB) httprouter.Handle {
12 | return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
13 | w.Header().Set("Access-Control-Allow-Origin", "*")
14 | key := p.ByName("key")
15 | b, err := io.ReadAll(r.Body)
16 | if err != nil {
17 | http.Error(w, err.Error(), http.StatusInternalServerError)
18 | return
19 | }
20 | err = db.Update(func(tx *bbolt.Tx) error {
21 | bkt, err := tx.CreateBucketIfNotExists([]byte("data"))
22 | if err != nil {
23 | return err
24 | }
25 | return bkt.Put([]byte(key), b)
26 | })
27 | if err != nil {
28 | http.Error(w, err.Error(), http.StatusInternalServerError)
29 | return
30 | }
31 | }
32 | }
33 |
34 | func read(db *bbolt.DB) httprouter.Handle {
35 | return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
36 | w.Header().Set("Access-Control-Allow-Origin", "*")
37 | key := p.ByName("key")
38 | err := db.View(func(tx *bbolt.Tx) error {
39 | bkt := tx.Bucket([]byte("data"))
40 | if bkt == nil {
41 | http.NotFound(w, r)
42 | return nil
43 | }
44 | v := bkt.Get([]byte(key))
45 | if v == nil {
46 | http.NotFound(w, r)
47 | return nil
48 | }
49 | w.Write(v)
50 | return nil
51 | })
52 | if err != nil {
53 | http.Error(w, err.Error(), http.StatusInternalServerError)
54 | return
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/api/bilibili.go:
--------------------------------------------------------------------------------
1 | package api
2 |
3 | import (
4 | "encoding/json"
5 | "io"
6 | "net/http"
7 | "net/url"
8 | "time"
9 |
10 | "github.com/julienschmidt/httprouter"
11 | )
12 |
13 | func bilivideoGet(t *http.Transport) httprouter.Handle {
14 | c := http.Client{
15 | Transport: t,
16 | Timeout: 10 * time.Second,
17 | }
18 | return func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
19 | w.Header().Set("Access-Control-Allow-Origin", "*")
20 | qn := r.FormValue("qn")
21 | if qn == "" {
22 | qn = "120"
23 | }
24 | bvid := r.FormValue("bvid")
25 | cid := r.FormValue("cid")
26 |
27 | if bvid == "" || cid == "" {
28 | http.Error(w, "bvid or cid is required", http.StatusBadRequest)
29 | return
30 | }
31 | fnval := "0"
32 | if qn == "120" {
33 | fnval = "128"
34 | }
35 | DedeUserID := r.FormValue("DedeUserID")
36 | DedeUserID__ckMd5 := r.FormValue("DedeUserID__ckMd5")
37 | SESSDATA := r.FormValue("SESSDATA")
38 | bili_jct := r.FormValue("bili_jct")
39 |
40 | uq := url.Values{}
41 | uq.Set("bvid", bvid)
42 | uq.Set("cid", cid)
43 | uq.Set("fnval", fnval)
44 | uq.Set("qn", qn)
45 | reqs, err := http.NewRequest("GET", "https://api.bilibili.com/x/player/playurl?"+uq.Encode(), nil)
46 | if err != nil {
47 | http.Error(w, err.Error(), http.StatusInternalServerError)
48 | return
49 | }
50 | reqs.Header.Set("cookie", "DedeUserID="+DedeUserID+"; DedeUserID__ckMd5="+DedeUserID__ckMd5+"; SESSDATA="+SESSDATA+"; bili_jct="+bili_jct)
51 | resp, err := c.Do(reqs)
52 | if resp != nil {
53 | defer resp.Body.Close()
54 | }
55 | if err != nil {
56 | http.Error(w, err.Error(), http.StatusInternalServerError)
57 | return
58 | }
59 | b, err := io.ReadAll(resp.Body)
60 | if err != nil {
61 | http.Error(w, err.Error(), http.StatusInternalServerError)
62 | return
63 | }
64 | bvideo := bili[biliVideoInfo]{}
65 | err = json.Unmarshal(b, &bvideo)
66 | if err != nil {
67 | http.Error(w, err.Error(), http.StatusInternalServerError)
68 | return
69 | }
70 | if bvideo.Code != 0 {
71 | http.Error(w, bvideo.Message, http.StatusInternalServerError)
72 | return
73 | }
74 | if len(bvideo.Data.Durl) != 1 {
75 | http.Error(w, "无法处理分段视频", http.StatusInternalServerError)
76 | return
77 | }
78 | w.Write([]byte(bvideo.Data.Durl[0].URL))
79 | }
80 | }
81 |
82 | type bili[T any] struct {
83 | Code int `json:"code"`
84 | Data T `json:"data"`
85 | Message string `json:"message"`
86 | TTL int `json:"ttl"`
87 | }
88 |
89 | type biliVideoInfo struct {
90 | AcceptDescription []string `json:"accept_description"`
91 | AcceptFormat string `json:"accept_format"`
92 | AcceptQuality []int `json:"accept_quality"`
93 | Durl []biliVideoDurl `json:"durl"`
94 | Format string `json:"format"`
95 | From string `json:"from"`
96 | Message string `json:"message"`
97 | Quality int `json:"quality"`
98 | Result string `json:"result"`
99 | SeekParam string `json:"seek_param"`
100 | SeekType string `json:"seek_type"`
101 | Timelength int `json:"timelength"`
102 | VideoCodecid int `json:"video_codecid"`
103 | }
104 |
105 | type biliVideoDurl struct {
106 | Ahead string `json:"ahead"`
107 | BackupURL []string `json:"backup_url"`
108 | Length int `json:"length"`
109 | Order int `json:"order"`
110 | Size int `json:"size"`
111 | URL string `json:"url"`
112 | Vhead string `json:"vhead"`
113 | }
114 |
--------------------------------------------------------------------------------
/api/server.go:
--------------------------------------------------------------------------------
1 | package api
2 |
3 | import (
4 | "context"
5 | "net/http"
6 | "strconv"
7 | "time"
8 |
9 | "github.com/julienschmidt/httprouter"
10 | "github.com/xmdhs/player-go/utils"
11 | "go.etcd.io/bbolt"
12 | )
13 |
14 | func Server(cxt context.Context, db *bbolt.DB, t *http.Transport) int {
15 | p := utils.GetProt()
16 |
17 | mux := httprouter.New()
18 |
19 | mux.GlobalOPTIONS = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
20 | if r.Header.Get("Access-Control-Request-Method") != "" {
21 | header := w.Header()
22 | header.Set("Access-Control-Allow-Origin", "*")
23 | header.Set("Access-Control-Allow-Methods", r.Header.Get("Access-Control-Request-Method"))
24 | header.Set("Access-Control-Allow-Headers", r.Header.Get("Access-Control-Request-Headers"))
25 | }
26 | w.WriteHeader(http.StatusNoContent)
27 | })
28 |
29 | mux.POST("/store/:key", store(db))
30 | mux.GET("/store/:key", read(db))
31 | mux.GET("/bilibili.flv", bilivideoGet(t))
32 |
33 | s := http.Server{
34 | Addr: "127.0.0.1:" + strconv.FormatInt(p, 10),
35 | Handler: mux,
36 | ReadTimeout: 10 * time.Second,
37 | WriteTimeout: 60 * time.Second,
38 | ReadHeaderTimeout: 5 * time.Second,
39 | }
40 |
41 | go s.ListenAndServe()
42 | go func() {
43 | <-cxt.Done()
44 | s.Shutdown(cxt)
45 | }()
46 | return int(p)
47 | }
48 |
--------------------------------------------------------------------------------
/browser.go:
--------------------------------------------------------------------------------
1 | //go:build browser
2 |
3 | package main
4 |
5 | import (
6 | "bytes"
7 | "context"
8 | "embed"
9 | "flag"
10 | "fmt"
11 | "log"
12 | "net/http"
13 | "strconv"
14 | "time"
15 |
16 | "github.com/pkg/browser"
17 | "github.com/xmdhs/player-go/api"
18 | "github.com/xmdhs/player-go/cors"
19 | "go.etcd.io/bbolt"
20 |
21 | "github.com/mattn/go-ieproxy"
22 | )
23 |
24 | //go:embed frontend/dist
25 | var assets embed.FS
26 |
27 | func main() {
28 | cxt := context.Background()
29 |
30 | t := http.DefaultTransport.(*http.Transport).Clone()
31 | t.Proxy = ieproxy.GetProxyFunc()
32 |
33 | db, err := bbolt.Open("player.db", 0600, nil)
34 | if err != nil {
35 | panic(err)
36 | }
37 |
38 | cport := cors.Server(cxt, t)
39 | apiPort := api.Server(cxt, db, t)
40 |
41 | ieproxy.OverrideEnvWithStaticProxy()
42 |
43 | mux := http.NewServeMux()
44 |
45 | mux.HandleFunc("/", indexH(cport, apiPort))
46 | mux.Handle("/assets/", AddPrefix("frontend/dist", http.FileServer(http.FS(assets))))
47 |
48 | server := &http.Server{
49 | Addr: "127.0.0.1:" + port,
50 | ReadTimeout: 10 * time.Second,
51 | WriteTimeout: 20 * time.Second,
52 | ReadHeaderTimeout: 5 * time.Second,
53 | Handler: mux,
54 | }
55 | fmt.Printf("http://127.0.0.1:%v", port)
56 | browser.OpenURL("http://127.0.0.1:" + port)
57 | log.Println(server.ListenAndServe())
58 | }
59 |
60 | var (
61 | port string
62 | )
63 |
64 | func init() {
65 | flag.StringVar(&port, "port", "8080", "port")
66 | flag.Parse()
67 | }
68 |
69 | func indexH(port, apiPort int) http.HandlerFunc {
70 | b, err := assets.ReadFile("frontend/dist/index.html")
71 | if err != nil {
72 | panic(err)
73 | }
74 | b = bytes.Replace(b, []byte(``), []byte("\n"+
75 | ""), -1)
76 | return func(w http.ResponseWriter, r *http.Request) {
77 | w.Header().Set("Content-Type", "text/html")
78 | w.Write(b)
79 | }
80 | }
81 |
82 | func AddPrefix(prefix string, h http.Handler) http.Handler {
83 | if prefix == "" {
84 | return h
85 | }
86 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
87 | if r.URL.Path == "/" {
88 | r.URL.Path = prefix
89 | } else {
90 | r.URL.Path = prefix + r.URL.Path
91 | }
92 | h.ServeHTTP(w, r)
93 | })
94 | }
95 |
--------------------------------------------------------------------------------
/cors/cors.go:
--------------------------------------------------------------------------------
1 | package cors
2 |
3 | import (
4 | "context"
5 | "log"
6 | "net/http"
7 | "net/http/httputil"
8 | "net/url"
9 | "strconv"
10 | "strings"
11 | "time"
12 |
13 | "github.com/xmdhs/player-go/utils"
14 | )
15 |
16 | func Server(cxt context.Context, t *http.Transport) int {
17 | p := utils.GetProt()
18 | s := http.Server{
19 | Addr: "127.0.0.1:" + strconv.FormatInt(p, 10),
20 | Handler: handler(t),
21 | ReadTimeout: 10 * time.Second,
22 | WriteTimeout: 60 * time.Second,
23 | ReadHeaderTimeout: 5 * time.Second,
24 | }
25 |
26 | go s.ListenAndServe()
27 | go func() {
28 | <-cxt.Done()
29 | s.Shutdown(cxt)
30 | }()
31 | return int(p)
32 | }
33 |
34 | func handler(t *http.Transport) http.HandlerFunc {
35 | return func(w http.ResponseWriter, r *http.Request) {
36 | q := r.URL.Query()
37 | proxyURL := q.Get("_proxyURL")
38 | if proxyURL != "" {
39 | purl, err := url.Parse(proxyURL)
40 | if err != nil {
41 | w.WriteHeader(http.StatusBadRequest)
42 | w.Write([]byte(err.Error()))
43 | return
44 | }
45 | corsProxy(purl, t, q.Get("_referer")).ServeHTTP(w, r)
46 | return
47 | }
48 | u := r.URL.String()
49 | u = strings.TrimPrefix(u, "/")
50 | purl, err := url.Parse(u)
51 | if err != nil {
52 | w.WriteHeader(http.StatusBadRequest)
53 | w.Write([]byte(err.Error()))
54 | return
55 | }
56 | if purl.Scheme == "" {
57 | purl.Scheme = "http"
58 | }
59 | if purl.Host == "" {
60 | w.WriteHeader(http.StatusBadRequest)
61 | return
62 | }
63 | corsProxy(purl, t, "").ServeHTTP(w, r)
64 | }
65 | }
66 |
67 | func corsProxy(u *url.URL, t *http.Transport, referer string) http.HandlerFunc {
68 | return func(w http.ResponseWriter, r *http.Request) {
69 | proxy := httputil.NewSingleHostReverseProxy(&url.URL{
70 | Host: u.Host,
71 | Scheme: u.Scheme,
72 | })
73 | proxy.ErrorLog = log.Default()
74 | proxy.Transport = t
75 |
76 | df := proxy.Director
77 |
78 | proxy.Director = func(r *http.Request) {
79 | df(r)
80 | r.Header.Del("referer")
81 | r.Header.Del("origin")
82 | r.Header.Del("X-Forwarded-For")
83 | r.Header.Del("X-Real-IP")
84 | r.Host = u.Host
85 | if referer != "" {
86 | r.Header.Set("referer", referer)
87 | }
88 | }
89 |
90 | proxy.ModifyResponse = func(r *http.Response) error {
91 | r.Header.Set("Access-Control-Allow-Origin", "*")
92 | r.Header.Set("Access-Control-Allow-Methods", r.Header.Get("Access-Control-Request-Method"))
93 | r.Header.Set("Access-Control-Allow-Headers", r.Header.Get("Access-Control-Request-Headers"))
94 | r.Header.Set("X-ToProxy", r.Request.URL.String())
95 | if r.StatusCode >= 300 && r.StatusCode < 400 && r.Header.Get("Location") != "" {
96 | r.Header.Set("Location", "/"+r.Header.Get("Location"))
97 | }
98 | return nil
99 | }
100 |
101 | r.URL = u
102 | r.RemoteAddr = ""
103 | r.RequestURI = u.String()
104 |
105 | proxy.ServeHTTP(w, r)
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/xmdhs/player-go
2 |
3 | go 1.18
4 |
5 | require (
6 | github.com/julienschmidt/httprouter v1.3.0
7 | github.com/mattn/go-ieproxy v0.0.7
8 | github.com/pkg/browser v0.0.0-20210706143420-7d21f8c997e2
9 | github.com/wailsapp/wails/v2 v2.3.1
10 | go.etcd.io/bbolt v1.3.6
11 | )
12 |
13 | require (
14 | github.com/bep/debounce v1.2.1 // indirect
15 | github.com/go-ole/go-ole v1.2.6 // indirect
16 | github.com/google/uuid v1.1.2 // indirect
17 | github.com/imdario/mergo v0.3.12 // indirect
18 | github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect
19 | github.com/labstack/echo/v4 v4.9.0 // indirect
20 | github.com/labstack/gommon v0.3.1 // indirect
21 | github.com/leaanthony/go-ansi-parser v1.0.1 // indirect
22 | github.com/leaanthony/gosod v1.0.3 // indirect
23 | github.com/leaanthony/slicer v1.5.0 // indirect
24 | github.com/mattn/go-colorable v0.1.11 // indirect
25 | github.com/mattn/go-isatty v0.0.14 // indirect
26 | github.com/pkg/errors v0.9.1 // indirect
27 | github.com/samber/lo v1.27.1 // indirect
28 | github.com/tkrajina/go-reflector v0.5.5 // indirect
29 | github.com/valyala/bytebufferpool v1.0.0 // indirect
30 | github.com/valyala/fasttemplate v1.2.1 // indirect
31 | github.com/wailsapp/mimetype v1.4.1 // indirect
32 | golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 // indirect
33 | golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 // indirect
34 | golang.org/x/net v0.0.0-20220722155237-a158d28d115b // indirect
35 | golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f // indirect
36 | golang.org/x/text v0.3.7 // indirect
37 | )
38 |
--------------------------------------------------------------------------------
/go.sum:
--------------------------------------------------------------------------------
1 | github.com/bep/debounce v1.2.1 h1:v67fRdBA9UQu2NhLFXrSg0Brw7CexQekrBwDMM8bzeY=
2 | github.com/bep/debounce v1.2.1/go.mod h1:H8yggRPQKLUhUoqrJC1bO2xNya7vanpDl7xR3ISbCJ0=
3 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
4 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
5 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
6 | github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
7 | github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
8 | github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
9 | github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
10 | github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
11 | github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
12 | github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e h1:Q3+PugElBCf4PFpxhErSzU3/PY5sFL5Z6rfv4AbGAck=
13 | github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs=
14 | github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U=
15 | github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
16 | github.com/labstack/echo/v4 v4.9.0 h1:wPOF1CE6gvt/kmbMR4dGzWvHMPT+sAEUJOwOTtvITVY=
17 | github.com/labstack/echo/v4 v4.9.0/go.mod h1:xkCDAdFCIf8jsFQ5NnbK7oqaF/yU1A1X20Ltm0OvSks=
18 | github.com/labstack/gommon v0.3.1 h1:OomWaJXm7xR6L1HmEtGyQf26TEn7V6X88mktX9kee9o=
19 | github.com/labstack/gommon v0.3.1/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM=
20 | github.com/leaanthony/debme v1.2.1 h1:9Tgwf+kjcrbMQ4WnPcEIUcQuIZYqdWftzZkBr+i/oOc=
21 | github.com/leaanthony/debme v1.2.1/go.mod h1:3V+sCm5tYAgQymvSOfYQ5Xx2JCr+OXiD9Jkw3otUjiA=
22 | github.com/leaanthony/go-ansi-parser v1.0.1 h1:97v6c5kYppVsbScf4r/VZdXyQ21KQIfeQOk2DgKxGG4=
23 | github.com/leaanthony/go-ansi-parser v1.0.1/go.mod h1:7arTzgVI47srICYhvgUV4CGd063sGEeoSlych5yeSPM=
24 | github.com/leaanthony/gosod v1.0.3 h1:Fnt+/B6NjQOVuCWOKYRREZnjGyvg+mEhd1nkkA04aTQ=
25 | github.com/leaanthony/gosod v1.0.3/go.mod h1:BJ2J+oHsQIyIQpnLPjnqFGTMnOZXDbvWtRCSG7jGxs4=
26 | github.com/leaanthony/slicer v1.5.0 h1:aHYTN8xbCCLxJmkNKiLB6tgcMARl4eWmH9/F+S/0HtY=
27 | github.com/leaanthony/slicer v1.5.0/go.mod h1:FwrApmf8gOrpzEWM2J/9Lh79tyq8KTX5AzRtwV7m4AY=
28 | github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE=
29 | github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU=
30 | github.com/mattn/go-colorable v0.1.11 h1:nQ+aFkoE2TMGc0b68U2OKSexC+eq46+XwZzWXHRmPYs=
31 | github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
32 | github.com/mattn/go-ieproxy v0.0.7 h1:d2hBmNUJOAf2aGgzMQtz1wBByJQvRk72/1TXBiCVHXU=
33 | github.com/mattn/go-ieproxy v0.0.7/go.mod h1:6ZpRmhBaYuBX1U2za+9rC9iCGLsSp2tftelZne7CPko=
34 | github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
35 | github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
36 | github.com/pkg/browser v0.0.0-20210706143420-7d21f8c997e2 h1:acNfDZXmm28D2Yg/c3ALnZStzNaZMSagpbr96vY6Zjc=
37 | github.com/pkg/browser v0.0.0-20210706143420-7d21f8c997e2/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI=
38 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
39 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
40 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
41 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
42 | github.com/samber/lo v1.27.1 h1:sTXwkRiIFIQG+G0HeAvOEnGjqWeWtI9cg5/n51KrxPg=
43 | github.com/samber/lo v1.27.1/go.mod h1:it33p9UtPMS7z72fP4gw/EIfQB2eI8ke7GR2wc6+Rhg=
44 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
45 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
46 | github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
47 | github.com/thoas/go-funk v0.9.1 h1:O549iLZqPpTUQ10ykd26sZhzD+rmR5pWhuElrhbC20M=
48 | github.com/tkrajina/go-reflector v0.5.5 h1:gwoQFNye30Kk7NrExj8zm3zFtrGPqOkzFMLuQZg1DtQ=
49 | github.com/tkrajina/go-reflector v0.5.5/go.mod h1:ECbqLgccecY5kPmPmXg1MrHW585yMcDkVl6IvJe64T4=
50 | github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
51 | github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
52 | github.com/valyala/fasttemplate v1.2.1 h1:TVEnxayobAdVkhQfrfes2IzOB6o+z4roRkPF52WA1u4=
53 | github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
54 | github.com/wailsapp/mimetype v1.4.1 h1:pQN9ycO7uo4vsUUuPeHEYoUkLVkaRntMnHJxVwYhwHs=
55 | github.com/wailsapp/mimetype v1.4.1/go.mod h1:9aV5k31bBOv5z6u+QP8TltzvNGJPmNJD4XlAL3U+j3o=
56 | github.com/wailsapp/wails/v2 v2.3.1 h1:ZJz+pyIBKyASkgO8JO31NuHO1gTTHmvwiHYHwei1CqM=
57 | github.com/wailsapp/wails/v2 v2.3.1/go.mod h1:zlNLI0E2c2qA6miiuAHtp0Bac8FaGH0tlhA19OssR/8=
58 | go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU=
59 | go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4=
60 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
61 | golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg=
62 | golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
63 | golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 h1:3MTrJm4PyNL9NBqvYDSj3DHl46qQakyfqfWo4jgfaEM=
64 | golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE=
65 | golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
66 | golang.org/x/net v0.0.0-20220107192237-5cfca573fb4d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
67 | golang.org/x/net v0.0.0-20220722155237-a158d28d115b h1:PxfKdU9lEEDYjdIzOtC4qFWgkU2rGHdKlKowJSMN9h0=
68 | golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
69 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
70 | golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
71 | golang.org/x/sys v0.0.0-20200810151505-1b9f1253b3ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
72 | golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
73 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
74 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
75 | golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
76 | golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
77 | golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
78 | golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
79 | golang.org/x/sys v0.0.0-20220110181412-a018aaa089fe/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
80 | golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f h1:v4INt8xihDGvnrfjMDVXGxw9wrfxYyCjk0KbXjhR55s=
81 | golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
82 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
83 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
84 | golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
85 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
86 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
87 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
88 | gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
89 | gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
90 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
91 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
92 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
93 |
--------------------------------------------------------------------------------
/main.go:
--------------------------------------------------------------------------------
1 | //go:build !browser
2 |
3 | package main
4 |
5 | import (
6 | "context"
7 | "embed"
8 | "log"
9 | "net/http"
10 | "os"
11 | "path"
12 |
13 | "github.com/mattn/go-ieproxy"
14 | "github.com/wailsapp/wails/v2"
15 | "github.com/wailsapp/wails/v2/pkg/options"
16 | "github.com/wailsapp/wails/v2/pkg/options/windows"
17 | "github.com/xmdhs/player-go/api"
18 | "github.com/xmdhs/player-go/cors"
19 | "go.etcd.io/bbolt"
20 | )
21 |
22 | //go:embed frontend/dist
23 | var assets embed.FS
24 |
25 | func main() {
26 | t := http.DefaultTransport.(*http.Transport).Clone()
27 | t.Proxy = ieproxy.GetProxyFunc()
28 |
29 | db, err := bbolt.Open("player.db", 0600, nil)
30 | if err != nil {
31 | panic(err)
32 | }
33 | app := &App{
34 | t: t,
35 | db: db,
36 | }
37 | pwd, err := os.Getwd()
38 | if err != nil {
39 | panic(err)
40 | }
41 |
42 | err = wails.Run(&options.App{
43 | Title: "player",
44 | Width: 800,
45 | Height: 600,
46 | Assets: &assets,
47 | OnStartup: app.startup,
48 | OnShutdown: app.shutdown,
49 | Bind: []interface{}{
50 | app,
51 | },
52 | Windows: &windows.Options{
53 | WebviewUserDataPath: path.Join(pwd, "data"),
54 | },
55 | })
56 | if err != nil {
57 | log.Fatal(err)
58 | }
59 | }
60 |
61 | type App struct {
62 | ctx context.Context
63 | t *http.Transport
64 | db *bbolt.DB
65 | }
66 |
67 | func (b *App) startup(ctx context.Context) {
68 | b.ctx = ctx
69 | }
70 |
71 | func (b *App) shutdown(ctx context.Context) {}
72 |
73 | func (b *App) CorsServer() int {
74 | return cors.Server(b.ctx, b.t)
75 | }
76 |
77 | func (b *App) ApiServer() int {
78 | return api.Server(b.ctx, b.db, b.t)
79 | }
80 |
--------------------------------------------------------------------------------
/utils/utils.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import (
4 | "net"
5 | "strconv"
6 | "strings"
7 | )
8 |
9 | func GetProt() int64 {
10 | l, err := net.Listen("tcp", "127.0.0.1:0")
11 | if err != nil {
12 | panic(err)
13 | }
14 | defer l.Close()
15 | list := strings.Split(l.Addr().String(), ":")
16 | i, err := strconv.ParseInt(list[1], 10, 64)
17 | if err != nil {
18 | panic(err)
19 | }
20 | return i
21 | }
22 |
--------------------------------------------------------------------------------
/wails.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "player-go",
3 | "info": {
4 | "productVersion": "0.0.1",
5 | "copyright": "xmdhs",
6 | "comments": "player for danmu"
7 | },
8 | "outputfilename": "player"
9 | }
--------------------------------------------------------------------------------