Este software é para meu uso pessoal e não sou responsável pela forma como você o utilizará. Então, fique longe de encrencas, faça potes e não guerras!
Uma das minhas atividades profissionais consiste em divulgar o Redis, e isso também acontece com vídeos e webinars ao vivo. Recentemente estou fazendo lives no LinkedIn, transmitindo minha live pelo Zoom, e nem sempre me lembro de apertar o botão “Gravar”.
Porém, e felizmente, o LinkedIn mantém a gravação da minha live como “Gravada anteriormente ao vivo”, para que possa ser assistida posteriormente. Não tenho ideia da retenção que o LinkedIn oferece para esses vídeos, mas tenho certeza de que não oferece uma maneira de baixar esses vídeos.
Então, pesquisei no Google e não consegui encontrar nada sério. Download do YouTube, download do Pinterest, download do Facebook, mas todos os downloaders relacionados ao LinkedIn eram simplesmente falsos.
Portanto, preciso construir meu próprio LinkedIn Video Downloader! ?
Agora, a ideia era... Acho que não vou encontrar um link (src ou href) para algum vídeo na fonte 1 de algum tipo de formato (mp4, webm, vid mkv, avi, mov e assim por diante) , mas acho que encontrarei algo relacionado ao streaming de vídeo... mas não na fonte 1 , certamente no nível da rede.
Então, abri o Chrome e sua barra DevTools, selecionei o painel Rede e digitei (colei) o URL do meu evento de vídeo do LinkedIn na barra de endereço e pressionei Enter!
E foi isso que consegui.
Agora preciso encontrar algo que me lembre em relação a vídeo/stream/chunks/binary/qualquer coisa... então comecei a rolar o painel Rede e depois de algumas rolagens ouvi o primeiro sino! ?
Uma olhada melhor no mesmo pergaminho, e também encontrei outras informações. ?
Sim, metadados, mas sei que estamos chegando lá! Mas vamos ver o que conseguimos até agora:
Agora precisamos desses fragmentos.
Rolando um pouco mais para baixo e aqui está o primeiro fragmento. ?
Finalmente, um formato binário! Deve ser um fragmento do filme.
Uma verificação rápida com curl ...
Abra o terminal, copie e cole...
foogaro@MBP-di-Luigi tmp % curl ' https://streamweu-livectorprodmedia17-euwe.licdn.com/44eefc72-771d-4bfd-8985-aede1310be0f/L4E609f69d951866001-livemanifest.ism/QualityLevels(3200000)/Fragments(video=65886000,format=m3u8-aapl-v3,audiotrack=audio_und) ' --compressed
Warning: Binary output can mess up your terminal. Use " --output - " to tell
Warning: curl to output it to your terminal anyway, or consider " --output
Warning: <FILE> " to save to a file.
foogaro@MBP-di-Luigi tmp % curl ' https://streamweu-livectorprodmedia17-euwe.licdn.com/44eefc72-771d-4bfd-8985-aede1310be0f/L4E609f69d951866001-livemanifest.ism/QualityLevels(3200000)/Fragments(video=65886000,format=m3u8-aapl-v3,audiotrack=audio_und) ' --compressed -O
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 158k 100 158k 0 0 868k 0 --:--:-- --:--:-- --:--:-- 924k
foogaro@MBP-di-Luigi tmp % ll
total 320
drwxr-xr-x 3 foogaro staff 96 24 Ago 22:37 .
drwxr-xr-x 6 foogaro staff 192 24 Ago 22:37 ..
-rw-r--r-- 1 foogaro staff 162808 24 Ago 22:37 Fragments(video=65886000,format=m3u8-aapl-v3,audiotrack=audio_und)
foogaro@MBP-di-Luigi tmp % file Fragments ( video=65886000,format=m3u8-aapl-v3,audiotrack=audio_und )
Fragments(video=65886000,format=m3u8-aapl-v3,audiotrack=audio_und): MPEG transport stream data
foogaro@MBP-di-Luigi tmp % curl ' https://streamweu-livectorprodmedia17-euwe.licdn.com/44eefc72-771d-4bfd-8985-aede1310be0f/L4E609f69d951866001-livemanifest.ism/QualityLevels(3200000)/Fragments(video=65886000,format=m3u8-aapl-v3,audiotrack=audio_und) ' --compressed -o video.mpeg
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 158k 100 158k 0 0 926k 0 --:--:-- --:--:-- --:--:-- 981k
foogaro@MBP-di-Luigi tmp % ll
total 640
drwxr-xr-x 4 foogaro staff 128 24 Ago 22:39 .
drwxr-xr-x 6 foogaro staff 192 24 Ago 22:37 ..
-rw-r--r-- 1 foogaro staff 162808 24 Ago 22:37 Fragments(video=65886000,format=m3u8-aapl-v3,audiotrack=audio_und)
-rw-r--r-- 1 foogaro staff 162808 24 Ago 22:39 video.mpeg
foogaro@MBP-di-Luigi tmp %
Vamos ver se é um vídeo de verdade...
É um vídeo real e tem cerca de 2 segundos de duração, o que corresponde à TARGETDURATION que encontramos na lista completa de fragmentos. ?
Continue rolando e aqui estão eles.
Fragmentos, vejo fragmentos por toda parte.
Não vou descrever o código, você mesmo pode dar uma olhada, mas posso dizer o que foi necessário:
A implementação deve ser considerada na melhor das hipóteses, o que significa que funciona no meu computador!
A última parte da implementação, baixar/transmitir o arquivo de volta, foi possível graças a @swathisprasad (Swathi Prasad) e seu repositório https://github.com/swathisprasad/download-using-streaming-response-body
De resto, claro, graças ao StackOverflow.
Experimente com o docker se quiser:
foogaro@MBP-di-Luigi linkedin-video-downloader % docker run -it --rm=true -p 8080:8080 foogaro/linkedin-video-downloader
. ____ _ __ _ _
/ \ / ___ ' _ __ _ _(_)_ __ __ _
( ( )___ | ' _ | ' _| | ' _ / _ ` |
\ / ___) | | _) | | | | | || (_ | | ) ) ) )
' |____| .__|_| |_|_| |___, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.7.0)
2022-08-24 22:57:01.107 INFO 1 --- [ main] c.foogaro.data.LinkedInVideoApplication : Starting LinkedInVideoApplication v1.0.0 using Java 11.0.16.1 on c543811fe9f3 with PID 1 (/app/app.jar started by root in /app)
2022-08-24 22:57:01.121 INFO 1 --- [ main] c.foogaro.data.LinkedInVideoApplication : No active profile set, falling back to 1 default profile: "default"
2022-08-24 22:57:03.037 INFO 1 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2022-08-24 22:57:03.060 INFO 1 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2022-08-24 22:57:03.060 INFO 1 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.63]
2022-08-24 22:57:03.171 INFO 1 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2022-08-24 22:57:03.171 INFO 1 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 1969 ms
2022-08-24 22:57:03.900 INFO 1 --- [ main] o.s.b.a.w.s.WelcomePageHandlerMapping : Adding welcome page template: index
2022-08-24 22:57:04.286 INFO 1 --- [ main] o.s.b.a.e.web.EndpointLinksResolver : Exposing 1 endpoint(s) beneath base path ' /actuator '
2022-08-24 22:57:04.363 INFO 1 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ' '
2022-08-24 22:57:04.391 INFO 1 --- [ main] c.foogaro.data.LinkedInVideoApplication : Started LinkedInVideoApplication in 3.931 seconds (JVM running for 4.532)
2022-08-24 22:57:05.282 INFO 1 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet ' dispatcherServlet '
2022-08-24 22:57:05.283 INFO 1 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet ' dispatcherServlet '
2022-08-24 22:57:05.289 INFO 1 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 4 ms
2022-08-24 22:57:21.779 INFO 1 --- [nio-8080-exec-7] c.f.d.c.LinkedInVideoController : Steaming video download as: linkedin-video-1661421441774.zip
2022-08-24 22:57:21.800 INFO 1 --- [ taskExecutor-1] c.f.d.c.LinkedInVideoController : Video ID: c50f2327-7fa7-4cc8-8a2c-35711eb5296d/L4E60a4445e9d065000
2022-08-24 22:57:21.800 INFO 1 --- [ taskExecutor-1] c.f.d.c.LinkedInVideoController : Quality Level: 3200000
2022-08-24 22:57:21.991 INFO 1 --- [ taskExecutor-1] c.f.d.c.LinkedInVideoController : Number of video fragments: 2154
Obrigado por ler até agora!
Se você gostou ou achou útil, me dê uma estrela!
PRs são mais que bem-vindos, tanto no frontend quanto no backend! ?
Menti, procurei o link do vídeo no source da página! ? ↩ ↩ 2