[Source] YouTube - Obtendo URL para download de Vídeos

Started by Dark_Side, 07 de October , 2006, 10:10:38 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Dark_Side

Hi,
Estive dando uma olhada no sistema de identificação dos vídeos do YouTube e fiz um simples programa que retorna a URL de download para o respectivo vídeo.

Fiz o programa em duas linguagens: C e Perl.
Para usar o programa, basta abri-lo e fornecer a URL do vídeo, exemplo:

>> Digite o URL do video:
http://www.youtube.com/watch?v=xxxxxxx

Os vídeos do YouTube estão no formato .FLV (flash). Ao baixar o arquivo pela URL que o programa retornar, devemos realizar alguns procedimentos.

1) Pode-se obter um programa que execute tal formato, por exemplo o Riva FLV PLayer, que pode ser obtido em: http://baixaki.ig.com.br/site/detail36725.htm

2) No Linux, pode-se converter o arquivo FLV para MPEG, permitindo que o vídeo seja executado em um player comum.
Para mais informações sobre a conversão:
http://br-linux.org/linux/node/4909


Pois bem, primeiramente o código em C:

youtube.c


// Headers comuns
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifdef WIN32 // Se a plataforma for windows
#include <winsock.h> // Inclui header do winsock
WSADATA data;  // WSADATA -> inicializar socket
SOCKET sock; // socket

#else //Caso contrário

// Headers para o uso de sockets no Linux
#include <unistd.h>
#include <sys/sockets.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
int sock; // socket
#endif

// Estruturas comuns -> configuração do socket e resolver DNS
struct sockaddr_in addr;
struct hostent * host = NULL;

#define YOUTUBE_IP "208.65.153.241" // IP do servidor


void encerra() // Função para fechar sockets
{
     #ifdef WIN32     // Finaliza sockets no windows
     closesocket(sock);
     WSACleanup();
     #else // Finaliza sockets no linux
     close(sock);
     #endif

 }
void erro(const char * msg) // Mostra msg de erro e encerra
{
     printf("%s",msg);
     encerra();
     exit(1);
}

void cria_sock(const char* IP) // Tenta criar socket e conectar no IP definido
{
   if((sock = socket(AF_INET,SOCK_STREAM,0))==SOCKET_ERROR) // Tenta criar socket
    erro("Erro ao criar socket socket");
   
   
    // Configura o socket para conectar na porta 80 do IP
    addr.sin_family = AF_INET;
    addr.sin_port = htons(80);
    addr.sin_addr.s_addr = inet_addr(IP);
   
    // Tenta se conectar
    if(connect(sock,(struct sockaddr*)&addr,sizeof(addr))==SOCKET_ERROR)
    erro("Erro ao se conectar...");

}

int main()
{
 
 // Limpa a tela
 #ifdef WIN32
 system("cls");
 #else
 system("clear");
 #endif

 puts(">> Digite a url do video: ");
 
    char url[0x40]; // Obtém url do vídeo
    fgets(url,0x40,stdin);
    url[strlen(url)-1]='\0';

    char * tok = strstr(url,"youtube.com/watch?v="); // Verifica validade da URL
    if(tok == NULL)
    erro("Url invalida!");
   
    char video_id[0x20]; // Obtém ID do vídeo
    snprintf(video_id,0x20,"%s",tok+20);
 
    #ifdef WIN32 // Tenta inicializar winsock no windows
    if(WSAStartup(0x101,&data)==-1)
    erro("Erro ao inicializar Winsock.");
    #endif
   
    cria_sock(YOUTUBE_IP); // Tenta criar socket e conectar-se ao YouTube
       
    int size = 50 + strlen(video_id);
   
    char *req = (char*)malloc(size);
    if(req == NULL)
    erro("Erro ao alocar espaco..");
   
    // Faz requisição HTTP para obter o vídeo
   
    /*
    GET watch?v=ID_DO_VIDEO HTTP/1.1
    Host: www.youtube.com
   
    */
   
    snprintf(req,size,"GET /watch?v=%s HTTP/1.1\r\nHost: www.youtube.com\r\n\r\n",video_id);
    send(sock,req,strlen(req),0);
    free(req);
    puts("Procurando pelo video...");

    tok = NULL; // Zera o ponteiro para utilizá-lo posterioremente no While Loop
    char buffer[0x800]; // Buffer para receber dados
 
    // Obtém headers
    recv(sock,buffer,0x800,0);

    // Verifica se houve um redirecionamento -> vídeo inválido
    if(strstr(buffer,"HTTP/1.1 303")!= NULL)
 erro("O video especificado parece nao existir.");

    while(tok == NULL) // Recebe a resposta até que a URL do vídeo seja encontrada
    {
                memset(buffer,0x0,0x800); // Limpa o buffer
                recv(sock,buffer,0x800,0);
                tok  = strstr(buffer,"player2.swf"); // Separa a URL do vídeo
    }
   
closesocket(sock); // Fecha socket
cria_sock(YOUTUBE_IP); // Reconecta

tok = strtok(tok,"\""); // Tenta formatar a URL
 if(tok == NULL)
 erro("Erro ao obter URL do video...");
 
puts("Obtendo URL do video...");
         
char video_url[0x60];
snprintf(video_url,0x60,"%s",tok+12); // Escreve a URL formatada no buffer

size = 60 + strlen(video_url);
req = (char*)malloc(size);
    if(req == NULL)
    erro("Erro ao alocar espaco..");

/* Faz outra requisição:
       
       GET /get_video?video_id=ID_DO_VIDEO&headers=.... HTTP/1.1
       host: www.youtube.com
 
*/
     
snprintf(req,size,"GET /get_video?%s HTTP/1.1\r\nHost: www.youtube.com\r\n\r\n",video_url);
send(sock,req,strlen(req),0);
free(req);

int bytes = 1;

memset(buffer,0x0,0x800);
bytes = recv(sock,buffer,0x800,0); // Obtém headers

tok = strtok(strstr(buffer,"Location: "),"\r"); // Tenta obter URL de redirecionamento -> DOWNLOAD

if(tok == NULL)
 erro("Erro ao obter URL de Download.");
 
 memset(video_url,0x0,0x60);
 snprintf(video_url,0x60,"%s",tok+10); // Escreve no buffer a URL

 // Limpa a tela
 #ifdef WIN32
 system("cls");
 #else
 system("clear");
 #endif
 
printf("Download do video:\n%s\n",video_url);
encerra(); // Finaliza
 
    return 0;
}



Perl:

youtube.pl

use LWP::UserAgent; # Requisições HTTP

# Obtém URL do vídeo
print ">> Digite o URL do video:\n";
my $url = <stdin>;
chomp $url;

if(substr($url,0,7) ne "http://"){ # Inclui HTTP:// antes da url se necessário
$url = "http://$url";}
lc $url; # Conversão para minúsculas

if($url !~ /youtube.com\/watch\?v=/) # Verifica se a URL é válida
{

print "URL invalida!";
exit;
}

print "Procurando pelo video...\n";

my $useragent = LWP::UserAgent->new;
my $resp = $useragent->get($url); # Tenta obter o conteúdo da página

if($resp->is_error)  # Em caso de erro
{
print "Ocorreu um erro ao fazer a requisicao.";
exit;
}

# Obtém a URL de onde o vídeo é exibido:
# www.youtube.com/player2.swf?URL_DO_VIDEO
# o programa irá obter apenas a URL_DO_VIDEO
# é necessário enviar uma requisição para www.youtube.com/get_video?URL_DO_VIDEO

my $redir = $resp->as_string;
$redir =~ m/player2.swf\?(.*?)\"/;


# Evita redirecionamento
sub LWP::UserAgent::redirect_ok { return 0;}

print "Obtendo URL de Download...\n";

# Formata a URL para fazer a requisição
$url = "http://www.youtube.com/get_video?$1";
my $useragent = LWP::UserAgent->new;
$resp = $useragent->head($url); # Tenta obter os headers

if($resp->is_error)  # Em caso de erro
{
print "Erro ao obter URL de Download";
exit;
}


my $download = $resp->header("Location"); # Obtém o header de redirecionamento -> URL do vídeo

print "\nDownload do video:\n $download\n"; # Mostra o endereço

Por um problema de compatibilidade do meu modem com o Linux, não pude realizar testes no Linux. Se possível, gostaria que reportassem os possíveis erros lolz :)

Brigado hein...

Bye.

Dark_Side

Hi,
Lolz... Me xingaram por ter feito os programas no modo console e até me ameacaram de morte hahuauha, zuando :)

Sladrak

Se vc pudesse comentar o codigo do vb seria de grande ajuda.

Dei uma olhada no projeto mas ja faz um tempim q nao mexia no vb,
com seus comentarios creio que seja de + facil o entendimento...

Flw

Anonymous

e aí blz :)

fiquei com uma duvida

o que essa linha faz

video_url = Mid(url.Text, InStr(1, url.Text, "youtube.com") + 11)

??

em C o equivalente seria essa parte ne?

snprintf(video_url,0x60,"%s",tok+12)

onde tok nesse caso (pelo q entendi seria a id do video)

e pq vc usa hexadecimais, humm, 0x20 seria 32 n eh?

huahuaa flw eh isso :P

vuln

po.. parabens :). Um programa de exelente utilidade. Tudo bem que ja existe um site que faz todo o servico.. keepmind.com algo assim, sei la. Bem, mesmo assim parabens.!

Ate mais.
"O amor por princípio, a Ordem por base, o progresso por objetivo."

Dark_Side

Quote from: "dudeabot"e aí blz :)

fiquei com uma duvida

o que essa linha faz

video_url = Mid(url.Text, InStr(1, url.Text, "youtube.com") + 11)

??

em C o equivalente seria essa parte ne?

snprintf(video_url,0x60,"%s",tok+12)

onde tok nesse caso (pelo q entendi seria a id do video)

e pq vc usa hexadecimais, humm, 0x20 seria 32 n eh?

huahuaa flw eh isso :)

Dark_Side

Hi,

Segue o código em VB, versão copy and paste, lolz:

' Função da API para executar comandos -> no programa: abrir URL
Private Declare Function ShellExecute Lib "shell32.dll" Alias "ShellExecuteA" (ByVal hwnd As Long, ByVal lpOperation As String, ByVal lpFile As String, ByVal lpParameters As String, ByVal lpDirectory As String, ByVal nShowCmd As Long) As Long

Dim init As Boolean 'Validar -> conectar e obter url
Dim verif As Boolean ' Validar -> URL digitada
Dim redir As String ' URL de redirecionamento
Dim video_url As String 'URL do vídeo
Dim download_url As String  'URL para download
Dim data As String 'Buffer para receber dados do socket

Private Sub Form_Load()
' Estado inicial -> aguardando
init = True
verif = False
End Sub

Private Sub go_Click()
'Verifica se há dados digitados
If Len(url.Text) = 0 Then
MsgBox "Digite o endereço do Vídeo", vbCritical, "..."
Exit Sub
End If

'Verifica se a URL contém formatado válido
If InStr(1, url.Text, "youtube.com/watch?v=") = 0 Then
MsgBox "URL inválida!", vbCritical, "..."
Exit Sub
End If

'Tenta se conectar no youtube :)
sock.Connect "www.youtube.com", 80
Call disab  'Função -> disabilitar campos
End Sub

Private Sub sock_Connect() 'Ao conectar

Select Case init 'Verifica estado
Case True 'Se for a primeira conexão, diretamente em youtube.com

'Obtém URL de identificação do vídeo: "watch?v=XXXX"
video_url = Mid(url.Text, InStr(1, url.Text, "youtube.com") + 11)


'Envia requisição:

' GET URL_IDENTIFICAO HTTP/1.1
' host: www.youtube.com

'
sock.SendData "GET " + video_url + " HTTP/1.1" & vbCrLf & "Host: www.youtube.com" & vbCrLf & vbCrLf

Case Else 'Se não for primeira conexão -> obter URL de  redirecionamento
'Envia outra requisição -> obter url de download:

' GET /get_video?REDIRECIONAMENTO HTTP/1.1
' host: www.youtube.com

sock.SendData "GET /get_video?" + redir + " HTTP/1.1" & vbCrLf & "Host: www.youtube.com" & vbCrLf & vbCrLf
End Select

End Sub

Private Sub sock_DataArrival(ByVal bytesTotal As Long) 'Ao receber resposta

'Recebe dados -> armazena no buffer "data"
sock.GetData data

Select Case init
Case True 'Se for a primeira conexão

If verificar = False Then 'Verifica se o vídeo foi encontrado -> Função
MsgBox "O video especificado para não existir!", vbExclamation, "..."
sock.Close 'Fecha o socket
Call hab 'Reabilita campos
Exit Sub 'Encerra
End If

'Verifca por "player2.swf?" na resposta da requisição.
'Exemplo: player2.swf?video_id=xxxxx&ssss=xxxx",...

If InStr(1, data, "player2.swf?") Then
redir = Mid(data, InStr(1, data, "player2.swf?") + 12) 'Retorna a string formada depois de "player2.swf?"

'Retorna a substring após "player2.swf?" retirando aspas "
'Ex: player2.swf?xxx=xxx&aaa=",... -> player2.swf?xxx=xxx&aaa=
redir = Mid(redir, 1, InStr(1, redir, Chr(34)) - 1)

init = False 'init = false -> na próxima conexão o programa irá executar as outras instruções abaixo
sock.Close 'Fecha socket
sock.Connect "www.youtube.com", 80 'Reconecta-se
End If

Case Else 'Se não for a primeira conexão
sock.Close 'Certifica-se que o socket foi fechado

'Obtém URL de download do header: "Location: URL_REDIR" -> "URL_REDIR"
download_url = Mid(data, InStr(1, data, "Location: ") + 10)

'Retira quebra de linha
download_url = Mid(download_url, 1, InStr(1, download_url, vbCrLf))
MsgBox "Pronto para download... Pressione OK para continuar...", vbInformation, "lolz"

'Abre a URL obtida no navegador
ShellExecute 0, "open", download_url, 0, 0, 0
Call hab 'Reabilita campos
init = True 'Como a segunda conexão foi feita com sucesso, para que se possa obter outros vídeos -> init=true -> primeiras instruções novamente
Exit Sub 'Encerra
End Select
End Sub

Private Sub sock_Error(ByVal Number As Integer, Description As String, ByVal Scode As Long, ByVal Source As String, ByVal HelpFile As String, ByVal HelpContext As Long, CancelDisplay As Boolean)
'Erro
MsgBox "Erro ao se conectar!", vbCritical, "..."
sock.Close 'Fecha socket

'Volta ao estado inicial
init = True
verif = False
Call hab 'Reabilita campos
End Sub

Sub hab() 'Torna habilitados: TextBox e o botão OK
url.Enabled = True
go.Enabled = True
End Sub

Sub disab() 'Torna disabilitados: TextBox e o botão OK
url.Enabled = False
go.Enabled = False
End Sub

Function verificar() As Boolean
If verif = True Then verificar = True 'Se já ouve a verificação encerra

If InStr(1, data, "HTTP/1.1 303") Then 'Verifica se foi retornado o código 303 -> redirecionamento
'Redirecionamento = vídoe não encontrado
verificar = False 'Retorna false -> vídeo não encontrado
Else
verificar = True 'Se não houver código 303 -> vídeo encontrado
verif = True 'Define que já houve a verificação
End If
End Function

Anonymous

no código C não tá faltando uma função para ele baixar o video n? pq parece q ele so vai ate o ponto de pegar a url

vlw

Dark_Side

Hi,
Lolz, é porque quando eu escrevi o código, eu ainda não tive a idéia de fazer com que o download iniciasse automaticamente. A idéia surgiu quando estava escrevendo o código no Visual Basic.

Pode-se entretanto, adicionar a seguinte linha:

...
#ifdef WIN32 // Para windows
 size = strlen(video_url) + 7;
 char cmd[size];
 snprintf(cmd,size,"start %s",video_url); // Executa comando: start URL_VIDEO -> abre navegador
 system("cmd");

#else // Linux

 size = strlen(video_url) + 6;
 char cmd[size];
 snprintf(cmd,size,"wget %s",video_url); // comando wget URL -> baixa o vídeo
 system("cmd");

#endif

Bye :)

Dark_Side

Hi,
pff, nem posso editar :(

O correto seria: system(cmd) e não system("cmd");  =\

Bye...

insanity


Anonymous

eita já virou .pl? lol

para acessar o IE (q eh padrao no win32)

    char teste[100];
    sprintf(teste,"IEXPLORE %s", url_video);
    cmd(teste);

t+

Anonymous

Quote from: "dudeabot"eita já virou .pl? lol

para acessar o IE (q eh padrao no win32)

    char teste[100];
    sprintf(teste,"IEXPLORE %s", url_video);
    cmd(teste);

t+

ops, C não é java  ::)

    sprintf(teste,"C:/Arquiv~1/Intern~1/IEXPLORE.EXE %s", "google.com");
    system(teste);
agora sim..

vuln

Aqui o arquivo em Perl (.pl) deu alguns erros. :( Linha 3 e 7.
"O amor por princípio, a Ordem por base, o progresso por objetivo."