Microservice on GO للاستيلاء على الفيديو من التغريدات

عمت مساءً يا خبرافشيانس! مقال للمبتدئين ، نوع من الأفكار الجديدة التي لن تراها هنا. وهذه الوظيفة ، على الأرجح ، تم تنفيذها عشرات المرات بلغات مختلفة. الفكرة هي أنه إذا حصلت على رابط إلى منشور على Twitter يحتوي على مقطع فيديو ، فاختر هذا الفيديو وقم بتحويله إلى mkv.


لرجال الأعمال!


ما نحتاجه:


  • اذهب
  • ffmpeg
  • عامل ميناء (على الرغم من أنه من الممكن بدونه. ومع ذلك ، أين بدونه هذه الأيام؟! ؛)

لدينا رابط إلى تغريدة من الفيديو:


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) 

من أين نحصل على رابط رمز JS لمشغل الفيديو:


src="https://abs.twimg.com/web-video-player/TwitterVideoPlayerIframe.f52b5b572446290e.js"
من هذا الملف js نحتاج إلى شيء واحد مهم للغاية - حامل الترخيص للحصول على إذن في twitter api.


Regex'pee له!


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

هذا لا يكفي للوصول إلى واجهة برمجة التطبيقات ، ما زلت بحاجة إلى guest_token. يمكن الحصول عليها عن طريق تطبيق طلب POST على العنوان - " https://api.twitter.com/1.1/guest/activate.json " ، ويمر هناك: personalization_id و guest_id من ملف تعريف الارتباط (الذي تلقيناه في الرد من الخادم عند الوصول إلى الخادم السابق) عنوان URL):


  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 يسمح لك بتجاوز حد api لـ 300 طلب.


الجواب هو gzip ، يمكن فكه في Go ، شيء مثل هذا:


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

حسنا ، هذا كل شيء! الآن لدينا كل ما نحتاجه للاتصال بـ API:


  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) 

ستكون استجابة API هي Json مع وصف للفيديو ، والأهم من ذلك ، عنوان URL لاستلامه (playbackUrl):


 {"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 ، بينما نتحقق من تنسيق الفيديو الذي رأيته بتنسيقين محتملين ، الأول هو 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) { 

كيف يمكن جمع كل هذا؟


على سبيل المثال ، Makefile بسيط (إنشاء ، جعل تشغيل ...):


 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" ، في الصورة الأساسية أوبونتو لم تكن هناك شهادات جذر ولم يتعرف عميل http على https twitter ، وألقاها من الجهاز المضيف عبر --volume (الآن ، مثل كيف ، فمن الأصح استخدام - جبل ).


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/ar442096/


All Articles