Script Em Python Para Baixar Legendas do Youtube

Introdução

Na referência [1] eu mostrei como é possível obter as legendas de vídeos do youtube de forma manual. Ficou faltando um script como uma prova de conceito, porém, hoje, postarei um script em python que baixa legendas de vídeos do youtube.

O código

Primeiro o código:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# [XML2SRT.py]
# Módulo que realiza o download e conversão de legendas
# do youtube.
#
# [Autor]
# Marcos Paulo Ferreira (Daemonio)
# undefinido at gmail com
# https://daemoniolabs.wordpress.com
# 
# Versão 1.0 by daemonio @ Thu Aug  1 20:00:06 BRT 2013
#
 
import urllib2
from xml.dom import minidom
import xml.parsers.expat
import HTMLParser

class URLNotFound(Exception):
    pass

class XMLError(Exception):
    pass

class XML2SRT():
    def __init__(self, idvideo):
        self.idvideo = idvideo

    def getList(self):
        """
        Obtém a lista de legendas disponíveis
        """
        url = 'http://video.google.com/timedtext?type=list&v='+self.idvideo

        # Carrega a URL
        try:
            source = urllib2.urlopen(url).read()
        except urllib2.HTTPError:
            raise URLNotFound('Cant load URL: '+url)

        # Carrega o XML
        try:
            xmlDoc = minidom.parseString(source)
        except xml.parsers.expat.ExpatError:
            raise XMLError('Cant parser XML file.')

        # Monta a lista
        sublist=[]
        for x in xmlDoc.getElementsByTagName('track'):
            lang_t=x.getAttribute('lang_translated')
            name=x.getAttribute('name')
            lang_code=x.getAttribute('lang_code')
            sublist.append([lang_t, name, lang_code])

        return sublist

    def tempo_subrip(self, xtime):
        """
        Converte um tempo em segundos no formato
        de tempo SubRip
        """

        subtime=[]
        timetxt=''

        if '.' not in xtime: xtime+='.000'

        SEC,MILI=xtime.split('.')
        SEC=int(SEC)

        while len(MILI) < 3:
            MILI=MILI+'0'

        subtime.append(str(SEC/3600))
        subtime.append(str((SEC%3600)/60))
        subtime.append(str((SEC%3600)%60))

        for i in range(3):
            if 1 == len(subtime[i]):
                subtime[i]='0'+subtime[i]

        i=':'.join(subtime)+','+MILI
        return i.encode('utf-8')

    def getSub(self, lang_code, name):
        """
        Retorna a legenda indicada pelos parâmetros
        lang_code e name. A legenda é retornada de
        forma completa como uma string.
        """

        name=urllib2.quote(name)
        url = 'http://video.google.com/timedtext?type=track&v='+self.idvideo
        url = url + '&lang='+lang_code+'&name='+name

        try:
            source = urllib2.urlopen(url).read()
        except urllib2.HTTPError:
            raise URLNotFound('Cant load URL: '+url)

        try:
            xmlDoc = minidom.parseString(source)
        except xml.parsers.expat.ExpatError:
            raise XMLError('Cant parser XML file.')

        captionsList = xmlDoc.getElementsByTagName('text') ;

        srtext=''
        for id, x in enumerate(captionsList, 1):
            try:
                caption = x.firstChild.data 
            except AttributeError:
                continue

            # Atributos de tempos. Algumas legendas nao tem 'dur'
            # e isso gera a exceção ValueError.
            start=float(x.getAttribute('start'))
            try:
                dur=float(x.getAttribute('dur'))
            except ValueError:
                dur=0

            end=start+dur

            srtext += str(id) + '\n'
            srtext += self.tempo_subrip(str(start)) + ' --> ' + self.tempo_subrip(str(end)) + '\n'
            srtext += HTMLParser.HTMLParser().unescape(caption).encode('utf-8') + '\n'
            srtext += '\n'

        return srtext[:-1]

if __name__ == '__main__':
    import sys

    argc = len(sys.argv)

    if argc < 3:
        print '[uso]',sys.argv[0],'<codigo video> <arquivo saida>'
        sys.exit(-1)

    # Lê os parâmetros
    idvideo = sys.argv[1]
    outputfile = sys.argv[2]

    # Cria a instância
    subobj = XML2SRT(idvideo)

    try:
        # Lista de legendas
        sublist = subobj.getList()
    except URLNotFound:
        print 'Erro: Código inválido.'
        sys.exit(-1)
    except XMLError:
        print 'Erro: Vídeo sem legenda.'
        sys.exit(-1)

    # Monta um menu de escolha
    print 'Selecione o idioma (-1 = sair)'
    l = len(sublist)
    for c, [label, name, idlang] in enumerate(sublist):
        print '[',c,']',label

    # Lê a opção
    opt=int(raw_input('>> '))

    # Recupera os atributos da opção digitada
    # e escreve a legenda no arquivo passado.
    if opt >= 0 and opt < len(sublist):
        try:
            filefd=open(outputfile, 'w')
        except:
            print 'Erro: Impossível criar arquivo.'
            sys.exit(-1)
        else:
            label, name, idlang = sublist[opt]
            filefd.write(subobj.getSub(idlang, name))
        finally:
            filefd.close()

salve como XML2SRT.py

Exemplos

Baixado o script, transforme-o em executável:

$ chmod +x XML2SRT.py

Em seguida, execute-o:

$ ./XML2SRT.py
[uso] ./XML2SRT.py <codigo video> <arquivo saida>

Devemos passar o código do vídeo no primeiro parâmetro e o arquivo de saída (que conterá a legenda) no segundo. Utilizarei o vídeo exemplo de [1] para teste:

$ ./XML2SRT.py kGYACultjCY legenda_portugues.srt
Selecione o idioma (-1 = sair)
[ 0 ] Czech
[ 1 ] Dutch
[ 2 ] English
[ 3 ] French
[ 4 ] German
[ 5 ] Hebrew
[ 6 ] Italian
[ 7 ] Japanese
[ 8 ] Polish
[ 9 ] Portuguese
[ 10 ] Spanish
[ 11 ] Swedish
>> 9

O script apresenta em forma de menu todas as legendas disponíveis para o vídeo e, com isso, basta selecionar o número do idioma desejado e apertar enter. No exemplo acima, a legenda em português foi gravada no arquivo legenda_portugues.srt:

$ head -n 15 legenda_portugues.srt
1
00:00:00,880 --> 00:00:02,680
RIDLEY SCOTT EM A VIDA EM UM DIA

2
00:00:03,080 --> 00:00:06,680
Deveria ser pessoal. Deve ser pessoal. É isso que estamos procurando.

3
00:00:07,160 --> 00:00:12,000
Na verdade, o que importa é o que agrada você como autor.

4
00:00:12,680 --> 00:00:14,160
O primeiro filme que eu fiz foi um dia na minha vida.

Agora só baixar o vídeo e usar a legenda :-D

Conclusão

Esse é um dos meus primeiros scripts em Python e por isso, se encontrarem algum erro ou até mesmo dica de implementação, podem falar comigo. Ah, existem outros scripts com o nome XML2SRT, porém decidi deixar assim mesmo porque todos eles, ao meu ver, são scripts pessoais e pouco divulgados. Acredito que não tenha problema algum :-o

Referências

[1] Download e Conversão de Legendas Do Youtube by Daemonio (Acessado em: Agosto/2013)
https://daemoniolabs.wordpress.com/2012/11/21/download-e-conversao-de-legendas-do-youtube/

Deixe um comentário