Get karaoke ass generator from negromate.web, add date to songs
This commit is contained in:
parent
ed5990900b
commit
2f135fed6b
|
@ -1,10 +1,14 @@
|
|||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from ..loader import load_songs
|
||||
|
||||
name = 'songs'
|
||||
help_text = 'Update song database'
|
||||
initial_config = {
|
||||
'generate': 'yes',
|
||||
'regenerate': 'no',
|
||||
'karaoke_template_file': '~/negro_mate/karaoke_templates/karaoke.ass',
|
||||
}
|
||||
|
||||
|
||||
def options(parser, config, **kwargs):
|
||||
|
@ -13,10 +17,31 @@ def options(parser, config, **kwargs):
|
|||
default=config['global']['song_folder'],
|
||||
help="Folder with the song database, defaults to {}".format(
|
||||
config['global']['song_folder']))
|
||||
parser.add_argument(
|
||||
'-g', '--generate', action='store_const', const='yes',
|
||||
default=config['songs']['generate'],
|
||||
help="Generate missing files, defaults to {}".format(
|
||||
config['songs']['generate']))
|
||||
parser.add_argument(
|
||||
'-r', '--regenerate', action='store_const', const='yes',
|
||||
default=config['songs']['regenerate'],
|
||||
help="Regenerate missing files, defaults to {}".format(
|
||||
config['songs']['regenerate']))
|
||||
parser.add_argument(
|
||||
'-k', '--karaoke-template', type=Path,
|
||||
default=config['songs']['karaoke_template_file'],
|
||||
help="Ass file with the karaoke template, defaults to {}".format(
|
||||
config['songs']['karaoke_template_file']))
|
||||
|
||||
|
||||
def run(args, **kwargs):
|
||||
songs, pending_songs = load_songs(args.song_folder.expanduser())
|
||||
generate = args.generate == 'yes'
|
||||
regenerate = args.regenerate == 'yes'
|
||||
songs, pending_songs = load_songs(
|
||||
root_folder=args.song_folder.expanduser(),
|
||||
generate=generate, regenerate=regenerate,
|
||||
karaoke_template_file=args.karaoke_template.expanduser())
|
||||
|
||||
print(
|
||||
"#######\n"
|
||||
" Songs\n"
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
import os
|
||||
import subprocess
|
||||
import time
|
||||
from contextlib import contextmanager
|
||||
|
||||
import ass
|
||||
|
||||
|
||||
@contextmanager
|
||||
def Xephyr_env(display=":2", *args, **kwargs):
|
||||
env = os.environ.copy()
|
||||
xephyr = subprocess.Popen(["Xephyr", display], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
||||
env['DISPLAY'] = display
|
||||
try:
|
||||
yield env
|
||||
finally:
|
||||
xephyr.kill()
|
||||
|
||||
|
||||
def set_template(template_subtitles, orig_file, target_file=None):
|
||||
if target_file is None:
|
||||
target_file = orig_file
|
||||
|
||||
with open(orig_file, 'r') as orig:
|
||||
subtitles = ass.parse(orig)
|
||||
|
||||
new_events = []
|
||||
for dialogue in template_subtitles.events:
|
||||
new_events.append(dialogue)
|
||||
|
||||
for dialogue in subtitles.events:
|
||||
if dialogue.effect.startswith('code'):
|
||||
continue
|
||||
if dialogue.effect.startswith('template'):
|
||||
continue
|
||||
new_events.append(dialogue)
|
||||
|
||||
subtitles.events = new_events
|
||||
|
||||
with open(target_file, 'w', encoding='utf-8-sig') as target:
|
||||
subtitles.dump_file(target)
|
||||
|
||||
|
||||
def run(command, env, wait=None):
|
||||
subprocess.Popen(
|
||||
command,
|
||||
env=env,
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL,
|
||||
)
|
||||
if wait is not None:
|
||||
time.sleep(wait)
|
||||
|
||||
|
||||
def apply_template(subtitles, env):
|
||||
run(["aegisub-3.2", subtitles], env=env, wait=2)
|
||||
|
||||
# Si pide confirmación para cargar video ignorar el popup
|
||||
run(["xdotool", "key", "Escape"], env=env, wait=0.1)
|
||||
|
||||
# abrir el menú de automatización, bajar dos y darle a aplicar template
|
||||
run(["xdotool", "key", "alt+u"], env=env, wait=0.1)
|
||||
run(["xdotool", "key", "Down"], env=env, wait=0.1)
|
||||
run(["xdotool", "key", "Down"], env=env, wait=0.1)
|
||||
run(["xdotool", "key", "Return"], env=env, wait=2)
|
||||
|
||||
# guardar
|
||||
run(["xdotool", "key", "ctrl+s"], env=env)
|
||||
|
||||
# cerrar programa
|
||||
run(["xdotool", "key", "ctrl+q"], env=env)
|
||||
|
||||
|
||||
def update_karaoke_songs(songs, template_file, regenerate=False):
|
||||
from negromate.songs.utils import needs_change
|
||||
|
||||
with open(template_file, 'r') as template:
|
||||
template_subtitles = ass.parse(template)
|
||||
|
||||
with Xephyr_env() as env:
|
||||
for song in songs:
|
||||
if song.metadata.get('karaoke'):
|
||||
target = song.path / "{}.karaoke.ass".format(song.path.name)
|
||||
if regenerate or needs_change(target, (song.ass, template_file)):
|
||||
set_template(
|
||||
template_subtitles=template_subtitles,
|
||||
orig_file=str(song.ass),
|
||||
target_file=str(target)
|
||||
)
|
||||
time.sleep(2)
|
||||
apply_template(str(target), env)
|
||||
time.sleep(2)
|
|
@ -1,10 +1,9 @@
|
|||
import json
|
||||
|
||||
import asstosrt
|
||||
import srt
|
||||
import webvtt
|
||||
|
||||
from .utils import needs_change, generate_cover, generate_thumbnail
|
||||
from .utils import needs_change, generate_cover, generate_thumbnail, generate_karaoke_ass
|
||||
from . import logger
|
||||
|
||||
|
||||
|
@ -14,6 +13,7 @@ class Song:
|
|||
self.metadata = None
|
||||
self.original = None
|
||||
self.author = None
|
||||
self.date = None
|
||||
self.path = path
|
||||
self.root = root
|
||||
self.video = None
|
||||
|
@ -38,6 +38,8 @@ class Song:
|
|||
self.original = self.metadata['original']
|
||||
if 'author' in self.metadata:
|
||||
self.author = self.metadata['author']
|
||||
if 'date' in self.metadata:
|
||||
self.date = self.metadata['date']
|
||||
elif entry.name.endswith('mp4'):
|
||||
self.video = entry
|
||||
self.video_type = 'video/mp4'
|
||||
|
@ -70,28 +72,43 @@ class Song:
|
|||
else:
|
||||
self.files.append(entry)
|
||||
|
||||
srt = self.path / "{}.srt".format(self.path.name)
|
||||
if needs_change(srt, (self.ass,)):
|
||||
self.srt = srt
|
||||
def generate_missing(self, regenerate=False, karaoke_template_file=None):
|
||||
srt_ = self.path / "{}.srt".format(self.path.name)
|
||||
if regenerate or needs_change(srt_, (self.ass,)):
|
||||
logger.info("generating {}".format(srt_))
|
||||
self.srt = srt_
|
||||
with self.ass.open('r') as assfile, self.srt.open('w') as srtfile:
|
||||
srtfile.write(asstosrt.convert(assfile))
|
||||
self.files.append(self.srt)
|
||||
|
||||
vtt = self.path / "{}.vtt".format(self.path.name)
|
||||
if needs_change(vtt, (self.srt,)):
|
||||
if regenerate or needs_change(vtt, (self.srt,)):
|
||||
logger.info("generating {}".format(vtt))
|
||||
self.vtt = vtt
|
||||
webvtt.from_srt(str(self.srt.absolute())).save(str(self.vtt.absolute()))
|
||||
|
||||
cover = self.path / "cover.jpg"
|
||||
if needs_change(cover, (self.video,)):
|
||||
if regenerate or needs_change(cover, (self.video,)):
|
||||
logger.info("generating {}".format(cover))
|
||||
self.cover = cover
|
||||
generate_cover(self.video, self.cover)
|
||||
generate_cover(self.video, self.cover)
|
||||
|
||||
thumbnail = self.path / "thumb.jpg"
|
||||
if needs_change(thumbnail, (self.cover,)):
|
||||
if regenerate or needs_change(thumbnail, (self.cover,)):
|
||||
logger.info("generating {}".format(thumbnail))
|
||||
self.thumbnail = thumbnail
|
||||
generate_thumbnail(self.cover, self.thumbnail)
|
||||
|
||||
karaoke_ass = self.path / "{}.karaoke.ass".format(self.path.name)
|
||||
karaoke_requirements = (
|
||||
self.metadata.get('karaoke', False),
|
||||
regenerate or needs_change(karaoke_ass, (self.ass, karaoke_template_file)),
|
||||
)
|
||||
if all(karaoke_requirements):
|
||||
logger.info("generating {}".format(karaoke_ass))
|
||||
self.karaoke_ass = karaoke_ass
|
||||
generate_karaoke_ass(str(karaoke_template_file), str(self.ass), str(karaoke_ass))
|
||||
|
||||
@property
|
||||
def publish(self):
|
||||
has_subtitles = self.ass or self.srt or self.vtt
|
||||
|
@ -99,7 +116,7 @@ class Song:
|
|||
return has_video and has_subtitles
|
||||
|
||||
|
||||
def load_songs(root_folder):
|
||||
def load_songs(root_folder, generate=True, regenerate=False, karaoke_template_file=None):
|
||||
songs = []
|
||||
pending_songs = []
|
||||
for entry in root_folder.iterdir():
|
||||
|
@ -109,6 +126,8 @@ def load_songs(root_folder):
|
|||
logger.info("building {}".format(entry.name))
|
||||
try:
|
||||
song = Song(entry, root_folder)
|
||||
if generate:
|
||||
song.generate_missing(regenerate, karaoke_template_file)
|
||||
except Exception as e:
|
||||
logger.error("Error: %s", e)
|
||||
continue
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
import subprocess
|
||||
import ass
|
||||
import time
|
||||
|
||||
from . import karaoke_templates
|
||||
|
||||
|
||||
def needs_change(destination, dependencies):
|
||||
|
@ -7,7 +11,7 @@ def needs_change(destination, dependencies):
|
|||
if dependency is None:
|
||||
return False
|
||||
last_dependency_change = max(
|
||||
last_dependency_change,
|
||||
last_dependency_change,
|
||||
dependency.lstat().st_mtime
|
||||
)
|
||||
|
||||
|
@ -41,3 +45,18 @@ def generate_thumbnail(cover, thumbnail, geometry="200x200"):
|
|||
str(thumbnail.absolute()),
|
||||
]
|
||||
subprocess.check_call(command)
|
||||
|
||||
|
||||
def generate_karaoke_ass(template_file, orig_file, target_file):
|
||||
with open(template_file, 'r') as template:
|
||||
template_subtitles = ass.parse(template)
|
||||
|
||||
with karaoke_templates.Xephyr_env() as env:
|
||||
karaoke_templates.set_template(
|
||||
template_subtitles=template_subtitles,
|
||||
orig_file=orig_file,
|
||||
target_file=target_file,
|
||||
)
|
||||
time.sleep(2)
|
||||
karaoke_templates.apply_template(target_file, env)
|
||||
time.sleep(2)
|
||||
|
|
Loading…
Reference in New Issue