Buenas tardes, Khabravchians! Artículo para principiantes, algún tipo de nuevas ideas que no verá aquí. Y esta funcionalidad, muy probablemente, se implementó docenas de veces en varios idiomas. La idea es que si obtiene un enlace a una publicación en Twitter que contiene un video, tome este video y conviértalo a mkv.
A los negocios!
Lo que necesitamos
- Ir
- ffmpeg
- acoplador (aunque es posible sin él. Sin embargo, ¿dónde sin él en estos días?!;)
Tenemos un enlace a un tweet del video:
https://twitter.com/FunnyVines/status/1101196533830041600
De todo el enlace, solo estamos interesados en la identificación que consiste en números, por lo que extraemos toda la subcadena digital con una regularidad elemental:
var reurl = regexp.MustCompile(`\/(\d*)$`)
Con la identificación recibida, vaya a la dirección:
resp, err := client.Get("https://twitter.com/i/videos/tweet/" + id)
¿Dónde obtenemos el enlace al código JS del reproductor de video?
src="https://abs.twimg.com/web-video-player/TwitterVideoPlayerIframe.f52b5b572446290e.js"
De este archivo js necesitamos una cosa muy importante: portador de la autorización en la API de Twitter.
Regex'pee le!
re, _ := regexp.Compile(`(?m)authorization:\"Bearer (.*)\",\"x-csrf`)
Esto no es suficiente para acceder a la API, aún necesita guest_token. Se puede obtener aplicando una solicitud POST a la dirección: " https://api.twitter.com/1.1/guest/activate.json ", pasando allí: personalization_id y guest_id de la cookie (que recibimos en la respuesta del servidor al acceder a la anterior 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 } }
token de invitadoCambia periódicamente, no entendía con qué frecuencia llamarlo (más bien, cambia en el temporizador, un intervalo de 15 minutos), pero parece que la activación regular de /1.1/guest/activate.json le permite omitir el límite de la API para 300 solicitudes.
La respuesta es gzip, se puede desempaquetar en Go, algo como esto:
res, err := gzip.NewReader(resp.Body) if err != nil { return "", err } defer res.Close() r, err := ioutil.ReadAll(res)
Bueno, eso es todo! Ahora tenemos todo lo que necesitamos para llamar a la 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)
La respuesta de la API será Json con una descripción del video y, lo más importante, la URL para recibirlo (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"
Y finalmente, tenemos la dirección del video, la enviamos a ffmpeg, mientras comprobamos en qué formato de video vi 2 formatos posibles, el primero es 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 }
Y el segundo es el archivo de lista de reproducción m3u8 , para esta opción se necesita un paso más: obtenemos
él y tome la URL del contenido en la resolución deseada:
#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
Y aún así, ffmpeg.
Y ahora, un poco sobre el servidor HTTP
Yo usé:
La lógica es la siguiente, iniciamos el servidor:
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) }
Y procesamos solo una ruta / * video:
¿Cómo se puede recoger todo esto?
Por ejemplo, un Makefile simple (make build, make run ...):
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
Preste atención al indicador "-v / etc / ssl: / etc / ssl: ro", en la imagen base ubuntu no había certificados raíz y el cliente http no reconocía https twitter, lo lanzó desde la máquina host a través de --volume (ahora, como cómo, es más correcto usar --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
Sin lugar a dudas, no descubrí América en este artículo, pero de repente será útil para alguien.
Las fuentes están disponibles aquí .