owo vídeo

Todos nós sabemos que o YouTube demora para enviar novos vídeos para a "box" (e as vezes nem envia o vídeo!), ou seja, muitas pessoas que são inscritas no seu canal talvez nem estejam recebendo seus novos vídeos! Para resolver este problema (junto com o grande aumento de YouTubers no Discord) eu tinha resolvido fazer o sistema de sincronizações de novos vídeos para a Loritta.

Parece simples né: Apenas verificar se o canal enviou um novo vídeo e, se ele enviou, notificar no servidor. Infelizmente isto apenas parece simples, já que para criar isto é bem mais complicado...

Neste post irei explicar toda a "história" por trás do sistema de verificação de novos vídeos do YouTube da Loritta, junto com todas as dificuldades que eu tive e como eu resolvi elas... talvez seja interessante caso você esteja fazendo um sistema parecido ou apenas está curioso para saber como eu fiz um sistema que (as vezes!) notifica mais rápido que o YouTube!

Soluções sem usar a Loritta

Antes de eu explicar como eu fiz a minha versão na Loritta, vamos explicar como alguém poderia notificar novos vídeos sem a Loritta.

IFTTT

Logo do IFTTT O IFTTT (if this then do that) é um serviço que permite você criar "receitas" para quando acontecer algo if this possa acontecer alguma coisa em outro serviço then do that, como por exemplo: Ao postar algo no Facebook, retweetar automaticamente no Twitter.

É possível usar o IFTTT para notificar novos vídeos do YouTube, mas o delay até ele notificar leva até 15 minutos, deixando inviável já que seria mais rápido alguém ficar vendo se o YouTuber enviou um novo vídeo e avisar manualmente.

Bot para fazer RSS feed relay

Existem bots no Discord (como o Discord.RSS) que conseguem pegar uma feed RSS e anunciar novidades quando algo acontecer nela, como o YouTube possui RSS feeds para canais do YouTube, é possível usar esses tipos de bots para notificar novos vídeos, mas...

  1. Desde o último update do YouTube, não é possível pegar mais as feeds RSS de canais de uma maneira "fácil", sendo necessário adicionar ?disable_polymer=1 na URL do canal para poder pegar o link da Feed RSS pelo "View Page Info" do Firefox (para os curiosos, o link para pegar a feed RSS de um canal é https://www.youtube.com/feeds/videos.xml?channel_id=ID do canal no YouTube)
  2. A feed RSS demora MUITO para atualizar se o canal é grande, mais informações sobre isto mais a frente no post...

Como surgiu a ideia de criar um sistema de sincronização de vídeos?

Eu estava no servidor do CoreDasAntigas no Discord e eu notei que o Core vivia enviando vídeos manualmente no canal de #novos-videos do servidor dele... ai eu pensei "hmmm, acho que seria possível automatizar isto!".

E foi assim que eu tive a ideia de criar um sistema de sincronização de vídeos do YouTube na Loritta.

Versão v1.0 - A primeira versão do sistema de sincronia de vídeos

29/06/2017 - 01/07/2017 Na primeira versão de verificações de vídeos do YouTube, eu fui inocente e fiz que apenas um canal poderia ser notificado por servidor (pensando que ninguém iria querer que a Loritta notificasse mais de um canal por servidor... estava errado!) e, para verificar novos vídeos do YouTube, eu pegava as informações do canal e pegava a playlist de últimos vídeos enviados e ficava comparando se o ID do último vídeo anunciado era diferente do último vídeo da playlist, se fosse, nós iriamos anunciar no servidor. Simples, não?

Enquanto ele funcionava para canais pequenos (e nos meus testes eu já estava "nossa, quando isso for colocado no servidor do Core vai ser uma maravilha e eu serei notado pelo senpai Core!"), em canais grandes (como o do CoreDasAntigas) era MUITO lerdo, já que a API do YouTube demora até 15 minutos para "atualizar" a API para mostrar que o usuário enviou um novo vídeo.

Após o SMix (um dos administradores do servidor do CoreDasAntigas) reclamar que a Loritta não estava anunciando novos vídeos, eu tive que repensar como eu poderia refazer o sistema de verificação de vídeos do YouTube

Versão v2.0 - Vamos verificar em TODOS os lugares!

01/07/2017 - 28/08/2017 Em um commit apropriadamente chamado "A API do YouTube é um lixo... Tentar corrigir problema de sincronia de vídeos recentes" eu tinha refeito quase completamente como a Loritta estava verificando novos vídeos do YouTube.

Para provar que o meu novo sistema iria funcionar bem, eu testei com um dos canais maiores e que postam todos os dias várias vezes eu conheço... RezendeEvil.

No novo sistema de verificação, eu tive que verificar de três maneiras diferentes para conseguir notificar novos vídeos de um canal, sendo elas...

  • A lista de playlists de envios recentes do canal
  • Usando a pesquisa do YouTube para procurar os vídeos mais recentes de um canal (já percebeu que as vezes, quando você procura no YouTube um canal, aparece um vídeo que o canal enviou recentemente mas ao procurar no canal dele você não encontra?)
  • Feeds RSS

Em vez de usar o velho sistema de comprar IDs, eu precisei ser mais esperto e comparar a data do último vídeo comparado com a data do último vídeo anunciado, já que como é verificado em três lugares diferentes, talvez um dos lugares esteja ainda mostrando o vídeo velho, causando dessincronização, fazendo que ela anuncie o último vídeo enviado e o último vídeo anunciado várias vezes.

O novo sistema funcionava bem, eu estava conseguindo ver novos vídeos do RezendeEvil antes de alguém conseguir comentar "first!" neles!

Versão v2.1 - Vários gostos, vários canais a serem anunciados

28/08/2017 - 04/09/2017 Pessoas querem anunciar vários canais do YouTube em seus servidores, já que muitas pessoas estavam criando servidores de vários YouTubers em um só servidor (exemplo: Tunados e o Driscord), fazendo que seja necessário que a Loritta anuncie novos vídeos de vários canais em um só servidor.

Enquanto não foi tão trabalhoso adicionar suporte a verificação de vários canais (na verdade o que foi mais difícil foi a parte do painel), outro problema iria surgir ao adicionar suporte a verificação de vários canais em um só servidor...

Versão v2.2 - Redesign do YouTube

04/09/2017 - 30/09/2017 YouTube tinha mudado o design dele, causando que a Loritta não conseguisse pegar o ID do canal... foi necessário mudar como é verificado o ID do canal, antes o que era apenas uma query no elemento que possuia o atributo data-channel-external-id agora foi alterado para um RegEx já que o ID do canal estava guardado dentro de um JavaScript Object... val pattern = Pattern.compile("\"key\":\"browse_id\",\"value\":\"([A-z0-9_-]+)\"")

Versão v2.3 - try ... catch sempre é útil!

30/09/2017 - 01/10/2017 Devido a um canal que estava dando problema ao verificar, vários outros canais que foram adicionados depois desse tal canal não estavam sendo verificados!

Ou seja, eu coloquei que a verificação de novos vídeos ficasse dentro de um try ... catch e corrigi o problema que estava afetando o tal canal.

Ao fazer isto, eu comecei a perceber que na verdade existiam VÁRIOS canais que não estavam sendo verificados e que agora a verificação de novos vídeos estava demorando mais (afinal, mais canais = mais tempo necessário para verificar todos os canais) e esta mudança também teve outra consequência...

Versão v2.4 - Tentativa de speed up!

01/10/2017 - 03/10/2017 Para tentar acelerar as verificações, eu fiz para que seja criado uma thread para cada canal verificado no YouTube, acelerando bastante a verificação de novos vídeos!

...e também causando um problema.

Versão v2.5 - YouTube API Key Rotation!

03/10/2017 - 23/11/2017 Agora que veio um dos problemas que eu tinha falado que iriam acontecer antes, pelo visto a API do YouTube possui rate limit (cotas)... ou seja, ao atingir o limite de acessos a API do dia, você teria que esperar até a meia noite do pacífico até poder fazer usar a API novamente...

Como a minha key que eu estava usando tinha sido criada em 2014, ela ainda tinha o limite de 500k requisições por dia, o que é considerado muito comparado com as keys geradas após mudarem o limite (50k por dia), o problema é que mesmo assim eu estava atingindo o limite...

Você pode achar "ah, mas 500k não é muito? Dá para usar isso dai sem nenhum problema!", até você pensar que...

  • Na época a Loritta verificava + ou - uns 1000 canais
  • Ela verificava todos os canais a cada 10 segundos
  • Duas das três verificações que eu faço usam a API do YouTube, ou seja, para verificar um novo vídeo eu tenho que fazer dois acessos a API do YouTube

Ou seja, eu utilizo 12000 (1000 * 6 * 2) a API do YouTube por minuto, 720000 vezes por hora e 17280000 vezes por dia! Muito mais do que a minha cota atual da minha key.

Ou seja, tive que ser criativo, criei um sistema de key rotation que funcionava assim:

  • A Loritta possui 5 keys do YouTube, uma delas é a antiga key (com 500k requests) e as outras 4 com 50k requests, isto já dá 700k requests diferentes que eu posso fazer com a Loritta!
  • Quando uma key chegava no limite de cotas, a Loritta considerava que aquela key está "inválida" e trocava para outra key da lista
  • Ao chegar a meia noite no pacífico (umas 3 horas da manhã), a Loritta automaticamente "desinvalidava" todas as keys que foram consideradas inválidas

Jeitinho brasileiro de corrigir o problema, mas pelo ou menos foi resolvido... até que eu realmente tive que mudar algumas coisas na verificação de vídeo para evitar que chegasse o limite tão rápido.

Versão v3.0 - Vamos verificar canais do YouTube, usando playlists!

23/11/2017 - 19/03/2018 Verificar vários canais de três maneiras diferentes não estava dando muito certo, muitas vezes a Loritta as vezes estava anunciando o novo vídeo, depois o vídeo velho, e depois o vídeo novo (e as vezes anunciando o novo vídeo duas vezes seguidas!), demorava mais para verificar e ainda usava a key do YouTube duas vezes seguidas só para verificar.

Também existia o problema que ela verificava o mesmo canal várias vezes caso vários servidores tivessem colocado o mesmo canal para ser verificado... que era uma grande perda de tempo já que a gente já tinha verificado aquele canal, para que verificar novamente?

Ou seja, tive que inovar... percebi que a página de uploads recentes (da playlist!) no YouTube atualizava bem rápido, mais rápido que a API! Ou seja, eu mudei para que funcionasse assim:

  • Pegar todos os IDs dos canais adicionados na Loritta
  • Verificar todos os canais baseando na lista
  • Pegar o ID da playlist de uploads recentes pela API do YouTube
  • Pegar a página de uploads recentes pelo website do YouTube
  • Caso tenha enviado um vídeo novo, pegue os servidores que colocaram para notificar os vídeos deste canal e avise no servidor!

E funcionava bem! É claro, teve algumas regressões pelo novo sistema...

  • Não era mais possível mostrar a descrição do vídeo na mensagem de novo vídeo
  • Não era mais possível comparar as datas, ou seja, ela só estava comparando o ID do último vídeo, causando problemas caso o canal deletasse o último vídeo enviado, já que iria avisar o penúltimo vídeo enviado.

Mas mesmo assim, funcionava BEM melhor que o antigo sistema!

Versão v4.0 - YouTubeVideoRelayClient

19/03/2018 - 14/06/2018 O antigo sistema estava funcionando muito bem... até que muitas pessoas começaram a usar a Loritta e terem colocado para ela anunciar novos vídeos do canal... o que era praticamente instantâneo estava levando quase 8 minutos para anunciar novos vídeos de canais do YouTube! O que é inaceitável já que se continuasse assim era melhor usar outros jeitos para verificar novos vídeos de canais do que usar a Loritta.

Então era hora de inovar, como eu poderia fazer um sistema melhor que o atual? Um dos maiores problemas que eu tinha encontrado no sistema atual é que ele não ligava se o canal enviava vídeos toda hora ou se o canal era inativo a mais de 300 dias, ela iria continuar a verificar todos os canais toda hora instantaneamente, causando delays já que quanto mais canais = mais demora para verificar.

Então para o YouTubeVideoRelayClient eu decidi verificar de outro jeito: Originalmente eu estava verificando usando a página do canal do YouTube mas existia um problema nisto:

  • Alguns canais estavam falhando para serem verificados
  • Como sempre, o YouTube DEMORAVA para anunciar novos vídeos lá

E mesmo assim, nos meus testes eu tinha percebido que estava demorando MUITO tempo para carregar todos os ~4000 canais da Loritta nele (uns 20 minutos!), o que é inaceitável.

Enquanto estava programando o YouTubeVideoRelayClient eu estava vendo o vídeo do CoreDasAntigas sobre desmonetização de canais e ele tinha citado o Social Blade no vídeo, então eu resolvi dar umas olhadas no Social Blade e descobri que ele mostrava os vídeos recentes do canal lá! Perfeito para o que eu queria! (mesmo que não tenha nenhuma relação com o vídeo do Core)

Usei o meu querido Firefox na aba de "Conexões" para descobrir como o Social Blade usava a API (não pública 👀) deles para pegar os vídeos recentes e usei no YouTubeVideoRelayClient e... deu certo!

Implementei um sistema de "delay" para cada canal que funciona assim:

  • Se o canal enviou um vídeo em menos de 3 dias, verifique o canal TODA HORA
  • Caso seja mais de 3 dias, adicione um delay na verificação dependendo de quantos dias fazem desde o último vídeo enviado
  • Caso o canal não tenha enviado um vídeo a mais de 9 dias, verifique o canal a cada 15 minutos
  • Caso o canal não tenha vídeos, verifique a cada uma hora

...mas ainda tinha o problema que demorava MUITO para adicionar todos os 4000 canais no YouTubeVideoRelayClient... então decidi fazer a mesma coisa que o Discord faz para fazer "resource balancing"... shards!

Para quem não sabe, fazer "sharding" é separar os recursos em instancias diferentes, ou seja, em vez de processar tudo em apenas uma instância, eu posso usar várias instâncias para separar todos os canais, originalmente eu pensava que o bottleneck era a conexão mesmo, mas pelo visto ao fazer sharding o tempo para adicionar todos os 4000 canais diminuiu de 20 minutos para apenas 5 minutos! Bem mais aceitável que antes.

Eu estou atualmente rodando quatro shards do YouTubeVideoRelayClient na Loritta (separando os canais assim Math.abs(it.hashCode()) % 4 == 0/1/2/3) e tudo é enviado e recebido via sockets!

E agora, finalmente, os vídeos do RezendeEvil estão sendo anunciados rapidamente novamente. :3

Vídeo novo do nosso querido Rezendão, anunciado pela Loritta

Lembrando que o YouTubeVideoRelayClient é de código-aberto e você pode ver tudo que ele faz! (E até modificar ele ao seu gosto, desde que você deixe os créditos)

O sistema do YouTubeVideoRelayClient funciona muito bem e eu espero que o Social Blade não faça a mesma coisa que um certo bichinho amarelo fez comigo...

Power do Futuro chegou com más notícias, e com uma solução! - Push via PubSubhubbub

14/06/2018 - Hoje

É, o Social Blade resolveu dar uma de Simsimi e bloquear o método que eu estava usando, e agora?

Bem, eu encontrei uma luz no final do túnel, que é o sistema que a Loritta utiliza até hoje e que funciona extremamente bem!

A API do YouTube permite você se inscrever para receber push notifications quando um canal envia um novo vídeo! A documentação dele está aqui.

É um sistema extremamente mais simples e muito melhor que as outras tentativas que eu realizei, sendo a única desvantagem o requerimento de ficar registrando as webhooks após X dias, já que elas expiram.

Como funciona? Simples, você pede para o YouTube "hey YouTube me manda as notificações do canal xyz para mim aqui nessa URL ok vlw te amo", você responde um request do YouTube confirmando que você realmente criou o pedido e depois é só sentar e relaxar e ver as notificações push sendo enviadas para a sua URL desejada!

É muito mais simples, usa menos recursos (já que você não precisa ficar verificando várias vezes perguntando "já saiu novo vídeo??") e nunca deu problema! Se você está querendo fazer um sistema similar, recomendo usar as push notifications do YouTube.

E é essa foi a história sobre como eu criei o sistema de verificar novos vídeos do YouTube da Loritta!