├── requirements.txt ├── CHANGES.md ├── setup.cfg ├── AUTHORS.md ├── examples ├── merkel │ ├── make.sh │ ├── merkel_remix.txt │ ├── Angela Merkel Speaking English to British Parliament-cGZWR5S1lCo.txt │ └── merkel_remix.json ├── macri_2 │ ├── make.sh │ ├── remix.txt │ └── fantochadas.txt ├── macron │ ├── macron_remix.txt │ ├── make.sh │ └── Présidentielle 2017 - Macron assure qu'il oeuvrera à 'retisser les liens entre l'Europe et les citoyens'-r0vpsx.txt ├── fort │ ├── remix.txt │ ├── make.sh │ └── Puroshow.com - El discurso de Fort-bra9kqtU7vk.txt ├── macri_1 │ ├── make.sh │ ├── macri_remix.txt │ └── El presidente Mauricio Macri inauguró el nuevo Centro de Trasbordo Constitución-GynDJC845Go.txt └── lo_que_tu_quieras_oir │ ├── make.sh │ ├── remix_de_sofia.txt │ └── mensaje_original.txt ├── MANIFEST.in ├── docs ├── index.txt ├── make.bat ├── Makefile └── conf.py ├── .gitignore ├── LICENSE ├── setup.py ├── Makefile ├── README.rst ├── CONTRIBUTING.md └── miau.py /requirements.txt: -------------------------------------------------------------------------------- 1 | docopt>=0.6.1 2 | moviepy>=0.2 3 | aeneas>=1.7.3 4 | langdetect -------------------------------------------------------------------------------- /CHANGES.md: -------------------------------------------------------------------------------- 1 | ## ChangeLog 2 | 3 | Version 0.1 4 | ----------- 5 | 6 | - First public version -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | # https://packaging.python.org/en/latest/distributing.html#wheels 2 | [bdist_wheel] 3 | universal = 1 4 | -------------------------------------------------------------------------------- /AUTHORS.md: -------------------------------------------------------------------------------- 1 | ## Credits 2 | 3 | #### Development Lead 4 | 5 | * Martín Gaitán 6 | 7 | #### Contributors 8 | -------------------------------------------------------------------------------- /examples/merkel/make.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/sh 2 | youtube-dl https://www.youtube.com/watch?v=cGZWR5S1lCo -f 43 3 | miau Angela\ Merkel* -r merkel_remix.txt --dump=merkel_remix.json -------------------------------------------------------------------------------- /examples/merkel/merkel_remix.txt: -------------------------------------------------------------------------------- 1 | I will deliver the clear and simple message+++ 2 | the rest of Europe is not prepared- 3 | I'm afraid they+ 4 | are very special++++ 5 | or so I have--- 6 | -------------------------------------------------------------------------------- /examples/macri_2/make.sh: -------------------------------------------------------------------------------- 1 | youtube-dl -o fantochadas.mp4 -f mp4 https://www.youtube.com/watch?v=iDELytzyBsc --external-downloader ffmpeg --external-downloader-args '-t 313' 2 | miau fantochadas.* -r remix.txt 3 | -------------------------------------------------------------------------------- /examples/macron/macron_remix.txt: -------------------------------------------------------------------------------- 1 | notre continent. 2 | notre manière de vivre++ 3 | une longue confrontation démocratique 4 | et de lutte++ 5 | Françaises, Français 6 | D’autres sont des menaces, comme le terrorisme. 7 | Vive la République ! Vive la France ! -------------------------------------------------------------------------------- /examples/fort/remix.txt: -------------------------------------------------------------------------------- 1 | no debe ser fácil para algunos asimilar++++ 2 | soy la demostración que hay una vida mejor 3 | en mi ausencia 4 | No dejan de hablar de mí 5 | Porque no tiene nada de malo ser hijo de un millonario 6 | yo no manejo el rating. Yo manejo un Roll Royce. -------------------------------------------------------------------------------- /examples/macri_1/make.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/sh 2 | youtube-dl https://youtu.be/GynDJC845Go -f 22 --external-downloader ffmpeg --external-downloader-args '-ss 365' 3 | miau El\ presidente\ Mauricio\ Macri\ inauguró\ el\ nuevo\ Centro\ de\ Trasbordo\ Constitución-GynDJC845Go.* -r macri_remix.txt -------------------------------------------------------------------------------- /examples/lo_que_tu_quieras_oir/make.sh: -------------------------------------------------------------------------------- 1 | youtube-dl -f mp4 https://www.youtube.com/watch?v=12Z3J1uzd0Q --external-downloader ffmpeg --external-downloader-args '-ss 153 -t 67' 2 | miau Lo\ que\ tú\ Quieras\ Oír-12Z3J1uzd0Q.mp4 mensaje_original.txt -r remix_de_sofia.txt -o remix_de_sofia.mp3 --debug -------------------------------------------------------------------------------- /examples/fort/make.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/sh 2 | youtube-dl -f 43 https://www.youtube.com/watch?v=bra9kqtU7vk --external-downloader ffmpeg --external-downloader-args '-t 167' 3 | miau Puroshow.com\ -\ El\ discurso\ de\ Fort-bra9kqtU7vk.* -r remix.txt 4 | # Result at https://www.youtube.com/watch?v=E_8BdQpXRLo -------------------------------------------------------------------------------- /examples/macron/make.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/sh 2 | youtube-dl http://www.lemonde.fr/election-presidentielle-2017/video/2017/05/07/presidentielle-2017-macron-assure-qu-il-s-efforcera-de-retisser-les-liens-entre-l-europe-et-les-citoyens_5123880_4854003.html 3 | miau Présidentielle* -r macron_remix.txt --lang=fr -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include AUTHORS.md 2 | include CONTRIBUTING.md 3 | include CHANGES.md 4 | include LICENSE 5 | include README.md 6 | include requirements.txt 7 | 8 | recursive-include tests * 9 | recursive-exclude * __pycache__ 10 | recursive-exclude * *.py[co] 11 | 12 | recursive-include docs *.md conf.py Makefile make.bat 13 | 14 | recursive-include miau/conf *.json -------------------------------------------------------------------------------- /docs/index.txt: -------------------------------------------------------------------------------- 1 | .. miau documentation master file, created by 2 | sphinx-quickstart on Thu May 28 01:22:58 2015. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Welcome to miau's documentation! 7 | ======================================================= 8 | 9 | Contents: 10 | 11 | .. toctree:: 12 | :maxdepth: 2 13 | 14 | 15 | 16 | Indices and tables 17 | ================== 18 | 19 | * :ref:`genindex` 20 | * :ref:`modindex` 21 | * :ref:`search` 22 | 23 | -------------------------------------------------------------------------------- /examples/lo_que_tu_quieras_oir/remix_de_sofia.txt: -------------------------------------------------------------------------------- 1 | Sofía, soy Miguel. 2 | Sofía, 3 | necesito 4 | volver a casa 5 | esta noche 6 | Durante meses he pensado en 7 | salvar lo nuestro 8 | necesito 9 | volver 10 | No quiero ser un inmaduro y lo he sido mucho tiempo por no decirte lo que pensaba. 11 | te quiero. 12 | habrás hecho tu vida al margen de mi. 13 | Pero 14 | necesito 15 | volver a casa, 16 | te quiero. 17 | quiero salvar lo que queda de nosotros. 18 | te quiero. 19 | Siento no tener fuerza para decirte esto a la cara. 20 | te quiero. 21 | te quiero. -------------------------------------------------------------------------------- /examples/merkel/Angela Merkel Speaking English to British Parliament-cGZWR5S1lCo.txt: -------------------------------------------------------------------------------- 1 | I've been told many times during the last few days that there are very special expectations of my speech here today. 2 | 3 | Supposedly, or so I have heard, some expect my speech to pave the way for a fundamental reform of the European architecture, which will satisfy all kinds of alleged or actual British wishes. I'm afraid they are in for a disappointment. I've also heard that others are expecting the exact opposite, and are hoping that I will deliver the clear and simple message here in London that the rest of Europe is not prepared to pay almost any price to keep Britain in the European Union. I'm afraid these hopes will be dashed too. -------------------------------------------------------------------------------- /examples/macri_2/remix.txt: -------------------------------------------------------------------------------- 1 | Buenos días, buenos días. 2 | +++la verdad es que 3 | estoy feliz 4 | ++++en este convencimiento, estando seguros 5 | ++de lo que nosotros somos capaces de hacer 6 | ---De lograr lo que hablábamos con Juan Cruz--- 7 | la ausencia del Estado 8 | que cada vez más argentinos tengan---- 9 | lugares de exclusión, de pobreza, de frustración 10 | ahí es donde viene, como decía Lino 11 | no podemos seguir viviendo en un país con+++++++++++++ 12 | posibilidades de trabajo, de inclusión, de participación. 13 | 14 | Pero la verdad es 15 | que enfrentamos 16 | esas poblaciones vulnerables 17 | le caen las lágrimas. 18 | 19 | Creo que hoy 20 | en base a creernos los más vivos, hacer fantochadas 21 | vamos a salir para arriba en cualquier momento 22 | Lino también 23 | en la misma dirección -------------------------------------------------------------------------------- /examples/macri_1/macri_remix.txt: -------------------------------------------------------------------------------- 1 | Como digo siempre, hacer política++++ 2 | +++en el atajo,++++ 3 | ++y todos queriendo participar+ 4 | +++en la mentira 5 | es el camino que hemos emprendido 6 | ++como decía Horacio, estamos construyendo un país 7 | que le va a aumentar+++ 8 | a la gente 9 | # la tranquilidad y la alegría 10 | Y por eso 11 | porque queremos realmente darles+++ 12 | la pobreza 13 | a nuestros maravillosos docentes------- 14 | ---en todas las provincias de la Argentina 15 | ese es el desafío 16 | este es el camino que hemos emprendido 17 | si el tucumano quiere 18 | ++educación pública de calidad------- 19 | ++hay que terminarlo, porque los estamos terminando y vamos a terminar sistemáticamente 20 | y para eso estamos haciendo lo que había que hacer 21 | --y mucho tiene que ver sin duda la maravillosa Reina 22 | -----María Eugenia 23 | felicitaciones a todos los que han trabajado en esta iniciativa 24 | Felicitaciones -------------------------------------------------------------------------------- /examples/lo_que_tu_quieras_oir/mensaje_original.txt: -------------------------------------------------------------------------------- 1 | Sofía, soy Miguel. Si estas en casa por favor coge el teléfono, es urgente que hablemos. 2 | No estas, Sofía, dios, no sé cómo decirte esto. No, no voy a volver a casa, ni esta noche ni ninguna otra. 3 | Es que...tú no te das cuenta pero necesito que me des algo de tiempo ;Porque tengo que pensar aunque sé que pueda que no lo merezca, pero no quiero volver. Tú no te das cuenta, estas con tus niños y tus plantas. 4 | Durante meses he pensado en que podíamos intentar salvar lo nuestro pero no es verdad. 5 | No quiero ser un inmaduro y lo he sido mucho tiempo por no decirte lo que pensaba. 6 | Ahora creerás que soy un cerdo, claro yo lo pensaría. 7 | Pero pronto habrás hecho tu vida al margen de mi. 8 | Yo lo necesito, necesito marcharme, salir de esa casa. 9 | Ahora te echo de menos pero pasará, ya no te quiero. 10 | No quiero salvar lo que queda de nosotros. 11 | Siento no tener fuerza para decirte esto a la cara. 12 | Pero si lo hablamos me quedo...me quedo y no quiero quedarme. -------------------------------------------------------------------------------- /examples/merkel/merkel_remix.json: -------------------------------------------------------------------------------- 1 | [ 2 | [ 3 | "I will deliver the clear and simple message", 4 | { 5 | "end": 49.47, 6 | "clip": "Angela Merkel Speaking English to British Parliament-cGZWR5S1lCo.webm", 7 | "begin": 46.68 8 | } 9 | ], 10 | [ 11 | "the rest of Europe is not prepared", 12 | { 13 | "end": 53.31, 14 | "clip": "Angela Merkel Speaking English to British Parliament-cGZWR5S1lCo.webm", 15 | "begin": 50.96 16 | } 17 | ], 18 | [ 19 | "I'm afraid they", 20 | { 21 | "end": 38.529999999999994, 22 | "clip": "Angela Merkel Speaking English to British Parliament-cGZWR5S1lCo.webm", 23 | "begin": 36.36 24 | } 25 | ], 26 | [ 27 | "are very special", 28 | { 29 | "end": 13.08, 30 | "clip": "Angela Merkel Speaking English to British Parliament-cGZWR5S1lCo.webm", 31 | "begin": 11.68 32 | } 33 | ], 34 | [ 35 | "or so I have", 36 | { 37 | "end": 20.85, 38 | "clip": "Angela Merkel Speaking English to British Parliament-cGZWR5S1lCo.webm", 39 | "begin": 17.4 40 | } 41 | ] 42 | ] -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # multimedia 7 | *.webm 8 | *.mp4 9 | *.mp3 10 | *.mkv 11 | *.avi 12 | *.ogg 13 | *.m4a 14 | 15 | # C extensions 16 | *.so 17 | 18 | # Distribution / packaging 19 | .Python 20 | env/ 21 | build/ 22 | develop-eggs/ 23 | dist/ 24 | downloads/ 25 | eggs/ 26 | .eggs/ 27 | lib/ 28 | lib64/ 29 | parts/ 30 | sdist/ 31 | var/ 32 | *.egg-info/ 33 | .installed.cfg 34 | *.egg 35 | 36 | # PyInstaller 37 | # Usually these files are written by a python script from a template 38 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 39 | *.manifest 40 | *.spec 41 | 42 | # Installer logs 43 | pip-log.txt 44 | pip-delete-this-directory.txt 45 | 46 | # Unit test / coverage reports 47 | htmlcov/ 48 | .tox/ 49 | .coverage 50 | .coverage.* 51 | .cache 52 | nosetests.xml 53 | coverage.xml 54 | *,cover 55 | .hypothesis/ 56 | 57 | # Translations 58 | *.mo 59 | *.pot 60 | 61 | # Django stuff: 62 | *.log 63 | local_settings.py 64 | 65 | # Flask stuff: 66 | instance/ 67 | .webassets-cache 68 | 69 | # Scrapy stuff: 70 | .scrapy 71 | 72 | # Sphinx documentation 73 | docs/_build/ 74 | 75 | # PyBuilder 76 | target/ 77 | 78 | # IPython Notebook 79 | .ipynb_checkpoints 80 | 81 | # pyenv 82 | .python-version 83 | 84 | # celery beat schedule file 85 | celerybeat-schedule 86 | 87 | # dotenv 88 | .env 89 | 90 | # virtualenv 91 | venv/ 92 | ENV/ 93 | 94 | # Spyder project settings 95 | .spyderproject 96 | 97 | # Rope project settings 98 | .ropeproject 99 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2017, Martín Gaitán 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | * Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import setuptools 4 | 5 | 6 | readme = '' 7 | if os.path.exists('README.md'): 8 | with open('README.md') as readme_file: 9 | readme = readme_file.read() 10 | 11 | changes = '' 12 | if os.path.exists('CHANGES.md'): 13 | with open('CHANGES.md') as changes_file: 14 | changes = changes_file.read() 15 | 16 | requirements = [] 17 | with open('requirements.txt') as requirements_file: 18 | requirements = requirements_file.readlines() 19 | 20 | test_requirements = [] 21 | 22 | setuptools.setup( 23 | name = 'miau', 24 | version = '0.1.0', 25 | description = "Remix speeches for fun and profit", 26 | long_description = '%s\n\n%s' % (readme, changes), 27 | author = "Martín Gaitán", 28 | author_email = 'gaitan@gmail.com', 29 | url = 'https://github.com/mgaitan/miau', 30 | packages = setuptools.find_packages(), 31 | package_dir = {'miau': 'miau'}, 32 | include_package_data = True, 33 | install_requires = requirements, 34 | entry_points = { 35 | 'console_scripts': [ 36 | 'miau = miau:main', 37 | ] 38 | }, 39 | license = "BSD", 40 | keywords = 'miau', 41 | classifiers = [ 42 | # https://pypi.python.org/pypi?%3Aaction=list_classifiers 43 | 'Intended Audience :: Developers', 44 | 'Operating System :: OS Independent', 45 | 'Programming Language :: Python', 46 | 'License :: OSI Approved :: BSD', 47 | "Programming Language :: Python :: 2", 48 | 'Programming Language :: Python :: 2.7', 49 | 'Programming Language :: Python :: 3', 50 | 'Programming Language :: Python :: 3.3', 51 | 'Programming Language :: Python :: 3.4', 52 | 'Programming Language :: Python :: 3.5', 53 | 'Programming Language :: Python :: 3.6', 54 | ], 55 | test_suite='tests', 56 | tests_require=test_requirements 57 | ) 58 | -------------------------------------------------------------------------------- /examples/fort/Puroshow.com - El discurso de Fort-bra9kqtU7vk.txt: -------------------------------------------------------------------------------- 1 | Buenas noches señor Marcelo Tinelli, jurado, participantes, público presente y pueblo argentino. Estoy aquí para dar a conocer los motivos de mi alejamiento y mi vuelta a Showmatch. Sé que haberme ido como lo hice fue impulsivo y pido disculpas por mi accionar. 2 | Ahora, qué tal, yo soy así y no voy a pedir disculpas por mostrarme como soy, ni por la personalidad que tengo, 3 | ni por elegir irme, dolido a Miami, a tomar distancia de todas las cosas horribles e hirientes que se dicen sobre Ricardo Fort. No dejan de hablar de mí hasta en mi ausencia. Si me nombran hasta en el noticiero, por suerte antes del pronóstico 4 | del tiempo y de la cotización del dólar, ¿no? Y por supuesto que me gusta que hablen de mi, ya que cada vez que me nombran, más alimentan mi fama. Pero sepan, señoras y señores, que los ataques duelen, y mucho. Y más duele que vengan de personas que pareciera creer que la moral es una planta que da moras. Me sentí tan mal con todas las agresiones que recibí 5 | que casi busco ayuda profesional. Y no estoy hablando de un asesino a sueldo, no, no, no, sino un psicólogo. Pero luego entendí que no debe ser fácil para algunos asimilar un ascenso un éxito tan rápido como el mío en este medio. Ni mucho menos les debe gustar que soy la demostración que hay una vida mejor y que la estoy disfrutando yo, no ellos. Si me dedicara al campo y cosechara como cosecho ahora palos y faltas de respeto, haría una fortuna sólo de eso. Pero como la fortuna ya la tengo me encanta gastarla. Porque no tiene nada de malo ser hijo de un millonario. Como tampoco tiene nada de malo ser un periodista de segunda selección que vive contando intimidades ajenas y faltándole el respeto a todo el mundo. Y cuando digo de segunda selección, lo digo por un periodista que no mide sus palabras y lastima con lo que dice. 6 | También me duele que digan que pienso que soy el rey de ShowMatch. Por favor, yo no manejo el rating. Yo manejo un Roll Royce. -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: clean-pyc clean-build docs clean 2 | 3 | help: 4 | @echo "clean - remove all build, test, coverage and Python artifacts" 5 | @echo "clean-build - remove build artifacts" 6 | @echo "clean-pyc - remove Python file artifacts" 7 | @echo "test - run tests quickly with the default Python" 8 | @echo "test-all - run tests on every Python version with tox" 9 | @echo "coverage - check code coverage quickly with the default Python" 10 | @echo "dist - package" 11 | @echo "install - install the package to the active Python's site-packages" 12 | @echo "release - package and upload a release to PyPI" 13 | @echo "release-test - package and upload a release to PYPI (test)" 14 | @echo "docs - generate Sphinx HTML documentation, including API docs" 15 | @echo "lint - check style with Pylint" 16 | 17 | 18 | clean: clean-build clean-pyc clean-test 19 | 20 | clean-build: 21 | rm -rf build/ 22 | rm -rf dist/ 23 | rm -rf .eggs/ 24 | find . -name '*.egg-info' -exec rm -fr {} + 25 | find . -name '*.egg' -exec rm -f {} + 26 | 27 | clean-pyc: 28 | find . -name '*.pyc' -exec rm -f {} + 29 | find . -name '*.pyo' -exec rm -f {} + 30 | find . -name '*~' -exec rm -f {} + 31 | find . -name '__pycache__' -exec rm -fr {} + 32 | 33 | clean-test: 34 | rm -rf .tox/ 35 | rm -f .coverage 36 | rm -rf htmlcov/ 37 | 38 | test: 39 | python setup.py test 40 | 41 | test-all: 42 | tox 43 | 44 | coverage: 45 | coverage run --source miau setup.py test 46 | coverage report -m 47 | coverage html 48 | open htmlcov/index.html 49 | 50 | release: clean 51 | python setup.py sdist upload 52 | python setup.py bdist_wheel upload 53 | 54 | release-test: clean 55 | python setup.py sdist upload --repository https://testpypi.python.org/pypi 56 | python setup.py bdist_wheel upload --repository https://testpypi.python.org/pypi 57 | open https://testpypi.python.org/pypi/miau 58 | 59 | dist: clean 60 | python setup.py sdist 61 | python setup.py bdist_wheel 62 | ls -l dist 63 | 64 | install: clean 65 | python setup.py install 66 | 67 | lint: 68 | pylint miau tests 69 | 70 | docs: 71 | rm -f docs/miau.rst 72 | rm -f docs/modules.rst 73 | sphinx-apidoc -o docs/ miau 74 | make -C docs clean 75 | make -C docs html 76 | open docs/_build/html/index.html 77 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | miau 2 | ==== 3 | 4 | Remix speeches for fun and profit (**work in progress**) 5 | 6 | .. |Travis| |PyPi| |PyPi Downloads| 7 | 8 | :License: BSD 9 | 10 | .. :Documentation: https://miau.readthedocs.org 11 | 12 | ``miau`` is a command line tool to easily generate remixes of clips like 13 | political speeches. 14 | 15 | Usage 16 | ----- 17 | 18 | :: 19 | 20 | tin@morochita:~/lab/miau$ miau --help 21 | Miau: Remix speeches for fun and profit 22 | 23 | Usage: 24 | miau ... -r [-o ] [-d ] [--lang ] [--debug] 25 | miau -h | --help 26 | miau --version 27 | 28 | Options: 29 | Input files patterns (clip/s and its transcripts) 30 | -r --remix Script text (txt or json) 31 | -d --dump Dump remix as json. 32 | Can be loaded with -r to reuse the aligment. 33 | -o --output Output filename 34 | -h --help Show this screen. 35 | --lang Set language (2-letter code) for inputs (default autodetect) 36 | --version Show version. 37 | 38 | 39 | Examples 40 | -------- 41 | 42 | 43 | - `Macri: "Vamos a salir para arriba en cualquier momento" `_ (spanish) 44 | 45 | .. image:: http://img.youtube.com/vi/YtY_CRiFKPY/0.jpg 46 | :target: https://youtu.be/YtY_CRiFKPY 47 | 48 | 49 | - `Merkel on Europe `_ (english) 50 | 51 | .. image:: http://img.youtube.com/vi/5nzWXjNJ9d8/0.jpg 52 | :target: https://www.youtube.com/watch?v=5nzWXjNJ9d8 53 | 54 | 55 | - `Macron "Autres sont des menaces" `_ (french) 56 | 57 | .. image:: http://img.youtube.com/vi/MhTv5rPo_8A/0.jpg 58 | :target: https://www.youtube.com/watch?v=MhTv5rPo_8A 59 | 60 | 61 | - `Macri: "Pobreza para nuestros docentes" `_ (spanish) 62 | 63 | .. image:: http://img.youtube.com/vi/vYE9AJaPAIA/0.jpg 64 | :target: https://youtu.be/vYE9AJaPAIA 65 | 66 | 67 | How it works? 68 | ------------- 69 | 70 | It uses `aeneas `__ to syncronize 71 | the transcription and the input audio/video file (force align), using as many iterations as needed. 72 | 73 | Another text define the remix script (i.e. "output speech"), using fragments of the input transcription. ``miau`` cuts the proper parts and join each of them using 74 | `moviepy `__. 75 | 76 | A detailed blog post (in spanish) is `here `_ 77 | 78 | 79 | Why *miau*? 80 | ----------- 81 | 82 | ``miau`` means ``meow`` in spanish. It's a joke about the popular 83 | (pejorative) `nickname assigned to Argentina's 84 | president `__ 85 | Mauricio "Cat" Macri. As I started this tool to make fun of President Macri, 86 | this was a pretty obvious choice. 87 | 88 | 89 | .. |Travis| image:: https://img.shields.io/travis/mgaitan/miau.svg 90 | :target: https://travis-ci.org/mgaitan/miau 91 | .. |PyPi| image:: https://img.shields.io/pypi/v/miau.svg 92 | :target: https://pypi.python.org/pypi/miau 93 | .. |PyPi Downloads| image:: http://img.shields.io/pypi/dm/miau.svg 94 | :target: https://pypi.python.org/pypi/miau 95 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ============ 2 | Contributing 3 | ============ 4 | 5 | Contributions are welcome, and they are greatly appreciated! Every 6 | little bit helps, and credit will always be given. 7 | 8 | You can contribute in many ways: 9 | 10 | Types of Contributions 11 | ---------------------- 12 | 13 | Report Bugs 14 | ~~~~~~~~~~~ 15 | 16 | Report bugs at https://github.com/mgaitan/miau/issues. 17 | 18 | If you are reporting a bug, please include: 19 | 20 | * Your operating system name and version. 21 | * Any details about your local setup that might be helpful in troubleshooting. 22 | * Detailed steps to reproduce the bug. 23 | 24 | Fix Bugs 25 | ~~~~~~~~ 26 | 27 | Look through the GitHub issues for bugs. Anything tagged with "bug" 28 | is open to whoever wants to implement it. 29 | 30 | Implement Features 31 | ~~~~~~~~~~~~~~~~~~ 32 | 33 | Look through the GitHub issues for features. Anything tagged with "feature" 34 | is open to whoever wants to implement it. 35 | 36 | Write Documentation 37 | ~~~~~~~~~~~~~~~~~~~ 38 | 39 | miau could always use more documentation, whether as part of the 40 | official miau docs, in docstrings, or even on the web in blog posts, 41 | articles, and such. 42 | 43 | Submit Feedback 44 | ~~~~~~~~~~~~~~~ 45 | 46 | The best way to send feedback is to file an issue at https://github.com/mgaitan/miau/issues. 47 | 48 | If you are proposing a feature: 49 | 50 | * Explain in detail how it would work. 51 | * Keep the scope as narrow as possible, to make it easier to implement. 52 | * Remember that this is a volunteer-driven project, and that contributions 53 | are welcome :) 54 | 55 | Get Started! 56 | ------------ 57 | 58 | Ready to contribute? Here's how to set up `miau` for local development. 59 | 60 | 1. Fork the `miau` repo on GitHub. 61 | 2. Clone your fork locally:: 62 | 63 | $ git clone git@github.com:your_name_here/miau.git 64 | 65 | 3. Install your local copy into a virtualenv. Assuming you have virtualenvwrapper installed, this is how you set up your fork for local development:: 66 | 67 | $ mkvirtualenv miau 68 | $ cd miau/ 69 | $ python setup.py develop 70 | 71 | 4. Create a branch for local development:: 72 | 73 | $ git checkout -b name-of-your-bugfix-or-feature 74 | 75 | Now you can make your changes locally. 76 | 77 | 5. When you're done making changes, check that your changes pass flake8 and the tests, including testing other Python versions with tox:: 78 | 79 | $ flake8 miau tests 80 | $ python setup.py test 81 | $ tox 82 | 83 | To get flake8 and tox, just pip install them into your virtualenv. 84 | 85 | 6. Commit your changes and push your branch to GitHub:: 86 | 87 | $ git add . 88 | $ git commit -m "Your detailed description of your changes." 89 | $ git push origin name-of-your-bugfix-or-feature 90 | 91 | 7. Submit a pull request through the GitHub website. 92 | 93 | Pull Request Guidelines 94 | ----------------------- 95 | 96 | Before you submit a pull request, check that it meets these guidelines: 97 | 98 | 1. The pull request should include tests. 99 | 2. If the pull request adds functionality, the docs should be updated. Put 100 | your new functionality into a function with a docstring, and add the 101 | feature to the list in README.rst. 102 | 3. The pull request should work for Python 2.6, 2.7, 3.3, and 3.4, and for PyPy. Check 103 | https://travis-ci.org/mgaitan/miau/pull_requests 104 | and make sure that the tests pass for all supported Python versions. 105 | 106 | Tips 107 | ---- 108 | 109 | To run a subset of tests:: 110 | 111 | $ python -m unittest tests.test_miau 112 | -------------------------------------------------------------------------------- /examples/macri_2/fantochadas.txt: -------------------------------------------------------------------------------- 1 | Escucharemos las palabras del señor presidente de La Nación, 2 | Mauricio Macri. 3 | 4 | Buenos días, buenos días. Una alegría estar acá a punto de ser otro vehículo 5 | experimental en el espacio con este viento, vamos a salir para arriba en cualquier momento con la Gobernadora que con el viento se emociona y le caen las lágrimas. 6 | Pero la verdad es que estoy feliz de compartir este momento con ustedes, orgulloso de escucharlo al Ministro tan apasionado con tantos proyectos, doce iniciativas que estamos lanzando, como él lo explicaba. 7 | La tecnología en las escuelas; la acuicultura; la agricultura de precisión; 8 | la medicina; el ocuparnos de esas poblaciones vulnerables que están acá a pocos kilómetros, como le comentaba al Ministro antes de arrancar, que tanto tiempo han estado invisibles frente a la ausencia del Estado. 9 | Hay tantas cosas que tenemos por delante que son realidad, que tienen que ver con nuestra capacidad, como hablábamos recién con Juan Cruz y Pablo 10 | sobre este proyecto, que no es ciencia ficción. 11 | Este lanzador es una realidad de lo que nosotros somos capaces de hacer. 12 | Es una demostración de que somos un país con calidades, cualidades, talento, 13 | que en algunos sectores los hemos puesto en marcha durante muchos años 14 | y hemos continuado siendo referentes mundiales, como lo somos en todos los desarrollos que tienen que ver con la tecnología del mundo espacial. 15 | Pero el desafío que enfrentamos hoy es tratar de que esas islas de calidad se extiendan a todo el país, que incluya a todos los argentinos, 16 | no podemos seguir viviendo en un país con tantos lugares de exclusión, 17 | de pobreza, de frustración, necesitamos realmente compartir el futuro que viene. 18 | 19 | Y ahí es donde viene, como decía Lino, el gran desafío que tienen ustedes, 20 | que representan uno de los valores principales que tiene nuestro país 21 | y que es demostrar que la investigación, el desarrollo, la innovación, 22 | pueden ser y van a ser elementos centrales para construir soluciones de calidad 23 | que resuelvan muchos de estos problemas que venimos acumulando, 24 | negando y no resolviendo desde hace muchos años. 25 | 26 | Y en la resolución crearon nuevas oportunidades, porque en el camino a construir esas soluciones siempre se generan nuevas posibilidades de trabajo, 27 | de inclusión, de participación. 28 | 29 | De lograr lo que hablábamos con Juan Cruz, de que cada vez más argentinos tengan una tarea en la cual no necesiten despertador para ir a trabajar 30 | ni se acuerdan de los horarios, porque lo que hacen, como les pasa a cada uno de ustedes, los apasiona, los convoca, los nutre, ese esfuerzo que ponen ustedes 31 | es lo que los hace ser quiénes son, es lo que los hace sentirse parte, 32 | sentirse orgullosos, tener una autoestima alta. 33 | 34 | Eso es lo que necesitamos, que todos los argentinos tengamos la autoestima bien alta, pero no en base a creernos los más vivos, 35 | hacer fantochadas, sino en base al hacer diario, el hacer las cosas bien. 36 | 37 | Creo que hoy nos estamos comprometiendo con doce iniciativas muy valiosas. 38 | Estamos invirtiendo en un momento en el cual al país no le sobra nada, 39 | porque como decíamos, hay muchas deudas sociales pendientes. 40 | 41 | Estamos invirtiendo mil millones poniendo toda la esperanza en que de ahí va a salir mucho, mucho para muchos argentinos, mucho para demostrarle al mundo 42 | todo lo que somos capaces de hacer. Y esto es también parte de ese compromiso 43 | que yo asumí, que es unir a los argentinos. 44 | 45 | Unidos en esta gesta, unidos en este convencimiento, estando seguros de que 46 | el mundo de la ciencia y la tecnología tienen un enorme aporte por hacer 47 | en el mundo de la aplicación, es que hoy estamos acá. 48 | 49 | Así que felicitaciones a todos, estamos juntos en esto, como decía Lino también, por primera vez no es el Ministerio de Ciencia y Tecnología. 50 | Es Ciencia y Tecnología en conjunto con Educación, con Desarrollo Social, con Energía, con Producción, con Agroindustria, todos juntos 51 | tirando en la misma dirección, en construir una Argentina como la que soñamos 52 | y como la que merecemos. 53 | 54 | Gracias y a seguir trabajando. -------------------------------------------------------------------------------- /examples/macron/Présidentielle 2017 - Macron assure qu'il oeuvrera à 'retisser les liens entre l'Europe et les citoyens'-r0vpsx.txt: -------------------------------------------------------------------------------- 1 | À l’issue d’une longue confrontation démocratique, vous avez choisi de m’accorder votre confiance et je tiens à vous exprimer ma profonde gratitude. C’est un grand honneur et c’est une grande responsabilité. Car rien n’était écrit. Je veux vous dire merci. Merci du fond du cœur. 2 | 3 | Ma gratitude va à tous ceux d’entre vous qui m’ont apporté leur suffrage et leur soutien. Je ne vous oublierai pas. Je mettrai tout mon soin et toute mon énergie à être digne de votre confiance. 4 | 5 | Mais en cet instant, c’est à vous tous, citoyens de notre pays, que je veux m’adresser, quel qu’ait été votre choix. 6 | 7 | Bien des difficultés nous ont affaiblis depuis trop longtemps. Je ne méconnais aucune, ni les difficultés économiques, ni les fractures sociales, ni les impasses démocratiques, ni l’affaiblissement moral du pays. 8 | 9 | Je veux ce soir adresser un salut républicain à mon adversaire, Madame LE PEN. 10 | 11 | Je sais les divisions de notre nation qui ont conduit certains à des votes extrêmes. Je les respecte. 12 | 13 | Je sais la colère, l’anxiété, les doutes qu’une grande partie d’entre vous ont aussi exprimés : il est de ma responsabilité de les entendre, en protégeant les plus fragiles, en organisant mieux les solidarités, en luttant contre toutes les formes d’inégalité ou de discrimination, en assurant de manière implacable et résolue votre sécurité, en garantissant l’unité de la nation. 14 | 15 | Car derrière chacun des mots que je viens de prononcer, je sais qu’il y a des visages, des femmes et des hommes, des enfants et des familles, des vies entières. Il y a vous et les vôtres. 16 | 17 | Ce soir, c’est à vous tous que je m’adresse, vous tous ensemble, le peuple de France. 18 | 19 | Nous avons des devoirs envers notre pays. Nous sommes les héritiers d’une grande Histoire et du grand message humaniste adressé au monde. 20 | 21 | Cette histoire et ce message, nous devons les transmettre d’abord à nos enfants mais, plus important encore, il nous faut les porter vers l’avenir et leur donner une sève nouvelle. 22 | 23 | Je défendrai la France, ses intérêts vitaux, son image, son message, j’en prends l’engagement devant vous. 24 | 25 | Je défendrai l’Europe, la communauté de destin que se sont donnée les peuples de notre continent. 26 | 27 | C’est notre civilisation qui est en jeu, notre manière de vivre, d’être libres, de porter nos valeurs, nos entreprises communes et nos espoirs. J’oeuvrerai à retisser le lien entre l’Europe et les peuples qui la forment, entre l’Europe et les citoyens. 28 | 29 | J’adresse en votre nom aux nations du monde le salut de la France fraternelle. 30 | 31 | Je dis à leurs dirigeants que la France sera présente et attentive à la paix, à l’équilibre des puissances, à la coopération internationale, au respect des engagements pris en matière de développement et de lutte contre le réchauffement climatique. 32 | 33 | Je dis à tous que la France sera au premier rang de la lutte contre le terrorisme, sur son sol aussi bien que dans l’action internationale. Aussi longtemps que ce combat devra durer, nous le mènerons sans faiblir. 34 | 35 | Mes chers concitoyens, une nouvelle page de notre longue Histoire s’ouvre ce soir. Je veux que ce soit celle de l’espoir et de la confiance retrouvés. Le renouvellement de notre vie publique s’imposera à tous dès demain. 36 | 37 | La moralisation de notre vie publique, la reconnaissance du pluralisme, la vitalité démocratique seront, dès le premier jour, le socle de mon action. 38 | 39 | Je ne me laisserai arrêter par aucun obstacle. 40 | 41 | J’agirai avec détermination et dans le respect de chacun. 42 | 43 | Car par le travail, l’école, la culture, nous construirons un avenir meilleur. 44 | 45 | Françaises, Français, mes chers concitoyens, 46 | 47 | Je veux ce soir saluer le Président Hollande. Il a pendant cinq ans œuvré pour notre pays. 48 | 49 | Durant les cinq années qui s’ouvrent, ma responsabilité sera d’apaiser les peurs, de nous faire renouer avec l’optimisme, de retrouver l’esprit de conquête qui dit mieux que tout le génie français. 50 | 51 | Ma responsabilité sera de rassembler toutes les femmes et tous les hommes prêts à affronter les défis gigantesques qui nous attendent, et à agir. Certains de ces défis sont des chances comme la révolution numérique, la transition écologique, le redémarrage de l’Europe. D’autres sont des menaces, comme le terrorisme. 52 | 53 | Je me battrai de toutes mes forces contre la division qui nous mine et nous abat. 54 | 55 | C’est ainsi que nous pourrons rendre au peuple français, à chacune et chacun d’entre vous, dans sa vie professionnelle, personnelle et familiale, les chances que la France lui doit. 56 | 57 | Aimons la France. A compter de ce soir et pour les cinq années qui viennent, je vais avec humilité, avec dévouement, avec détermination la servir en votre nom. 58 | 59 | Vive la République ! Vive la France ! -------------------------------------------------------------------------------- /examples/macri_1/El presidente Mauricio Macri inauguró el nuevo Centro de Trasbordo Constitución-GynDJC845Go.txt: -------------------------------------------------------------------------------- 1 | Muy bien María. Bueno Horacio, buenos días dueño de casa; a María Eugenia, a todo el equipo, gracias por acompañarnos. 2 | 3 | Primero felicitaciones por el “tango volador”, los quiero felicitar de bailarín a bailarín, porque reconozco la calidad rápidamente, es realmente para exportación. 4 | 5 | Y hablando de exportación, quiero hablarles primero de que llegue esta mañana a las 6 de la mañana de Holanda, donde el afecto con que nos han recibido, el interés que hay del pueblo holandés por la Argentina, por todos nosotros, por tratar de ser parte, y mucho tiene que ver sin duda la maravillosa Reina de origen argentino que tiene los Países Bajos, y todos queriendo participar, creyendo en que tenemos un enorme futuro por delante, queriendo ser socios nuestros en crecer en la producción de alimentos, en la producción de energía, en hacer obras en las cuales ellos son muy buenos, todo el manejo del agua, piensen que ellos siempre han lidiado con el agua y las inundaciones, son el dos por ciento del territorio argentino y están entre los veinte países más importantes del mundo. 6 | 7 | Y quieren venir a ayudarnos acá, a ampliar las hectáreas en la Provincia para que se pueda producir más, y en todas las provincias de la Argentina, y así generar más trabajo. Y quieren ayudarnos a ampliar los puertos, y quieren participar en el desarrollo del mercado de la energía, porque también son buenos en energía. 8 | 9 | Y hacer obras como esta, que realmente como decía Horacio, es maravilloso, porque esto es apostar al transporte público, es apostar a que todos tengamos acceso a llegar de la manera más confortable, más segura, más digna, a nuestro trabajo, al hospital, a la escuela, y eso hicimos cuando empezamos esta obra. Y hoy la verdad es una maravilla poderla terminar, y felicitarlos a los muchachos porque ustedes también son artistas habiendo hecho esto. Un aplauso para todos los trabajadores que nos han dado esta alegría. (APLAUSOS) 10 | 11 | Y justamente, como decía Horacio, estamos construyendo un país que le dé oportunidades a todos los argentinos, estamos creyendo en que somos capaces de vivir mejor, que merecemos vivir mejor, y para eso estamos haciendo lo que había que hacer pensando en el largo plazo, no en el atajo, no en la mentira, no en el parche, en hacer las cosas de fondo que son las que ayudan a que un país pueda crecer; generar las herramientas para que cada argentino pueda elegir, y que pueda elegir vivir donde nació, porque ahí va a haber un trabajo. 12 | 13 | Y por eso vamos a tener más de 20 mil kilómetros de rutas y autopistas en obra de acá al 2019 ¿Y qué significa eso que son números tan grandes? 2.800 kilómetros de autopista terminados para el 2019, para que aquel que produce algo, ese algo pueda viajar por una ruta segura; para que aquel que quiere viajar pueda viajar por una ruta segura, que ya no es más ruta, es autopista, y que reduce la cantidad de accidentes que tenemos por año, y que aumenta nuestra potencialidad productiva. Y cuando comparamos, sí, van a ser 2.800 kilómetros de autopista nuevos en cuatro años contra 1.300 en más de quince años. 14 | 15 | Y con estas herramientas, recuperando los trenes de carga, ampliando los puertos, poniendo en obra 19 aeropuertos, con esta revolución de aviones ¿Para qué? Para que todo el mundo pueda volar y no tenga que pasar por Buenos Aires, y van a haber muchas más variantes para venir a visitar Buenos Aires-no se preocupe Jefe de Gobierno- Pero también si el tucumano quiere volar directamente a Mar del Plata o a Bariloche lo puede hacer. Y que en esa oportunidad nos podemos conectar con los afectos, podemos comerciar más, podemos desarrollarnos más. 16 | 17 | Y estos son los pasos concretos que estamos, que no son de un día para el otro, llevan su tiempo porque hay que proyectarlo, hay que decidirlo, hay que contratarlo, hay que controlarlo. Y hay que terminarlo, porque los estamos terminando y vamos a terminar sistemáticamente, como también las obras de cloacas y agua potable que estamos haciendo en la Provincia de Buenos Aires con la Gobernadora. 18 | 19 | Y esas obras que estamos haciendo, la buena noticia, es que dan trabajo, trabajo del bueno. Acá están los muchachos orgullosos de haber hecho esta obra, como están orgullosos todos los que están trabajando por todo el país, sintiendo que con su mano, con su inteligencia, están contribuyendo al crecimiento de la Argentina. 20 | 21 | Como digo siempre, hacer política es estar cerca, es cuidar a la gente, es tener un proyecto que los incluya a todos, a nuestros hijos y a los hijos de nuestros hijos. Y este es el camino que hemos emprendido, intentando recuperar el valor del diálogo entre nosotros los argentinos. 22 | 23 | No tenemos que detenernos frente a aquellos que quieren que este cambio no avance, tenemos que demostrarles nuestra convicción y de esa convicción convencerlos. Y las batallas que estamos dando son las batallas por el futuro, por eso Gobernadora también la quiero volver a alentar, porque sé que estamos en una discusión de fondo cuando discutimos que queremos mejorar la calidad de la educación pública, porque eso es lo que iguala oportunidades. (APLAUSOS) 24 | 25 | La educación pública de calidad es lo que hace que todos los chicos en este país tengan las mismas oportunidades, por lo cual este debate queremos que llegue hasta el final, porque queremos realmente darles herramientas a nuestros maravillosos docentes, para que puedan ellos a la vez transmitírselas a nuestros chicos para que consigan los mejores trabajos del siglo XXI, porque ese es el desafío, si queremos reducir la pobreza tenemos que generar trabajo, y este es el camino que hemos emprendido. 26 | 27 | Así que felicitaciones Horacio, felicitaciones a todos los que han trabajado en esta iniciativa, más de un millón de personas van a todos los días llegar a Buenos Aires y salir de Buenos Aires con esta maravillosa instalación que le va a aumentar la seguridad, la tranquilidad y la alegría de que en este país se progresa, se mejora. 28 | 29 | Felicitaciones y gracias -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | REM Command file for Sphinx documentation 4 | 5 | if "%SPHINXBUILD%" == "" ( 6 | set SPHINXBUILD=sphinx-build 7 | ) 8 | set BUILDDIR=_build 9 | set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . 10 | set I18NSPHINXOPTS=%SPHINXOPTS% . 11 | if NOT "%PAPER%" == "" ( 12 | set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% 13 | set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% 14 | ) 15 | 16 | if "%1" == "" goto help 17 | 18 | if "%1" == "help" ( 19 | :help 20 | echo.Please use `make ^` where ^ is one of 21 | echo. html to make standalone HTML files 22 | echo. dirhtml to make HTML files named index.html in directories 23 | echo. singlehtml to make a single large HTML file 24 | echo. pickle to make pickle files 25 | echo. json to make JSON files 26 | echo. htmlhelp to make HTML files and a HTML help project 27 | echo. qthelp to make HTML files and a qthelp project 28 | echo. devhelp to make HTML files and a Devhelp project 29 | echo. epub to make an epub 30 | echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter 31 | echo. text to make text files 32 | echo. man to make manual pages 33 | echo. texinfo to make Texinfo files 34 | echo. gettext to make PO message catalogs 35 | echo. changes to make an overview over all changed/added/deprecated items 36 | echo. xml to make Docutils-native XML files 37 | echo. pseudoxml to make pseudoxml-XML files for display purposes 38 | echo. linkcheck to check all external links for integrity 39 | echo. doctest to run all doctests embedded in the documentation if enabled 40 | echo. coverage to run coverage check of the documentation if enabled 41 | goto end 42 | ) 43 | 44 | if "%1" == "clean" ( 45 | for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i 46 | del /q /s %BUILDDIR%\* 47 | goto end 48 | ) 49 | 50 | 51 | REM Check if sphinx-build is available and fallback to Python version if any 52 | %SPHINXBUILD% 2> nul 53 | if errorlevel 9009 goto sphinx_python 54 | goto sphinx_ok 55 | 56 | :sphinx_python 57 | 58 | set SPHINXBUILD=python -m sphinx.__init__ 59 | %SPHINXBUILD% 2> nul 60 | if errorlevel 9009 ( 61 | echo. 62 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 63 | echo.installed, then set the SPHINXBUILD environment variable to point 64 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 65 | echo.may add the Sphinx directory to PATH. 66 | echo. 67 | echo.If you don't have Sphinx installed, grab it from 68 | echo.http://sphinx-doc.org/ 69 | exit /b 1 70 | ) 71 | 72 | :sphinx_ok 73 | 74 | 75 | if "%1" == "html" ( 76 | %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html 77 | if errorlevel 1 exit /b 1 78 | echo. 79 | echo.Build finished. The HTML pages are in %BUILDDIR%/html. 80 | goto end 81 | ) 82 | 83 | if "%1" == "dirhtml" ( 84 | %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml 85 | if errorlevel 1 exit /b 1 86 | echo. 87 | echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. 88 | goto end 89 | ) 90 | 91 | if "%1" == "singlehtml" ( 92 | %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml 93 | if errorlevel 1 exit /b 1 94 | echo. 95 | echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. 96 | goto end 97 | ) 98 | 99 | if "%1" == "pickle" ( 100 | %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle 101 | if errorlevel 1 exit /b 1 102 | echo. 103 | echo.Build finished; now you can process the pickle files. 104 | goto end 105 | ) 106 | 107 | if "%1" == "json" ( 108 | %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json 109 | if errorlevel 1 exit /b 1 110 | echo. 111 | echo.Build finished; now you can process the JSON files. 112 | goto end 113 | ) 114 | 115 | if "%1" == "htmlhelp" ( 116 | %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp 117 | if errorlevel 1 exit /b 1 118 | echo. 119 | echo.Build finished; now you can run HTML Help Workshop with the ^ 120 | .hhp project file in %BUILDDIR%/htmlhelp. 121 | goto end 122 | ) 123 | 124 | if "%1" == "qthelp" ( 125 | %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp 126 | if errorlevel 1 exit /b 1 127 | echo. 128 | echo.Build finished; now you can run "qcollectiongenerator" with the ^ 129 | .qhcp project file in %BUILDDIR%/qthelp, like this: 130 | echo.^> qcollectiongenerator %BUILDDIR%\qthelp\cookiecutterapp_name.qhcp 131 | echo.To view the help file: 132 | echo.^> assistant -collectionFile %BUILDDIR%\qthelp\cookiecutterapp_name.ghc 133 | goto end 134 | ) 135 | 136 | if "%1" == "devhelp" ( 137 | %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp 138 | if errorlevel 1 exit /b 1 139 | echo. 140 | echo.Build finished. 141 | goto end 142 | ) 143 | 144 | if "%1" == "epub" ( 145 | %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub 146 | if errorlevel 1 exit /b 1 147 | echo. 148 | echo.Build finished. The epub file is in %BUILDDIR%/epub. 149 | goto end 150 | ) 151 | 152 | if "%1" == "latex" ( 153 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 154 | if errorlevel 1 exit /b 1 155 | echo. 156 | echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. 157 | goto end 158 | ) 159 | 160 | if "%1" == "latexpdf" ( 161 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 162 | cd %BUILDDIR%/latex 163 | make all-pdf 164 | cd %~dp0 165 | echo. 166 | echo.Build finished; the PDF files are in %BUILDDIR%/latex. 167 | goto end 168 | ) 169 | 170 | if "%1" == "latexpdfja" ( 171 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 172 | cd %BUILDDIR%/latex 173 | make all-pdf-ja 174 | cd %~dp0 175 | echo. 176 | echo.Build finished; the PDF files are in %BUILDDIR%/latex. 177 | goto end 178 | ) 179 | 180 | if "%1" == "text" ( 181 | %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text 182 | if errorlevel 1 exit /b 1 183 | echo. 184 | echo.Build finished. The text files are in %BUILDDIR%/text. 185 | goto end 186 | ) 187 | 188 | if "%1" == "man" ( 189 | %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man 190 | if errorlevel 1 exit /b 1 191 | echo. 192 | echo.Build finished. The manual pages are in %BUILDDIR%/man. 193 | goto end 194 | ) 195 | 196 | if "%1" == "texinfo" ( 197 | %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo 198 | if errorlevel 1 exit /b 1 199 | echo. 200 | echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. 201 | goto end 202 | ) 203 | 204 | if "%1" == "gettext" ( 205 | %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale 206 | if errorlevel 1 exit /b 1 207 | echo. 208 | echo.Build finished. The message catalogs are in %BUILDDIR%/locale. 209 | goto end 210 | ) 211 | 212 | if "%1" == "changes" ( 213 | %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes 214 | if errorlevel 1 exit /b 1 215 | echo. 216 | echo.The overview file is in %BUILDDIR%/changes. 217 | goto end 218 | ) 219 | 220 | if "%1" == "linkcheck" ( 221 | %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck 222 | if errorlevel 1 exit /b 1 223 | echo. 224 | echo.Link check complete; look for any errors in the above output ^ 225 | or in %BUILDDIR%/linkcheck/output.txt. 226 | goto end 227 | ) 228 | 229 | if "%1" == "doctest" ( 230 | %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest 231 | if errorlevel 1 exit /b 1 232 | echo. 233 | echo.Testing of doctests in the sources finished, look at the ^ 234 | results in %BUILDDIR%/doctest/output.txt. 235 | goto end 236 | ) 237 | 238 | if "%1" == "coverage" ( 239 | %SPHINXBUILD% -b coverage %ALLSPHINXOPTS% %BUILDDIR%/coverage 240 | if errorlevel 1 exit /b 1 241 | echo. 242 | echo.Testing of coverage in the sources finished, look at the ^ 243 | results in %BUILDDIR%/coverage/python.txt. 244 | goto end 245 | ) 246 | 247 | if "%1" == "xml" ( 248 | %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml 249 | if errorlevel 1 exit /b 1 250 | echo. 251 | echo.Build finished. The XML files are in %BUILDDIR%/xml. 252 | goto end 253 | ) 254 | 255 | if "%1" == "pseudoxml" ( 256 | %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml 257 | if errorlevel 1 exit /b 1 258 | echo. 259 | echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. 260 | goto end 261 | ) 262 | 263 | :end 264 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | PAPER = 8 | BUILDDIR = _build 9 | 10 | # User-friendly check for sphinx-build 11 | ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) 12 | $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) 13 | endif 14 | 15 | # Internal variables. 16 | PAPEROPT_a4 = -D latex_paper_size=a4 17 | PAPEROPT_letter = -D latex_paper_size=letter 18 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 19 | # the i18n builder cannot share the environment and doctrees with the others 20 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 21 | 22 | .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest coverage gettext 23 | 24 | help: 25 | @echo "Please use \`make ' where is one of" 26 | @echo " html to make standalone HTML files" 27 | @echo " dirhtml to make HTML files named index.html in directories" 28 | @echo " singlehtml to make a single large HTML file" 29 | @echo " pickle to make pickle files" 30 | @echo " json to make JSON files" 31 | @echo " htmlhelp to make HTML files and a HTML help project" 32 | @echo " qthelp to make HTML files and a qthelp project" 33 | @echo " applehelp to make an Apple Help Book" 34 | @echo " devhelp to make HTML files and a Devhelp project" 35 | @echo " epub to make an epub" 36 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 37 | @echo " latexpdf to make LaTeX files and run them through pdflatex" 38 | @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" 39 | @echo " text to make text files" 40 | @echo " man to make manual pages" 41 | @echo " texinfo to make Texinfo files" 42 | @echo " info to make Texinfo files and run them through makeinfo" 43 | @echo " gettext to make PO message catalogs" 44 | @echo " changes to make an overview of all changed/added/deprecated items" 45 | @echo " xml to make Docutils-native XML files" 46 | @echo " pseudoxml to make pseudoxml-XML files for display purposes" 47 | @echo " linkcheck to check all external links for integrity" 48 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" 49 | @echo " coverage to run coverage check of the documentation (if enabled)" 50 | 51 | clean: 52 | rm -rf $(BUILDDIR)/* 53 | 54 | html: 55 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 56 | @echo 57 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." 58 | 59 | dirhtml: 60 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml 61 | @echo 62 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." 63 | 64 | singlehtml: 65 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml 66 | @echo 67 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." 68 | 69 | pickle: 70 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle 71 | @echo 72 | @echo "Build finished; now you can process the pickle files." 73 | 74 | json: 75 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json 76 | @echo 77 | @echo "Build finished; now you can process the JSON files." 78 | 79 | htmlhelp: 80 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp 81 | @echo 82 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 83 | ".hhp project file in $(BUILDDIR)/htmlhelp." 84 | 85 | qthelp: 86 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp 87 | @echo 88 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ 89 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:" 90 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/cookiecutterapp_name.qhcp" 91 | @echo "To view the help file:" 92 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/cookiecutterapp_name.qhc" 93 | 94 | applehelp: 95 | $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp 96 | @echo 97 | @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." 98 | @echo "N.B. You won't be able to view it unless you put it in" \ 99 | "~/Library/Documentation/Help or install it in your application" \ 100 | "bundle." 101 | 102 | devhelp: 103 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp 104 | @echo 105 | @echo "Build finished." 106 | @echo "To view the help file:" 107 | @echo "# mkdir -p $$HOME/.local/share/devhelp/cookiecutterapp_name" 108 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/cookiecutterapp_name" 109 | @echo "# devhelp" 110 | 111 | epub: 112 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub 113 | @echo 114 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub." 115 | 116 | latex: 117 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 118 | @echo 119 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." 120 | @echo "Run \`make' in that directory to run these through (pdf)latex" \ 121 | "(use \`make latexpdf' here to do that automatically)." 122 | 123 | latexpdf: 124 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 125 | @echo "Running LaTeX files through pdflatex..." 126 | $(MAKE) -C $(BUILDDIR)/latex all-pdf 127 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 128 | 129 | latexpdfja: 130 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 131 | @echo "Running LaTeX files through platex and dvipdfmx..." 132 | $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja 133 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 134 | 135 | text: 136 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text 137 | @echo 138 | @echo "Build finished. The text files are in $(BUILDDIR)/text." 139 | 140 | man: 141 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man 142 | @echo 143 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man." 144 | 145 | texinfo: 146 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 147 | @echo 148 | @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." 149 | @echo "Run \`make' in that directory to run these through makeinfo" \ 150 | "(use \`make info' here to do that automatically)." 151 | 152 | info: 153 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 154 | @echo "Running Texinfo files through makeinfo..." 155 | make -C $(BUILDDIR)/texinfo info 156 | @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." 157 | 158 | gettext: 159 | $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale 160 | @echo 161 | @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." 162 | 163 | changes: 164 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes 165 | @echo 166 | @echo "The overview file is in $(BUILDDIR)/changes." 167 | 168 | linkcheck: 169 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck 170 | @echo 171 | @echo "Link check complete; look for any errors in the above output " \ 172 | "or in $(BUILDDIR)/linkcheck/output.txt." 173 | 174 | doctest: 175 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest 176 | @echo "Testing of doctests in the sources finished, look at the " \ 177 | "results in $(BUILDDIR)/doctest/output.txt." 178 | 179 | coverage: 180 | $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage 181 | @echo "Testing of coverage in the sources finished, look at the " \ 182 | "results in $(BUILDDIR)/coverage/python.txt." 183 | 184 | xml: 185 | $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml 186 | @echo 187 | @echo "Build finished. The XML files are in $(BUILDDIR)/xml." 188 | 189 | pseudoxml: 190 | $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml 191 | @echo 192 | @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." 193 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # miau documentation build configuration file, created by 4 | # sphinx-quickstart on Thu May 28 01:22:58 2015. 5 | # 6 | # This file is execfile()d with the current directory set to its 7 | # containing dir. 8 | # 9 | # Note that not all possible configuration values are present in this 10 | # autogenerated file. 11 | # 12 | # All configuration values have a default; values that are commented out 13 | # serve to show the default. 14 | 15 | import sys 16 | import os 17 | import shlex 18 | 19 | # If extensions (or modules to document with autodoc) are in another directory, 20 | # add these directories to sys.path here. If the directory is relative to the 21 | # documentation root, use os.path.abspath to make it absolute, like shown here. 22 | #sys.path.insert(0, os.path.abspath('.')) 23 | 24 | # -- General configuration ------------------------------------------------ 25 | 26 | # If your documentation needs a minimal Sphinx version, state it here. 27 | #needs_sphinx = '1.0' 28 | 29 | # Add any Sphinx extension module names here, as strings. They can be 30 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 31 | # ones. 32 | extensions = [ 33 | 'sphinx.ext.autodoc', 34 | 'sphinx.ext.viewcode', 35 | ] 36 | 37 | # Add any paths that contain templates here, relative to this directory. 38 | templates_path = ['_templates'] 39 | 40 | # The suffix(es) of source filenames. 41 | # You can specify multiple suffix as a list of string: 42 | # source_suffix = ['.rst', '.md'] 43 | source_suffix = '.txt' 44 | 45 | # The encoding of source files. 46 | #source_encoding = 'utf-8-sig' 47 | 48 | # The master toctree document. 49 | master_doc = 'index' 50 | 51 | # General information about the project. 52 | project = u'miau' 53 | copyright = u'2015, Martín Gaitán' 54 | author = u'Martín Gaitán' 55 | 56 | # The version info for the project you're documenting, acts as replacement for 57 | # |version| and |release|, also used in various other places throughout the 58 | # built documents. 59 | # 60 | # The short X.Y version. 61 | version = '0.1.0' 62 | # The full version, including alpha/beta/rc tags. 63 | release = '0.1.0' 64 | 65 | # The language for content autogenerated by Sphinx. Refer to documentation 66 | # for a list of supported languages. 67 | # 68 | # This is also used if you do content translation via gettext catalogs. 69 | # Usually you set "language" from the command line for these cases. 70 | language = None 71 | 72 | # There are two options for replacing |today|: either, you set today to some 73 | # non-false value, then it is used: 74 | #today = '' 75 | # Else, today_fmt is used as the format for a strftime call. 76 | #today_fmt = '%B %d, %Y' 77 | 78 | # List of patterns, relative to source directory, that match files and 79 | # directories to ignore when looking for source files. 80 | exclude_patterns = ['_build'] 81 | 82 | # The reST default role (used for this markup: `text`) to use for all 83 | # documents. 84 | #default_role = None 85 | 86 | # If true, '()' will be appended to :func: etc. cross-reference text. 87 | #add_function_parentheses = True 88 | 89 | # If true, the current module name will be prepended to all description 90 | # unit titles (such as .. function::). 91 | #add_module_names = True 92 | 93 | # If true, sectionauthor and moduleauthor directives will be shown in the 94 | # output. They are ignored by default. 95 | #show_authors = False 96 | 97 | # The name of the Pygments (syntax highlighting) style to use. 98 | pygments_style = 'sphinx' 99 | 100 | # A list of ignored prefixes for module index sorting. 101 | #modindex_common_prefix = [] 102 | 103 | # If true, keep warnings as "system message" paragraphs in the built documents. 104 | #keep_warnings = False 105 | 106 | # If true, `todo` and `todoList` produce output, else they produce nothing. 107 | todo_include_todos = False 108 | 109 | 110 | # -- Options for HTML output ---------------------------------------------- 111 | 112 | # The theme to use for HTML and HTML Help pages. See the documentation for 113 | # a list of builtin themes. 114 | html_theme = 'alabaster' 115 | 116 | # Theme options are theme-specific and customize the look and feel of a theme 117 | # further. For a list of options available for each theme, see the 118 | # documentation. 119 | #html_theme_options = {} 120 | 121 | # Add any paths that contain custom themes here, relative to this directory. 122 | #html_theme_path = [] 123 | 124 | # The name for this set of Sphinx documents. If None, it defaults to 125 | # " v documentation". 126 | #html_title = None 127 | 128 | # A shorter title for the navigation bar. Default is the same as html_title. 129 | #html_short_title = None 130 | 131 | # The name of an image file (relative to this directory) to place at the top 132 | # of the sidebar. 133 | #html_logo = None 134 | 135 | # The name of an image file (within the static path) to use as favicon of the 136 | # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 137 | # pixels large. 138 | #html_favicon = None 139 | 140 | # Add any paths that contain custom static files (such as style sheets) here, 141 | # relative to this directory. They are copied after the builtin static files, 142 | # so a file named "default.css" will overwrite the builtin "default.css". 143 | html_static_path = ['_static'] 144 | 145 | # Add any extra paths that contain custom files (such as robots.txt or 146 | # .htaccess) here, relative to this directory. These files are copied 147 | # directly to the root of the documentation. 148 | #html_extra_path = [] 149 | 150 | # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, 151 | # using the given strftime format. 152 | #html_last_updated_fmt = '%b %d, %Y' 153 | 154 | # If true, SmartyPants will be used to convert quotes and dashes to 155 | # typographically correct entities. 156 | #html_use_smartypants = True 157 | 158 | # Custom sidebar templates, maps document names to template names. 159 | #html_sidebars = {} 160 | 161 | # Additional templates that should be rendered to pages, maps page names to 162 | # template names. 163 | #html_additional_pages = {} 164 | 165 | # If false, no module index is generated. 166 | #html_domain_indices = True 167 | 168 | # If false, no index is generated. 169 | #html_use_index = True 170 | 171 | # If true, the index is split into individual pages for each letter. 172 | #html_split_index = False 173 | 174 | # If true, links to the reST sources are added to the pages. 175 | #html_show_sourcelink = True 176 | 177 | # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. 178 | #html_show_sphinx = True 179 | 180 | # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. 181 | #html_show_copyright = True 182 | 183 | # If true, an OpenSearch description file will be output, and all pages will 184 | # contain a tag referring to it. The value of this option must be the 185 | # base URL from which the finished HTML is served. 186 | #html_use_opensearch = '' 187 | 188 | # This is the file name suffix for HTML files (e.g. ".xhtml"). 189 | #html_file_suffix = None 190 | 191 | # Language to be used for generating the HTML full-text search index. 192 | # Sphinx supports the following languages: 193 | # 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja' 194 | # 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr' 195 | #html_search_language = 'en' 196 | 197 | # A dictionary with options for the search language support, empty by default. 198 | # Now only 'ja' uses this config value 199 | #html_search_options = {'type': 'default'} 200 | 201 | # The name of a javascript file (relative to the configuration directory) that 202 | # implements a search results scorer. If empty, the default will be used. 203 | #html_search_scorer = 'scorer.js' 204 | 205 | # Output file base name for HTML help builder. 206 | htmlhelp_basename = 'cookiecutterapp_namedoc' 207 | 208 | # -- Options for LaTeX output --------------------------------------------- 209 | 210 | latex_elements = { 211 | # The paper size ('letterpaper' or 'a4paper'). 212 | #'papersize': 'letterpaper', 213 | 214 | # The font size ('10pt', '11pt' or '12pt'). 215 | #'pointsize': '10pt', 216 | 217 | # Additional stuff for the LaTeX preamble. 218 | #'preamble': '', 219 | 220 | # Latex figure (float) alignment 221 | #'figure_align': 'htbp', 222 | } 223 | 224 | # Grouping the document tree into LaTeX files. List of tuples 225 | # (source start file, target name, title, 226 | # author, documentclass [howto, manual, or own class]). 227 | latex_documents = [ 228 | (master_doc, 'cookiecutterapp_name.tex', u'\\{\\{ cookiecutter.app\\_name \\}\\} Documentation', 229 | u'\\{\\{ cookiecutter.full\\_name \\}\\}', 'manual'), 230 | ] 231 | 232 | # The name of an image file (relative to this directory) to place at the top of 233 | # the title page. 234 | #latex_logo = None 235 | 236 | # For "manual" documents, if this is true, then toplevel headings are parts, 237 | # not chapters. 238 | #latex_use_parts = False 239 | 240 | # If true, show page references after internal links. 241 | #latex_show_pagerefs = False 242 | 243 | # If true, show URL addresses after external links. 244 | #latex_show_urls = False 245 | 246 | # Documents to append as an appendix to all manuals. 247 | #latex_appendices = [] 248 | 249 | # If false, no module index is generated. 250 | #latex_domain_indices = True 251 | 252 | 253 | # -- Options for manual page output --------------------------------------- 254 | 255 | # One entry per manual page. List of tuples 256 | # (source start file, name, description, authors, manual section). 257 | man_pages = [ 258 | (master_doc, 'cookiecutterapp_name', u'miau Documentation', 259 | [author], 1) 260 | ] 261 | 262 | # If true, show URL addresses after external links. 263 | #man_show_urls = False 264 | 265 | 266 | # -- Options for Texinfo output ------------------------------------------- 267 | 268 | # Grouping the document tree into Texinfo files. List of tuples 269 | # (source start file, target name, title, author, 270 | # dir menu entry, description, category) 271 | texinfo_documents = [ 272 | (master_doc, 'cookiecutterapp_name', u'miau Documentation', 273 | author, 'cookiecutterapp_name', 'One line description of project.', 274 | 'Miscellaneous'), 275 | ] 276 | 277 | # Documents to append as an appendix to all manuals. 278 | #texinfo_appendices = [] 279 | 280 | # If false, no module index is generated. 281 | #texinfo_domain_indices = True 282 | 283 | # How to display URL addresses: 'footnote', 'no', or 'inline'. 284 | #texinfo_show_urls = 'footnote' 285 | 286 | # If true, do not generate a @detailmenu in the "Top" node's menu. 287 | #texinfo_no_detailmenu = False 288 | -------------------------------------------------------------------------------- /miau.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """ 3 | Miau: Remix speeches for fun and profit 4 | 5 | Usage: 6 | miau ... -r [-o -d --lang --debug] 7 | miau -h | --help 8 | miau --version 9 | 10 | Options: 11 | Input files patterns (clip/s and its transcripts) 12 | -r --remix Script text (txt or json) 13 | -d --dump Dump remix as json. 14 | Can be loaded with -r to reuse the aligment. 15 | -o --output Output filename (default to mp4 with remix's basename) 16 | -h --help Show this screen. 17 | --lang Set language (2-letter code) for inputs (default autodetect) 18 | --version Show version. 19 | """ 20 | 21 | from collections import OrderedDict 22 | import glob 23 | from itertools import chain 24 | import json 25 | import logging 26 | import os 27 | import re 28 | import tempfile 29 | 30 | from aeneas.tools.execute_task import ExecuteTaskCLI 31 | from docopt import docopt, DocoptExit 32 | import langdetect 33 | from moviepy.editor import ( 34 | VideoFileClip, AudioFileClip, 35 | concatenate_videoclips, concatenate_audioclips 36 | ) 37 | from moviepy.tools import extensions_dict 38 | 39 | 40 | VERSION = '0.1' 41 | 42 | OFFSET_PATTERN = re.compile('^(?P(\+|\-)+)?(?P.*?)(?P(\+|\-)+)?$') 43 | 44 | logging.basicConfig(format='[miau] %(asctime)s %(levelname)s: %(message)s', 45 | level=10, 46 | datefmt='%Y-%m-%d %H:%M:%S') 47 | 48 | 49 | def fragmenter(source, remix_lines, debug=False): 50 | """ 51 | return as many versions of the source text 52 | wrapped to ensure each remix verse (that exist on the source) 53 | appears as an independent line at least once as an 54 | independent line (if it exists) 55 | 56 | >>> fragmenter('I have a dream that one day this nation will rise up ' 57 | 'and live out the true meaning of its creed', 58 | ['I have a dream', 59 | 'out the true', # this two lines fit in the first iteration 60 | 'the true meaning', # but this requires a new one due repeat a part of verse 61 | 'that all men are created equal'] # and this one is returned as not found. 62 | ) 63 | (['\nI have a dream\nthat one day this nation will rise up and live \nout the true\nmeaning of its creed', 64 | 'I have a dream that one day this nation will rise up and live out \nthe true meaning\nof its creed'], 65 | ['that all men are created equal']) 66 | 67 | 68 | """ 69 | 70 | # fragments not present in this source. 71 | not_found_on_source = [] 72 | for line in remix_lines: 73 | if line not in source: 74 | not_found_on_source.append(line) 75 | 76 | def iterate(lines): 77 | 78 | current = source 79 | not_found = [] 80 | for line in lines: 81 | if line in not_found_on_source: 82 | continue 83 | 84 | if line not in current: 85 | not_found.append(line) 86 | continue 87 | current = current.replace(line, '\n{}\n'.format(line)) 88 | current = current.replace('\n ', '\n').replace('\n\n', '\n') 89 | return current, not_found 90 | 91 | results = [] 92 | count = 1 93 | while True: 94 | logging.info('Fragmenting source. Iteration %s', count) 95 | result, not_found = iterate(remix_lines) 96 | if debug: 97 | d = tempfile.mkstemp(suffix='-iter{}.txt'.format(count))[1] 98 | logging.debug('Writing fragmented source to {}'.format(d)) 99 | with open(d, 'w') as _t: 100 | _t.write(result) 101 | count += 1 102 | results.append(result) 103 | if not not_found: 104 | # finish, as all remix lines were found 105 | break 106 | remix_lines = not_found 107 | 108 | return results, not_found_on_source 109 | 110 | 111 | def fine_tuning(raw_line, offset_step=0.05): 112 | """given raw line potentially having symbols + or - 113 | at the beginning or the end, 114 | 115 | return of the cleaned line, start_offset, end_offset 116 | 117 | each symbol is equivalent to an ``offset_step`` (in seconds), 118 | positive or negative, which are applied to the segment cut then 119 | 120 | >>> fine_tuning('++this is a line---'): 121 | {'this is a line': {'start_offset': 0.1, 'end_offset': -0.15}} 122 | """ 123 | def _offset(symbols): 124 | if not symbols: 125 | return 0 126 | sign = int('{}1'.format(symbols[0])) 127 | return len(symbols) * offset_step * sign 128 | 129 | result = re.match(OFFSET_PATTERN, raw_line).groupdict() 130 | line = result.pop('line').strip() 131 | return {line: {k: _offset(v) for k, v in result.items()}} 132 | 133 | 134 | def make_remix(remix_data, mvp_clips, output_type): 135 | """ 136 | Return the moviepy clip resulting of concatenate each 137 | segment listed in the remix data 138 | 139 | :param remix_data: list of verses with its metadata to cut from:: 140 | 141 | [('line on remix': {'begin': start, 'end': end, 'clip': file}), ...] 142 | 143 | :param mvp_clips: dictionary of filename: {moviepy's clip} 144 | :param output_type: ``'audio'`` or ``'video'`` 145 | """ 146 | concatenate = ( 147 | concatenate_videoclips if output_type == 'video' else concatenate_audioclips 148 | ) 149 | segments = [] 150 | for _, segment_data in remix_data: 151 | clip = mvp_clips[segment_data['clip']] 152 | segment = clip.subclip(segment_data['begin'], segment_data['end']) 153 | segments.append(segment) 154 | 155 | return concatenate(segments) 156 | 157 | 158 | def get_fragments_database(mvp_clips, transcripts, remix, debug=False, force_language=None): 159 | """ 160 | generate a dictionary containing segment information for every 161 | line produced by :func:`fragmenter` 162 | 163 | :parameter clips: list of input clip filenames 164 | :parameter transcripts: raw texts of transcripts. map one-one to clips 165 | :remix: list of remix lines dictionaries as returned by :func:`fine_tuning` 166 | 167 | """ 168 | sources_by_clip = OrderedDict() 169 | remix_lines = list(remix.keys()) 170 | 171 | # 172 | for clip, transcript in zip(mvp_clips, transcripts): 173 | transcript = open(transcript).read().replace('\n', ' ').replace(' ', ' ') 174 | sources_by_clip[clip], remix_lines = fragmenter(transcript, remix_lines, debug=debug) 175 | if not remix_lines: 176 | break 177 | else: 178 | if remix_lines: 179 | raise ValueError( 180 | "Remix verse/s not found in transcripts given:\n{}".format('\n- '.join(remix_lines)) 181 | ) 182 | 183 | # create Task object 184 | 185 | fragments = OrderedDict() 186 | for clip, sources in sources_by_clip.items(): 187 | l_sources = len(sources) 188 | for i, source in enumerate(sources, 1): 189 | if force_language: 190 | language = force_language 191 | elif i == 1: 192 | # for first iteration of the clip, autodetect the language 193 | snippet = source[:source.index(' ', 100)] 194 | language = langdetect.detect(snippet) 195 | logging.info("Autodetected language for %s: %s", clip, language) 196 | 197 | config_string = u"task_language={}|is_text_type=plain|os_task_file_format=json".format(language) 198 | with tempfile.NamedTemporaryFile('w', delete=False) as f_in: 199 | f_in.write(source) 200 | output_json = '{}.json'.format(f_in.name) 201 | logging.info('Forcing aligment for %s (step %s/%s)', clip, i, l_sources) 202 | ExecuteTaskCLI(use_sys=False).run(arguments=[ 203 | None, 204 | os.path.abspath(clip), 205 | f_in.name, 206 | config_string, 207 | output_json 208 | ]) 209 | output = json.load(open(output_json)) 210 | for f in output['fragments']: 211 | line = f['lines'][0] 212 | try: 213 | offset_begin = remix[line]['offset_begin'] 214 | offset_end = remix[line]['offset_end'] 215 | except KeyError: 216 | offset_begin = 0 217 | offset_end = 0 218 | 219 | fragments[line] = { 220 | 'begin': float(f['begin']) + offset_begin, 221 | 'end': float(f['end']) + offset_end, 222 | 'clip': clip 223 | } 224 | if debug: 225 | d = tempfile.mkstemp(suffix='.json')[1] 226 | json.dump(fragments, open(d, 'w'), indent=2) 227 | logging.debug('Segments database written to {}'.format(d)) 228 | return fragments 229 | 230 | 231 | def ensure_audio(clip): 232 | if isinstance(clip, AudioFileClip): 233 | return clip 234 | elif isinstance(clip, VideoFileClip): 235 | return clip.audio 236 | 237 | 238 | def miau(clips, transcripts, remix, output_file=None, dump=None, debug=False, 239 | force_language=None): 240 | """Main miau entrypoint 241 | 242 | :param clips: list of audio/video files (as supported by moviepy). 243 | :param transcripts: list of transcriptions filenames, in the 244 | same order of ``clips``. 245 | :param remix: remix filename. Could be a raw text or a json file as 246 | generated by ``dump`` option. If it's a json, forced 247 | aligment is skipped. 248 | :param output_file: filename of the generated audio/video file. Format 249 | is inferred from the extension. 250 | :param dump: if ``True``, generate a json file that can replace the 251 | text based remix, useful for a manual tuning. 252 | :param debug: verbose output if ``True``. 253 | :param forced_language: By default language is inferred from a portion 254 | of each transcript. If a 2-letter language code 255 | is passed, it overrides that. 256 | """ 257 | if not output_file: 258 | # default to a video with the same filename than the remix 259 | output_file = '{}.mp4'.format(os.path.basename(remix).rsplit('.')[0]) 260 | output_extension = os.path.splitext(output_file)[1][1:] 261 | if output_extension not in extensions_dict: 262 | raise ValueError( 263 | 'Output format not supported: {}'.format(output_extension) 264 | ) 265 | output_type = extensions_dict[output_extension]['type'] 266 | 267 | # map input files to moviepy clips 268 | mvp_clips = OrderedDict() 269 | for filename in clips: 270 | try: 271 | clip = VideoFileClip(filename) 272 | except KeyError: 273 | clip = AudioFileClip(filename) 274 | mvp_clips[filename] = clip 275 | 276 | if output_type == 'video' and not all(isinstance(clip, VideoFileClip) for clip in mvp_clips.values()): 277 | logging.error("Output expect to be a video but input clips aren't all videos") 278 | return 279 | elif output_type == 'audio': 280 | # cast clips to audio if needed 281 | mvp_clips = OrderedDict([(k, ensure_audio(v)) for k, v in mvp_clips.items()]) 282 | 283 | with open(remix) as remix_fh: 284 | try: 285 | # read data from a json file (as generated by --dump option) 286 | # this skip the aligment 287 | remix_data = json.load(remix_fh) 288 | except json.JSONDecodeError: 289 | remix_fh.seek(0) 290 | remix_lines = OrderedDict() 291 | for l in remix_fh: 292 | l = l.strip() 293 | if not l or l.startswith('#'): 294 | continue 295 | remix_lines.update(fine_tuning(l)) 296 | fragments = get_fragments_database( 297 | clips, transcripts, remix_lines, 298 | debug=debug, force_language=force_language 299 | ) 300 | remix_data = [(l, fragments[l]) for l in remix_lines] 301 | 302 | if dump: 303 | logging.info('Dumping remix data in %s', dump) 304 | json.dump(remix_data, open(dump, 'w'), indent=2) 305 | 306 | output_clip = make_remix(remix_data, mvp_clips, output_type) 307 | method = 'write_videofile' if output_type == 'video' else 'write_audiofile' 308 | logging.info('Creating output file') 309 | getattr(output_clip, method)(output_file) 310 | 311 | 312 | def main(args=None): 313 | args = docopt(__doc__, argv=args, version=VERSION) 314 | 315 | # from the whole input bag, split media files from transcriptions 316 | # media and its transcript must be paired (i.e same order) 317 | # for example, supose a folder with a video file macri_gato.mp4 and 318 | # its transcription is macri_gato.txt 319 | # 320 | # *.mp4 *.txt 321 | # macri_gato.* 322 | # macri_gato.mp4 macri_gato.txt 323 | media = [] 324 | transcripts = [] 325 | for filename in chain.from_iterable(glob.iglob(pattern) for pattern in args['']): 326 | output_extension = os.path.splitext(filename)[1][1:] 327 | if output_extension in extensions_dict: 328 | media.append(filename) 329 | else: 330 | transcripts.append(filename) 331 | 332 | media_str = ' \n'.join(media) 333 | transcripts_str = ' \n'.join(transcripts) 334 | info = "Audio/Video:\n {}\nTranscripts/subtitle:\n {}".format(media_str, transcripts_str) 335 | logging.info(info) 336 | if not media or len(media) != len(transcripts): 337 | raise DocoptExit( 338 | "Input mismatch: the quantity of inputs and transcriptions differs" 339 | ) 340 | 341 | try: 342 | return miau( 343 | media, 344 | transcripts, 345 | args['--remix'], 346 | args['--output'], 347 | args['--dump'], 348 | debug=args['--debug'], 349 | force_language=args['--lang'] 350 | ) 351 | except ValueError as e: 352 | raise DocoptExit(str(e)) 353 | 354 | if __name__ == '__main__': 355 | main() --------------------------------------------------------------------------------