Tengo un archivo srt llamado subtitles.srt que no está en inglés y seguí las instrucciones de la documentación y el código fuente del paquete moviepy (https://moviepy.readthedocs.io/en/latest/_modules/moviepy/video/tools/subtitles.html ):

from moviepy.video.tools.subtitles import SubtitlesClip
from moviepy.video.io.VideoFileClip import VideoFileClip
generator = lambda txt: TextClip(txt, font='Georgia-Regular', fontsize=24, color='white')
sub = SubtitlesClip("subtitles.srt", generator, encoding='utf-8')

Y esto da el error TypeError: __init__() got an unexpected keyword argument 'encoding'.

En el código fuente, la clase SubtitlesClip tiene un argumento de palabra clave encoding. ¿Eso significa que la versión del código fuente está desactualizada o algo así? ¿Y qué puedo hacer al respecto? Incluso intenté copiar el código fuente de moviepy.video.tools.subtitles con el argumento de la palabra clave encoding directamente a mi código, sin embargo, generó más errores como en la línea:

from moviepy.decorators import convert_path_to_string

No pudo importar el decorador convert_path_to_string.

El código fuente no parece estar de acuerdo con lo que he instalado. ¿Alguna manera de arreglarlo? Si no es así, ¿existen buenas alternativas de las bibliotecas de Python para insertar subtítulos o editar videos en general?

Editar: Mi solución actual es crear una clase secundaria de SubtitlesClip y anular el constructor de la clase secundaria:

from moviepy.video.tools.subtitles import SubtitlesClip
from moviepy.video.VideoClip import TextClip, VideoClip
from moviepy.video.compositing.CompositeVideoClip import CompositeVideoClip
import re



from moviepy.tools import cvsecs

def file_to_subtitles_with_encoding(filename):
    """ Converts a srt file into subtitles.

    The returned list is of the form ``[((ta,tb),'some text'),...]``
    and can be fed to SubtitlesClip.

    Only works for '.srt' format for the moment.
    """
    times_texts = []
    current_times = None
    current_text = ""
    with open(filename,'r',encoding='utf-8') as f:
        for line in f:
            times = re.findall("([0-9]*:[0-9]*:[0-9]*,[0-9]*)", line)
            if times:
                current_times = [cvsecs(t) for t in times]
            elif line.strip() == '':
                times_texts.append((current_times, current_text.strip('\n')))
                current_times, current_text = None, ""
            elif current_times:
                current_text += line
    return times_texts


class SubtitlesClipUTF8(SubtitlesClip):
    def __init__(self, subtitles, make_textclip=None):
        
        VideoClip.__init__(self, has_constant_size=False)

        if isinstance(subtitles, str):
            subtitles = file_to_subtitles_with_encoding(subtitles)

        #subtitles = [(map(cvsecs, tt),txt) for tt, txt in subtitles]
        self.subtitles = subtitles
        self.textclips = dict()

        if make_textclip is None:
            make_textclip = lambda txt: TextClip(txt, font='Georgia-Bold',
                                        fontsize=24, color='white',
                                        stroke_color='black', stroke_width=0.5)

        self.make_textclip = make_textclip
        self.start=0
        self.duration = max([tb for ((ta,tb), txt) in self.subtitles])
        self.end=self.duration
        
        def add_textclip_if_none(t):
            """ Will generate a textclip if it hasn't been generated asked
            to generate it yet. If there is no subtitle to show at t, return
            false. """
            sub =[((ta,tb),txt) for ((ta,tb),txt) in self.textclips.keys()
                   if (ta<=t<tb)]
            if not sub:
                sub = [((ta,tb),txt) for ((ta,tb),txt) in self.subtitles if
                       (ta<=t<tb)]
                if not sub:
                    return False
            sub = sub[0]
            if sub not in self.textclips.keys():
                self.textclips[sub] = self.make_textclip(sub[1])

            return sub

        def make_frame(t):
            sub = add_textclip_if_none(t)
            return (self.textclips[sub].get_frame(t) if sub
                    else np.array([[[0,0,0]]]))

        def make_mask_frame(t):
            sub = add_textclip_if_none(t)
            return (self.textclips[sub].mask.get_frame(t) if sub
                    else np.array([[0]]))
        
        self.make_frame = make_frame
        hasmask = bool(self.make_textclip('T').mask)
        self.mask = VideoClip(make_mask_frame, ismask=True) if hasmask else None

De hecho, solo cambié dos líneas, pero tengo que crear una nueva clase y redefinir todo, así que dudo que sea realmente necesario. ¿Alguna solución mejor que esta?

1
Sato 12 mar. 2021 a las 17:10

1 respuesta

La mejor respuesta

La versión latest en la documentación (la que está viendo) corresponde a una versión de desarrollo 2.x, que aún no se ha lanzado a PyPI. La versión que ha instalado a través de pip es probablemente la 1.0.3, que es la última en PyPI, y no permite un parámetro encoding.

Desde el PR donde se introdujo la función, puede ver que solo se ha etiquetado para lanzamiento en versiones 2.x.

Es muy probable que copiar solo ese archivo a su código fuente no funcione, porque dependerá de los cambios que ocurrieron entre las dos versiones. Sin embargo, si se siente aventurero, puede instalar la versión dev del paquete, siguiendo la sección Método a mano en documentos.

1
Alessandro Cosentino 13 mar. 2021 a las 11:13