рдЯреНрд╡реАрдЯреНрд╕ рд╕реЗ рд╡реАрдбрд┐рдпреЛ рд╣рдерд┐рдпрд╛рдиреЗ рдХреЗ рд▓рд┐рдП GO рдкрд░ рдорд╛рдЗрдХреНрд░реЛрд╕реЙрд░реНрд╕реНрдЯ

рд╢реБрдн рджреЛрдкрд╣рд░, рдЦрд╛рдмрд░рд╡рдЪрд┐рдпрди! рд╢реБрд░реБрдЖрддреА рд▓реЛрдЧреЛрдВ рдХреЗ рд▓рд┐рдП рдЕрдиреБрдЪреНрдЫреЗрдж, рдХреБрдЫ рдкреНрд░рдХрд╛рд░ рдХреЗ рдирдП рд╡рд┐рдЪрд╛рд░ рдЬреЛ рдЖрдк рдпрд╣рд╛рдВ рдирд╣реАрдВ рджреЗрдЦреЗрдВрдЧреЗред рдФрд░ рдпрд╣ рдХрд╛рд░реНрдпрдХреНрд╖рдорддрд╛, рд╕рдмрд╕реЗ рдЕрдзрд┐рдХ рд╕рдВрднрд╛рд╡рдирд╛ рд╣реИ, рд╡рд┐рднрд┐рдиреНрди рднрд╛рд╖рд╛рдУрдВ рдореЗрдВ рджрд░реНрдЬрдиреЛрдВ рдмрд╛рд░ рд▓рд╛рдЧреВ рдХреА рдЧрдИ рдереАред рд╡рд┐рдЪрд╛рд░ рдпрд╣ рд╣реИ рдХрд┐ рдпрджрд┐ рдЖрдкрдХреЛ рдЯреНрд╡рд┐рдЯрд░ рдкрд░ рдПрдХ рдкреЛрд╕реНрдЯ рдХрд╛ рд▓рд┐рдВрдХ рдорд┐рд▓рддрд╛ рд╣реИ рдЬрд┐рд╕рдореЗрдВ рдПрдХ рд╡реАрдбрд┐рдпреЛ рд╣реИ, рддреЛ рдЗрд╕ рд╡реАрдбрд┐рдпреЛ рдХреЛ рдЪреБрдиреЗрдВ рдФрд░ рдЗрд╕реЗ mkv рдореЗрдВ рдмрджрд▓ рджреЗрдВред


рд╡реНрдпрд╛рдкрд╛рд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП!


рд╣рдореЗрдВ рдХреНрдпрд╛ рдЪрд╛рд╣рд┐рдП:


  • GO
  • ffmpeg
  • docker (рд╣рд╛рд▓рд╛рдБрдХрд┐ рдпрд╣ рдЗрд╕рдХреЗ рдмрд┐рдирд╛ рд╕рдВрднрд╡ рд╣реИред рд╣рд╛рд▓рд╛рдБрдХрд┐, рдЗрди рджрд┐рдиреЛрдВ рдЗрд╕рдХреЗ рдмрд┐рдирд╛ рдХрд╣рд╛рдБ?;)

рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рд╡реАрдбрд┐рдпреЛ рдХреЗ рдПрдХ рдЯреНрд╡реАрдЯ рдХрд╛ рд▓рд┐рдВрдХ рд╣реИ:


https://twitter.com/FunnyVines/status/1101196533830041600 

рд╕рдВрдкреВрд░реНрдг рд▓рд┐рдВрдХ рдореЗрдВ рд╕реЗ, рд╣рдо рдХреЗрд╡рд▓ рд╕рдВрдЦреНрдпрд╛рдУрдВ рд╕реЗ рдорд┐рд▓рдХрд░ рдЖрдИрдбреА рдореЗрдВ рд░реБрдЪрд┐ рд░рдЦрддреЗ рд╣реИрдВ, рдЗрд╕рд▓рд┐рдП рд╣рдо рдкреНрд░рд╛рдердорд┐рдХ рдирд┐рдпрдорд┐рддрддрд╛ рдХреЗ рд╕рд╛рде рдкреВрд░реЗ рдбрд┐рдЬрд┐рдЯрд▓ рд╡рд┐рдХрд▓реНрдк рдХреЛ рдЦреАрдВрдЪрддреЗ рд╣реИрдВ:


 var reurl = regexp.MustCompile(`\/(\d*)$`) //   -  e.GET("/*video", func(c *fasthttp.RequestCtx) { //      url := reurl.FindSubmatch([]byte(c.UserValue("video").(string))) 

рдкреНрд░рд╛рдкреНрдд рдЖрдИрдбреА рдХреЗ рд╕рд╛рде, рдкрддреЗ рдкрд░ рдЬрд╛рдПрдВ:


 resp, err := client.Get("https://twitter.com/i/videos/tweet/" + id) 

рд╣рдореЗрдВ рд╡реАрдбрд┐рдпреЛ рдкреНрд▓реЗрдпрд░ рдХреЗ рдЬреЗрдПрд╕ рдХреЛрдб рдХрд╛ рд▓рд┐рдВрдХ рдХрд╣рд╛рдВ рдорд┐рд▓реЗрдЧрд╛:


src="https://abs.twimg.com/web-video-player/TwitterVideoPlayerIframe.f52b5b572446290e.js"
рдЗрд╕ рдЬреЗрдПрд╕ рдлрд╝рд╛рдЗрд▓ рд╕реЗ, рд╣рдореЗрдВ рдЯреНрд╡рд┐рдЯрд░ рдПрдк рдореЗрдВ рдкреНрд░рд╛рдзрд┐рдХрд░рдг рдХреЗ рд▓рд┐рдП рдПрдХ рдмрд╣реБрдд рд╣реА рдорд╣рддреНрд╡рдкреВрд░реНрдг рдЪреАрдЬ - рд╡рд╛рд╣рдХ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред


рдЙрд╕реЗ Regex'pee!


 re, _ := regexp.Compile(`(?m)authorization:\"Bearer (.*)\",\"x-csrf`) 

рдпрд╣ рдПрдкреАрдЖрдИ рддрдХ рдкрд╣реБрдВрдЪрдиреЗ рдХреЗ рд▓рд┐рдП рдкрд░реНрдпрд╛рдкреНрдд рдирд╣реАрдВ рд╣реИ, рдлрд┐рд░ рднреА рдЖрдкрдХреЛ guest_token рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рдпрд╣ рдкрддреЗ рдкрд░ рдПрдХ POST рдЕрдиреБрд░реЛрдз рд▓рд╛рдЧреВ рдХрд░рдХреЗ рдкреНрд░рд╛рдкреНрдд рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ - " https://api.twitter.com/1.1/guest/activate.json ", рд╡рд╣рд╛рдВ рд╕реЗ рдЧреБрдЬрд░ рд░рд╣рд╛ рд╣реИ: рдХреБрдХреА рд╕реЗ рд╡реИрдпрдХреНрддрд┐рдХрд░рдг_рдЖрдИрдбреА рдФрд░ guest_id (рдЬреЛ рд╣рдореЗрдВ рдкрд┐рдЫрд▓реЗ рдПрдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╕рдордп рд╕рд░реНрд╡рд░ рд╕реЗ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдореЗрдВ рдкреНрд░рд╛рдкреНрдд рд╣реБрдЖ рдерд╛) рдпреВрдЖрд░рдПрд▓):


  var personalization_id, guest_id string cookies := resp.Cookies() for _, cookie := range cookies { if cookie.Name == "personalization_id" { personalization_id = cookie.Value } if cookie.Name == "guest_id" { guest_id = cookie.Value } } // // Get Activation url, _ := url.Parse("https://api.twitter.com/1.1/guest/activate.json") request := &http.Request{ Method: "POST", URL: url, Header: http.Header{ "user-agent": []string{"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36"}, "accept-encoding": []string{"gzip", "deflate", "br"}, "authorization": []string{"Bearer " + bearer}, "cookie": []string{"personalization_id=\"" + personalization_id + "\"; guest_id=" + guest_id} }, } resp, err = client.Do(request) 

guest_token

рдпрд╣ рд╕рдордп-рд╕рдордп рдкрд░ рдмрджрд▓рддрд╛ рд╣реИ, рдореБрдЭреЗ рд╕рдордЭ рдореЗрдВ рдирд╣реАрдВ рдЖрдпрд╛ рдХрд┐ рдЗрд╕реЗ рдХрд┐рддрдиреА рдмрд╛рд░ рдХреЙрд▓ рдХрд░рдирд╛ рд╣реИ (рдмрд▓реНрдХрд┐, рдпрд╣ рдЯрд╛рдЗрдорд░ рдореЗрдВ рдмрджрд▓рддрд╛ рд╣реИ - 15 рдорд┐рдирдЯ рдХрд╛ рдЕрдВрддрд░рд╛рд▓), рд▓реЗрдХрд┐рди рдРрд╕рд╛ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдирд┐рдпрдорд┐рдд рд░реВрдк рд╕реЗ /1.1/guest/activate.json рдХрд╛ рд╕рдХреНрд░рд┐рдпрдг рдЖрдкрдХреЛ 300 рдЕрдиреБрд░реЛрдзреЛрдВ рдХреЗ рд▓рд┐рдП рдПрдк рд╕реАрдорд╛ рдХреЛ рдмрд╛рдпрдкрд╛рд╕ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИред


рдЬрд╡рд╛рдм рдЧрдЬрд╝рдм рд╣реИ, рдЗрд╕реЗ рдЧреЛ рдореЗрдВ рдЕрдирдкреИрдХ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ, рдХреБрдЫ рдЗрд╕ рддрд░рд╣:


 res, err := gzip.NewReader(resp.Body) if err != nil { return "", err } defer res.Close() r, err := ioutil.ReadAll(res) 

рдЦреИрд░, рдпрд╣ рдмрд╛рдд рд╣реИ! рдЕрдм рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдПрдкреАрдЖрдИ рдХреЛ рдХреЙрд▓ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХ рд╕рдм рдХреБрдЫ рд╣реИ:


  url, _ = url.Parse("https://api.twitter.com/1.1/videos/tweet/config/" + id + ".json") request = &http.Request{ Method: "GET", URL: url, Header: http.Header{ "user-agent": []string{"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36"}, "accept-encoding": []string{"gzip", "deflate", "br"}, "origin": []string{"https://twitter.com"}, "x-guest-token": []string{gt.GuestToken}, "referer": []string{"https://twitter.com/i/videos/tweet/" + id}, "authorization": []string{"Bearer " + bearer}}, } resp, err = client.Do(request) 

рдПрдкреАрдЖрдИ рд╕реЗ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рд╡реАрдбрд┐рдпреЛ рдХреЗ рд╡рд┐рд╡рд░рдг рдХреЗ рд╕рд╛рде рдЬрд╕рди рд╣реЛрдЧреА, рдФрд░ рд╕рдмрд╕реЗ рдорд╣рддреНрд╡рдкреВрд░реНрдг рдмрд╛рдд, рдЗрд╕реЗ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП URL (рдкреНрд▓реЗрдмреИрдХ рдпреВрдЖрд░рдПрд▓):


 {"contentType":"media_entity","publisherId":"4888096512","contentId":"1096941371649347584","durationMs":11201,"playbackUrl":"https:\/\/video.twimg.com\/ext_tw_video\/1096941371649347584\/pu\/pl\/xcBvPmwAmKckck-F.m3u8?tag=6","playbackType" 

рдФрд░ рдЕрдВрдд рдореЗрдВ, рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рд╡реАрдбрд┐рдпреЛ рдХрд╛ рдкрддрд╛ рд╣реИ, рд╣рдо рдЗрд╕реЗ ffmpeg рдкрд░ рднреЗрдЬрддреЗ рд╣реИрдВ, рдЬрд┐рд╕рдореЗрдВ рд╡реАрдбрд┐рдпреЛ рдкреНрд░рд╛рд░реВрдк рдХреА рдЬрд╛рдВрдЪ рдХрд░рддреЗ рд╣реБрдП рдореИрдВрдиреЗ 2 рд╕рдВрднрд╛рд╡рд┐рдд рдкреНрд░рд╛рд░реВрдк рджреЗрдЦреЗ, рдкрд╣рд▓рд╛ рд╣реИ mp4:


 if strings.Contains(videoURL.Track.PlaybackURL, ".mp4") { convert := exec.Command("ffmpeg", "-i", videoURL.Track.PlaybackURL, "-c", "copy", "./videos/"+id+".mkv") convert.Stdout = os.Stdout convert.Stderr = os.Stderr if convert.Run() != nil { return "", err } return id, nil } 

рдФрд░ рджреВрд╕рд░рд╛ рдПрдХ m3u8 рдкреНрд▓реЗрд▓рд┐рд╕реНрдЯ рдлрд╝рд╛рдЗрд▓ рд╣реИ, рдЗрд╕ рд╡рд┐рдХрд▓реНрдк рдХреЗ рд▓рд┐рдП рдПрдХ рдФрд░ рдХрджрдо рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ - рд╣рдореЗрдВ GET рдорд┐рд▓рддрд╛ рд╣реИ
рдЙрд╕реЗ, рдФрд░ рд╡рд╛рдВрдЫрд┐рдд рд░рд┐рдЬрд╝реЙрд▓реНрдпреВрд╢рди рдореЗрдВ рд╕рд╛рдордЧреНрд░реА рдХрд╛ URL рд▓реЗрдВ:


 #EXT-X-INDEPENDENT-SEGMENTS #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=256000,RESOLUTION=180x316,CODECS="mp4a.40.2,avc1.4d0015" /ext_tw_video/1039516210948333568/pu/pl/180x316/x0HWMgnbSJ9y6NFL.m3u8 #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=832000,RESOLUTION=464x816,CODECS="mp4a.40.2,avc1.4d001f" /ext_tw_video/1039516210948333568/pu/pl/464x816/Z58__ptq1xBk8CIV.m3u8 

рдФрд░ рдлрд┐рд░ рднреА - ffmpegред


рдФрд░ рдЕрдм, HTTP рд╕рд░реНрд╡рд░ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдереЛрдбрд╝рд╛


рдореИрдВрдиреЗ рдЗрд╕реНрддреЗрдорд╛рд▓ рдХрд┐рдпрд╛:



рддрд░реНрдХ рдирд┐рдореНрдирд╛рдиреБрд╕рд╛рд░ рд╣реИ, рд╣рдо рд╕рд░реНрд╡рд░ рд╢реБрд░реВ рдХрд░рддреЗ рд╣реИрдВ:


 cfg := tcplisten.Config{ ReusePort: true, FastOpen: true, DeferAccept: true, Backlog: 1024, } ln, err := cfg.NewListener("tcp4", ":8080") if err != nil { log.Fatalf("error in reuseport listener: %s\n", err) } serv := fasthttp.Server{Handler: e.Handler, ReduceMemoryUsage: false, Name: "highload", Concurrency: 2 * 1024, DisableHeaderNamesNormalizing: true} if err := serv.Serve(ln); err != nil { log.Fatalf("error in fasthttp Server: %s", err) } 

рдФрд░ рд╣рдо рдХреЗрд╡рд▓ рдПрдХ рдорд╛рд░реНрдЧ / * рд╡реАрдбрд┐рдпреЛ рдХреА рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХрд░рддреЗ рд╣реИрдВ:


 //  : //  http://localhost:8080/https://twitter.com/FunnyVines/status/1101196533830041600 //   http://localhost:8080/1101196533830041600 e.GET("/*video", func(c *fasthttp.RequestCtx) { 

рдпрд╣ рд╕рдм рдХреИрд╕реЗ рдПрдХрддреНрд░ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ?


рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдПрдХ рд╕рд╛рдзрд╛рд░рдг рдореЗрдХрдлрд╛рдЗрд▓ (рдирд┐рд░реНрдорд╛рдг рдХрд░реЗрдВ, рд░рди рдмрдирд╛рдПрдВ ...):


 build: go build -o main docker build -t tvideo . run: go build -o main docker build -t tvideo . docker kill tvideo docker run -d --rm --name tvideo -v /etc/ssl:/etc/ssl:ro -v videos:/opt/videos -p 8080:8080 tvideo docker logs -f tvideo 

рдзреНрд╡рдЬ рдкрд░ рдзреНрдпрд╛рди рджреЗрдВ "-v / etc / ssl: / etc / ssl: ro", рдЖрдзрд╛рд░ рдЫрд╡рд┐ ubuntu рдореЗрдВ рдХреЛрдИ рдореВрд▓ рдкреНрд░рдорд╛рдг рдкрддреНрд░ рдирд╣реАрдВ рдереЗ рдФрд░ http рдХреНрд▓рд╛рдЗрдВрдЯ рдиреЗ рдЯреНрд╡рд┐рдЯрд░ https рдХреЛ рдирд╣реАрдВ рдкрд╣рдЪрд╛рдирд╛, рдЗрд╕реЗ рд╣реЛрд╕реНрдЯ рдорд╢реАрди рд╕реЗ - рд░реЛрд▓реНрдпреВрдо (рдЕрдм, рдЬреИрд╕реЗ) рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдлреЗрдВрдХ рджрд┐рдпрд╛ рдХреИрд╕реЗ, рдпрд╣ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЕрдзрд┐рдХ рд╕рд╣реА рд╣реИ --mount )ред


Dockerfile


 FROM ubuntu //     docker image COPY main /opt/app RUN apt-get update && \ //   apt-get install -y ffmpeg && \ chmod +x /opt/app EXPOSE 8080 WORKDIR /opt CMD ./app 

рдирд┐рд╕реНрд╕рдВрджреЗрд╣, рдореИрдВрдиреЗ рдЗрд╕ рд▓реЗрдЦ рдореЗрдВ рдЕрдореЗрд░рд┐рдХрд╛ рдХреА рдЦреЛрдЬ рдирд╣реАрдВ рдХреА рдереА, рд▓реЗрдХрд┐рди рдЕрдЪрд╛рдирдХ рдпрд╣ рдХрд┐рд╕реА рдХреЗ рдХрд╛рдо рдЖрдПрдЧрд╛ред


рдпрд╣рд╛рдВ рд╕реНрд░реЛрдд рдЙрдкрд▓рдмреНрдз рд╣реИрдВ ред

Source: https://habr.com/ru/post/hi442096/


All Articles