Merge branch 'master' into meson-vs2019

This commit is contained in:
odrling 2020-11-17 19:38:05 +01:00
commit 6907ea2c62
78 changed files with 8028 additions and 466 deletions

View File

@ -0,0 +1,14 @@
#!/bin/bash
dest="ftp://shelter.mahoro-net.org/aegisub-japan7"
tag=$(git describe --exact-match)
[ "$tag" ] || exit
curl -T 'packages\win_installer\output\Aegisub-Japan7-x64.exe' --user $FTP_USER:$FTP_PASS "$dest/Aegisub-Japan7-${tag#v}-x64.exe"
printf "${tag#v}\n$(git tag -l --format='%(contents)' $tag)" > latest
curl -T latest --user "$FTP_USER:$FTP_PASS" "$dest/"
url="Aegisub-Japan7-${tag#v}-x64.exe"
printf "<!doctype html><html><head><meta http-equiv='refresh' content='0; url=$url' /></head><body><a href='$url'>$url</a></body></html>" > Aegisub-Japan7-latest-x64
curl -T Aegisub-Japan7-latest-x64 --user "$FTP_USER:$FTP_PASS" "$dest/"

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "subprojects/japan7-fonts"]
path = subprojects/japan7-fonts
url = https://github.com/odrling/japan7-fonts.git

View File

@ -1,18 +1,24 @@
# Aegisub
# Aegisub-Japan7
For binaries and general information [see the homepage](http://www.aegisub.org).
[![Build status](https://ci.appveyor.com/api/projects/status/5huyx72x00ytp845/branch/master?svg=true)](https://ci.appveyor.com/project/odrling/aegisub/branch/master)
The bug tracker can be found at http://devel.aegisub.org.
## Installation
Support is available on [the forums](http://forum.aegisub.org) or [on IRC](irc://irc.rizon.net/aegisub).
The latest Windows build can be downloaded at https://mugen.karaokes.moe/downloads/aegisub-japan7/Aegisub-Japan7-latest-x64
## Building Aegisub
A package is available on the AUR for Arch Linux users: [aegisub-japan7-git](https://aur.archlinux.org/packages/aegisub-japan7-git/)
An ebuild is available for Gentoo users at https://git.odrling.xyz/odrling/odrling-overlay/src/branch/master/media-video/aegisub/aegisub-9999.ebuild
The default style uses the [Amaranth font](https://github.com/googlefonts/amaranth), which is installed by default when installing from the sources above.
## Building Aegisub-Japan7
### Windows
Prerequisites:
1. Visual Studio 2015 (the free Community edition is good enough)
1. Visual Studio 2017 (the free Community edition is good enough)
2. The June 2010 DirectX SDK (the final release before DirectSound was dropped)
3. [Yasm](http://yasm.tortall.net/) installed to somewhere on your path.
@ -81,6 +87,42 @@ wxWidgets is located in vendor/wxWidgets, and can be built like so:
Once the dependencies are installed, build Aegisub with `autoreconf && ./configure --with-wxdir=/path/to/Aegisub/vendor/wxWidgets && make && make osx-bundle`.
`autoreconf` should be skipped if you are building from a source tarball rather than `git`.
### Linux, BSD or Toasters
Install all the dependencies with the package manager of your distribution:
wxGTK
boost
icu
ffmpegsource
fontconfig
freetype
libass
zlib
libiconv
opengl
openal
openssl or libressl
Optional dependencies:
alsa-lib
fftw
openal
portaudio
pulseaudio
hunspell
luajit (can be bundled with your build)
Once all the dependencies are installed, run:
```bash
./autogen.sh
./configure
make -j$(nproc)
```
## Updating Moonscript
From within the Moonscript repository, run `bin/moon bin/splat.moon -l moonscript moonscript/ > bin/moonscript.lua`.

87
appveyor.yml Normal file
View File

@ -0,0 +1,87 @@
image: Visual Studio 2017
install:
- cd %APPVEYOR_BUILD_FOLDER%
- git submodule update --init --recursive
- curl -O https://mugen.karaokes.moe/downloads/aegisub-japan7/openssl-aegisub.zip
- set PATH=C:\gettext\bin;"C:\Program Files (x86)\Inno Setup 5";C:\yasm;%PATH%
- mkdir C:\yasm
- curl -o "C:\yasm\yasm.exe" http://www.tortall.net/projects/yasm/releases/yasm-1.3.0-win64.exe
- mkdir C:\gettext
- curl -L -o "C:\gettext.zip" https://github.com/vslavik/gettext-tools-windows/releases/download/v0.20.1/gettext-tools-windows-0.20.1.zip
- cd C:\gettext
- 7z x C:\gettext.zip
build_script:
- cd %APPVEYOR_BUILD_FOLDER%
- MSBuild.exe Aegisub.sln /target:BuildTasks
- 7z x openssl-aegisub.zip
- MSBuild.exe Aegisub.sln /m /p:Configuration=Release /p:Platform=x64
after_build:
- curl -o "C:\aegisub-codecs.zip" https://mugen.karaokes.moe/downloads/aegisub-codecs.zip
- cd %APPVEYOR_BUILD_FOLDER%
- msgfmt.exe -o po\ar.mo po\ar.po
- msgfmt.exe -o po\wxstd-ar.mo vendor\wxWidgets\locale\ar.po
- msgfmt.exe -o po\bg.mo po\bg.po
- msgfmt.exe -o po\ca.mo po\ca.po
- msgfmt.exe -o po\wxstd-ca.mo vendor\wxWidgets\locale\ca.po
- msgfmt.exe -o po\cs.mo po\cs.po
- msgfmt.exe -o po\wxstd-cs.mo vendor\wxWidgets\locale\cs.po
- msgfmt.exe -o po\da.mo po\da.po
- msgfmt.exe -o po\wxstd-da.mo vendor\wxWidgets\locale\da.po
- msgfmt.exe -o po\de.mo po\de.po
- msgfmt.exe -o po\wxstd-de.mo vendor\wxWidgets\locale\de.po
- msgfmt.exe -o po\el.mo po\el.po
- msgfmt.exe -o po\wxstd-el.mo vendor\wxWidgets\locale\el.po
- msgfmt.exe -o po\es.mo po\es.po
- msgfmt.exe -o po\wxstd-es.mo vendor\wxWidgets\locale\es.po
- msgfmt.exe -o po\eu.mo po\eu.po
- msgfmt.exe -o po\wxstd-eu.mo vendor\wxWidgets\locale\eu.po
- msgfmt.exe -o po\fa.mo po\fa.po
- msgfmt.exe -o po\fi.mo po\fi.po
- msgfmt.exe -o po\wxstd-fi.mo vendor\wxWidgets\locale\fi.po
- msgfmt.exe -o po\fr_FR.mo po\fr_FR.po
- msgfmt.exe -o po\wxstd-fr.mo vendor\wxWidgets\locale\fr.po
- msgfmt.exe -o po\gl.mo po\gl.po
- msgfmt.exe -o po\wxstd-gl_ES.mo vendor\wxWidgets\locale\gl_ES.po
- msgfmt.exe -o po\hu.mo po\hu.po
- msgfmt.exe -o po\wxstd-hu.mo vendor\wxWidgets\locale\hu.po
- msgfmt.exe -o po\id.mo po\id.po
- msgfmt.exe -o po\wxstd-id.mo vendor\wxWidgets\locale\id.po
- msgfmt.exe -o po\it.mo po\it.po
- msgfmt.exe -o po\wxstd-it.mo vendor\wxWidgets\locale\it.po
- msgfmt.exe -o po\ja.mo po\ja.po
- msgfmt.exe -o po\wxstd-ja.mo vendor\wxWidgets\locale\ja.po
- msgfmt.exe -o po\ko.mo po\ko.po
- msgfmt.exe -o po\wxstd-ko_KR.mo vendor\wxWidgets\locale\ko_KR.po
- msgfmt.exe -o po\nl.mo po\nl.po
- msgfmt.exe -o po\wxstd-nl.mo vendor\wxWidgets\locale\nl.po
- msgfmt.exe -o po\pl.mo po\pl.po
- msgfmt.exe -o po\wxstd-pl.mo vendor\wxWidgets\locale\pl.po
- msgfmt.exe -o po\pt_BR.mo po\pt_BR.po
- msgfmt.exe -o po\wxstd-pt_BR.mo vendor\wxWidgets\locale\pt_BR.po
- msgfmt.exe -o po\pt_PT.mo po\pt_PT.po
- msgfmt.exe -o po\wxstd-pt.mo vendor\wxWidgets\locale\pt.po
- msgfmt.exe -o po\ru.mo po\ru.po
- msgfmt.exe -o po\wxstd-ru.mo vendor\wxWidgets\locale\ru.po
- msgfmt.exe -o po\sr_RS.mo po\sr_RS.po
- msgfmt.exe -o po\sr_RS@latin.mo po\sr_RS@latin.po
- msgfmt.exe -o po\uk_UA.mo po\uk_UA.po
- msgfmt.exe -o po\wxstd-uk_UA.mo vendor\wxWidgets\locale\uk_UA.po
- msgfmt.exe -o po\vi.mo po\vi.po
- msgfmt.exe -o po\wxstd-vi.mo vendor\wxWidgets\locale\vi.po
- msgfmt.exe -o po\zh_CN.mo po\zh_CN.po
- msgfmt.exe -o po\wxstd-zh_CN.mo vendor\wxWidgets\locale\zh_CN.po
- msgfmt.exe -o po\zh_TW.mo po\zh_TW.po
- msgfmt.exe -o po\wxstd-zh_TW.mo vendor\wxWidgets\locale\zh_TW.po
- 7z x "C:\aegisub-codecs.zip"
- cd packages\win_installer
- iscc aegisub3.iss
- cd ..\..
on_success:
- IF DEFINED APPVEYOR_REPO_TAG_NAME bash.exe ".ci\upload_win_installer.sh"
artifacts:
- path: packages\win_installer\output\Aegisub-Japan7-x64.exe

View File

@ -0,0 +1,25 @@
local tr = aegisub.gettext
script_name = tr"Clean k tags"
script_description = tr"Remove double k tags"
script_author = "amoethyst"
script_version = "1.0"
function special_k(subs, sel)
-- if the first tag is K/kf this would break the timing for the previous timing
local expr = "^(.-){\\(ko?)([0-9.]*)[^}]-}([^{]-){\\[kK][fo]?([0-9.]*)[^}]-}( -{(\\[kK][fo]?)[0-9.]*[^}]-}.*)$"
for _, i in ipairs(sel) do
line = subs[i]
before, tag, k1, between, k2, after = line.text:match(expr)
while after ~= nil do
line.text = before .. "{\\" .. tag .. tonumber(k1) + tonumber(k2) .. "}" .. between .. after
subs[i] = line
before, tag, k1, between, k2, after = line.text:match(expr)
end
end
end
aegisub.register_macro(script_name, script_description, special_k)

View File

@ -0,0 +1,175 @@
local tr = aegisub.gettext
script_name = tr"Duetto Meika"
script_description = tr"The ultimate tool for karaoke duets"
script_author = "amoethyst"
include("utils.lua")
function replace_style(line, style_name, style_string)
before_style, after_style = line.text:match("^(.-{[^}]-)\\?s:".. style_name .."(.*)$")
return before_style .. style_string .. after_style
end
function duetto(subs, sel)
styles = {}
-- create the style map
for _, line in ipairs(subs) do
if line.class == "style" then
styles[line.name] = line
end
end
-- duetto~
for _, i in ipairs(sel) do
line = subs[i]
current_style = styles[line.style]
-- match every `s:` marker
for style_name in line.text:gmatch("{[^}]*s:([^}\\]*)[^}]*}") do
if style_name ~= current_style.name then
style = styles[style_name]
-- build the tags to use the new style
style_string = ""
if current_style.color1 ~= style.color1 then
style_string = style_string .. "\\c" .. style.color1
end
if current_style.color2 ~= style.color2 then
style_string = style_string .. "\\2c" .. style.color2
end
if current_style.color3 ~= style.color3 then
style_string = style_string .. "\\3c" .. style.color3
end
if current_style.color4 ~= style.color4 then
style_string = style_string .. "\\4c" .. style.color4
end
-- set style
line.text = replace_style(line, style_name, style_string)
current_style = style
else
-- remove marker to not break everything
line.text = replace_style(line, style_name, "")
end
end
subs[i] = line
end
aegisub.set_undo_point(script_name)
end
function test_colors(c1, c2)
return color_from_style(c1) == color_from_style(c2)
end
function get_script_style(style, styles)
for key, script_style in pairs(styles) do
if (test_colors(style.color1, script_style.color1)
and test_colors(style.color2, script_style.color2)
and test_colors(style.color3, script_style.color3)
and test_colors(style.color4, script_style.color4)
and tonumber(style.fontsize) == tonumber(script_style.fontsize)
and style.fontname == script_style.fontname) then
return script_style
end
end
return nil
end
function deduetto_meika(subs, sel)
local styles = {}
local last_style = -1
-- create the style map
for i, line in ipairs(subs) do
if line.class == "style" then
styles[line.name] = line
last_style = i
end
end
local new_styles = {}
for _, i in ipairs(sel) do
local line = subs[i]
local current_style = table.copy(styles[line.style])
local search_index = 1
while search_index < #line.text do
local match_start, match_end = line.text:find("{[^}]*}", search_index)
if match_start == nil then
break
end
local bracketed = line.text:sub(match_start, match_end)
local new_style = false
-- change style's colors
for tag, value in bracketed:gmatch("\\([1-4]?c)([^}\\]*)") do
new_style = true
if tag == "c" or tag == "1c" then
current_style.color1 = value
elseif tag == "2c" then
current_style.color2 = value
elseif tag == "3c" then
current_style.color3 = value
elseif tag == "4c" then
current_style.color4 = value
end
end
-- change style's font
for tag, value in bracketed:gmatch("\\(f[sn])([^}\\]*)") do
new_style = true
if tag == "fs" then
current_style.fontsize = value
elseif tag == "fn" then
current_style.fontname = value
end
end
if new_style then
local script_style = get_script_style(current_style, styles)
if script_style == nil then
if get_script_style(current_style, new_styles) == nil then
new_styles[#new_styles+1] = table.copy(current_style)
end
else
-- remove inline colors
bracketed = bracketed:gsub("\\[1-4]?c[^\\}]*", "")
bracketed = bracketed:gsub("\\[1-4]?a[^\\}]*", "")
-- remove inline fonts
bracketed = bracketed:gsub("\\f[sn][^\\}]*", "")
-- add style marker
bracketed = "{s:" .. script_style.name .. bracketed:sub(2, #bracketed)
line.text = line.text:sub(1, match_start-1) .. bracketed .. line.text:sub(match_end + 1, #line.text)
end
end
search_index = match_start + 1
end
subs[i] = line
end
if #new_styles > 0 then
for i, new_style in ipairs(new_styles) do
new_style.name = "Deduetto style " .. i
subs.insert(last_style, new_style)
last_style = last_style + 1
aegisub.log("Created new style: " .. new_style.name .. "\n")
end
end
end
aegisub.register_macro(script_name, script_description, duetto)
aegisub.register_macro(tr"Deduetto Meika", tr"Create styles from inline color tags", deduetto_meika)

View File

@ -0,0 +1,173 @@
local tr = aegisub.gettext
script_name = tr"Karaoke 1sec adjust lead-in"
script_description = tr"Adjust karaoke leadin to 1sec"
script_author = "Flore"
script_version = "1.00"
include("cleantags.lua")
leadinmsec = 1000 --lead in time can be changed here
ktag = "\\[kK][fo]?%d+" --pattern used to detect karaoke tags
-- KM template line definition
km_template_effect = "template pre-line all keeptags"
km_template_text = '!retime("line",$start < 900 and -$start or -900,200)!{!$start < 900 and "\\\\k" .. ($start/10) or "\\\\k90"!\\fad(!$start < 900 and $start or 300!,200)}'
function hasleadin(line)--check if there is an existing lead in (2 consecutive bracket with karaoke tags at the start of the line)
return line.text:find("^{[^{}]-" .. ktag .. "[^{}]-}%s*{[^{}]-" .. ktag .. "[^{}]-}")
end
function removeleadin(line)
if not hasleadin(line) then
return line
end
leadin = tonumber( line.text:match("^{[^{}]-\\[kK][fo]?(%d+)[^{}]-}%s*{[^{}]-" .. ktag .. "[^{}]-}") ) --read lead-in value
line.text = line.text:gsub("^({[^{}]-)\\[kK][fo]?%d+(.-}%s*{[^{}]-" .. ktag .. ".-})","%1%2") --remove lead in
line.text = cleantags(line.text) --clean tags
line.start_time = line.start_time + leadin*10 --adjust start time
--aegisub.log(line.text)
return line
end
function adjust_1sec(subs, sel)
for _, i in ipairs(sel) do
local line = subs[i]
line.text = cleantags(line.text)
if( line.text:find(ktag)) then--don't do anything if there is no ktags in this line
--start by removing existing lead-in
while hasleadin(line) do
if aegisub.progress.is_cancelled() then return end
line = removeleadin(line)
end
--then add our lead in
if line.start_time >= leadinmsec then
line.text = string.format("{\\k%d}%s",leadinmsec/10, line.text)
line.start_time = line.start_time - leadinmsec
else --if line starts too early to put the needed lead in, make the line start at time 0 and fill with appropriate lead in
line.text = string.format("{\\k%d}%s",line.start_time/10, line.text)
line.start_time = 0
end
subs[i] = line
end
end
aegisub.set_undo_point(tr"1sec adjust lead-in")
end
function remove_tag(line, tag)
local expr = "^(.-{[^}]*)\\" .. tag .. "[^\\}]*(.*)"
while true do
before, after = line.text:match(expr)
if before == nil then
return line
else
line.text = cleantags(before .. after)
end
end
end
function is_template_line(line)
return (line.class == "dialogue"
and line.effect == km_template_effect
and line.text == km_template_text)
end
function mugenizer(subs)
local first = nil
local styles_different = false
local styles = 0
local i_styles = {}
local template_present = false
for i, line in ipairs(subs) do
if line.class == "info" then
if line.key == "PlayResX" or line.key == "PlayResY" then
line.value = "0"
end
end
if line.class == "style" then
line.fontname = "Arial"
line.fontsize = "24"
line.outline = "1.5"
line.shadow = "0"
line.margin_l = "15"
line.margin_r = "15"
line.margin_t = "20"
line.margin_b = "20"
i_styles[styles] = i
if styles > 0 then
styles_different = styles_different or line.color1 ~= subs[i_styles[styles-1]].color1 or line.color2 ~= subs[i_styles[styles-1]].color2 or line.color3 ~= subs[i_styles[styles-1]].color3 or line.color4 ~= subs[i_styles[styles-1]].color4
end
styles = styles + 1
end
if is_template_line(line) then
line.comment = true
template_present = true
end
if line.class == "dialogue" and not line.comment and line.effect ~= "fx" then
if first == nil then
first = i
end
line.text = cleantags(line.text)
while hasleadin(line) do
if aegisub.progress.is_cancelled() then return end
line = removeleadin(line)
end
line = remove_tag(line, "fad")
end
subs[i] = line
end
if not styles_different then
for i = 0, styles-1, 1 do
line = subs[i_styles[i]]
line.color1 = "&H008AFF"
line.color2 = "&HFFFFFF"
line.color3 = "&H000000"
line.color4 = "&H000000"
subs[i_styles[i]] = line
end
end
if not template_present then
-- add mugen's magic line
line = subs[first]
line.comment = true
line.start_time = 0
line.end_time = 0
line.effect = km_template_effect
line.text = km_template_text
subs.insert(first, line)
end
end
aegisub.register_macro(script_name, script_description, adjust_1sec)
aegisub.register_macro(tr"Mugenizer", tr"Mugenize your subs", mugenizer)

View File

@ -1,79 +0,0 @@
--[[
Copyright (c) 2007, Niels Martin Hansen
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the Aegisub Group nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
]]
local tr = aegisub.gettext
script_name = tr"Automatic karaoke lead-in"
script_description = tr"Join up the ends of selected lines and add \\k tags to shift karaoke"
script_author = "Niels Martin Hansen"
script_version = "1.0"
function add_auto_leadin(subs, sel)
-- Smallest inter-line duration
local min_interdur = nil
for i = 2, #sel do
-- Grab two selected lines
local A = subs[sel[i-1]]
local B = subs[sel[i]]
-- Blank duration between lines
local interdur = B.start_time - A.end_time
if interdur > 0 then
-- Update smallest inter-line duration
if not min_interdur or interdur < min_interdur then
min_interdur = interdur
end
B.start_time = A.end_time
B.text = string.format("{\\k%d}%s", interdur/10, B.text)
subs[sel[i]] = B
else
aegisub.debug.out(2, "Warning: Skipping line-pair with zero or negative inter-duration:\n%s\n%s\n\n", A.text, B.text)
end
end
if min_interdur then
aegisub.debug.out(0, "Smallest inter-line duration: %d milliseconds", min_interdur)
aegisub.set_undo_point(script_name)
else
aegisub.debug.out(2, "Warning: No lines modified")
end
end
function check_minsel_2(subs, sel)
return #sel >= 2
end
aegisub.register_macro(script_name, script_description, add_auto_leadin, check_minsel_2)

View File

@ -0,0 +1,48 @@
local tr = aegisub.gettext
script_name = tr"Split karaoke line"
script_description = tr"Split line at {split} marker according to ktags"
script_author = "amoethyst"
script_version = "1.0"
function split_line(subs, sel)
function getduration(line)
d = 0
kduration = "{[^}]-\\[kK][fo]?(%d+)[^}]-}"
for match in line:gmatch(kduration) do
d = d + tonumber(match)
end
return d * 10
end
insertions = 0
for _, i in ipairs(sel) do
i = i + insertions
line1 = subs[i]
line2 = subs[i]
split_expr = "(.-)%s*{split}%s*(.*)"
line1.text, line2.text = line1.text:match(split_expr)
while line1.text ~= nil do
line1.end_time = line1.start_time + getduration(line1.text)
line2.start_time = line1.end_time
subs[i] = line1
i = i + 1
insertions = insertions + 1
subs.insert(i, line2)
line1 = subs[i]
line1.text, line2.text = line1.text:match(split_expr)
end
end
aegisub.set_undo_point(tr"Karaoke split")
end
aegisub.register_macro(script_name, script_description, split_line)

View File

@ -1,21 +0,0 @@
-- Automation 4 demo script
-- Macro that adds \be1 tags in front of every selected line
local tr = aegisub.gettext
script_name = tr"Add edgeblur"
script_description = tr"A demo macro showing how to do simple line modification in Automation 4"
script_author = "Niels Martin Hansen"
script_version = "1"
function add_edgeblur(subtitles, selected_lines, active_line)
for z, i in ipairs(selected_lines) do
local l = subtitles[i]
l.text = "{\\be1}" .. l.text
subtitles[i] = l
end
aegisub.set_undo_point(script_name)
end
aegisub.register_macro(script_name, tr"Adds \\be1 tags to all selected lines", add_edgeblur)

View File

@ -1,80 +0,0 @@
-- Automation 4 demo script
-- Converts halfwidth (ASCII) Latin letters to fullwidth JIS Latin letters
local tr = aegisub.gettext
script_name = tr("Make text fullwidth")
script_description = tr("Shows how to use the unicode include to iterate over characters and a lookup table to convert those characters to something else.")
script_author = "Niels Martin Hansen"
script_version = "1"
include("unicode.lua")
lookup = {
['!'] = '', ['"'] = '', ['#'] = '', ['$'] = '',
['%'] = '', ['&'] = '', ["'"] = '', ['('] = '',
[')'] = '', ['*'] = '', ['+'] = '', [','] = '',
['-'] = '', ['.'] = '', ['/'] = '',
['1'] = '', ['2'] = '', ['3'] = '', ['4'] = '',
['5'] = '', ['6'] = '', ['7'] = '', ['8'] = '',
['9'] = '', ['0'] = '',
[':'] = '', [';'] = '', ['<'] = '', ['='] = '',
['>'] = '', ['?'] = '', ['@'] = '',
['A'] = '', ['B'] = '', ['C'] = '', ['D'] = '',
['E'] = '', ['F'] = '', ['G'] = '', ['H'] = '',
['I'] = '', ['J'] = '', ['K'] = '', ['L'] = '',
['M'] = '', ['N'] = '', ['O'] = '', ['P'] = '',
['Q'] = '', ['R'] = '', ['S'] = '', ['T'] = '',
['U'] = '', ['V'] = '', ['W'] = '', ['X'] = '',
['Y'] = '', ['Z'] = '',
['['] = '', ['\\'] = '', [']'] = '', ['^'] = '',
['a'] = '', ['b'] = '', ['c'] = '', ['d'] = '',
['e'] = '', ['f'] = '', ['g'] = '', ['h'] = '',
['i'] = '', ['j'] = '', ['k'] = '', ['l'] = '',
['m'] = '', ['n'] = '', ['o'] = '', ['p'] = '',
['q'] = '', ['r'] = '', ['s'] = '', ['t'] = '',
['u'] = '', ['v'] = '', ['w'] = '', ['x'] = '',
['y'] = '', ['z'] = '',
['_'] = '_', ['`'] = '',
['{'] = '', ['|'] = '', ['}'] = '', ['~'] = '',
}
function make_fullwidth(subtitles, selected_lines, active_line)
for z, i in ipairs(selected_lines) do
local l = subtitles[i]
aegisub.debug.out(string.format('Processing line %d: "%s"\n', i, l.text))
aegisub.debug.out("Chars: \n")
local in_tags = false
local newtext = ""
for c in unicode.chars(l.text) do
aegisub.debug.out(c .. ' -> ')
if c == "{" then
in_tags = true
end
if in_tags then
aegisub.debug.out(c .. " (ignored, in tags)\n")
newtext = newtext .. c
else
if lookup[c] then
aegisub.debug.out(lookup[c] .. " (converted)\n")
newtext = newtext .. lookup[c]
else
aegisub.debug.out(c .. " (not found in lookup)\n")
newtext = newtext .. c
end
end
if c == "}" then
in_tags = false
end
end
l.text = newtext
subtitles[i] = l
end
aegisub.set_undo_point(tr"Make fullwidth")
end
aegisub.register_macro(tr"Make fullwidth", tr"Convert Latin letters to SJIS fullwidth letters", make_fullwidth)

View File

@ -1,32 +0,0 @@
-- Copyright (c) 2010, Thomas Goyne <plorkyeran@aegisub.org>
--
-- Permission to use, copy, modify, and distribute this software for any
-- purpose with or without fee is hereby granted, provided that the above
-- copyright notice and this permission notice appear in all copies.
--
-- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-- ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
local tr = aegisub.gettext
script_name = tr"Strip tags"
script_description = tr"Remove all override tags from selected lines"
script_author = "Thomas Goyne"
script_version = "1"
function strip_tags(subs, sel)
for _, i in ipairs(sel) do
local line = subs[i]
line.text = line.text:gsub("{[^}]+}", "")
subs[i] = line
end
aegisub.set_undo_point(tr"strip tags")
end
aegisub.register_macro(script_name, script_description, strip_tags)

View File

@ -0,0 +1,523 @@
--[[ "Blur / Layers" creates layers with blur. Supports 2 borders, xbord, ybord, xshad, and yshad. Basic support for transforms and \r.
"Blur + Glow" - Same as above but with an extra layer for glow. Set blur amount and alpha for the glow.
The "double border" option additionally lets you change the size and colour of the 2nd border.
If blur is missing, default blur is added.
"Bottom blur" allows you to use different blur for the lowest non-glow layer than for top layer(s).
"fix \\1a for layers with border and fade" - Uses \1a&HFF& for the duration of a fade on layers with border.
"transition" - for \fad(500,0) with transition 80ms you get \1a&HFF&\t(420,500,\1a&H00&).
"only add glow" - will add glow to a line with a border, without messing with the primary / border. (Blur + Glow)
"only add 2nd border" - will add 2nd border, without messing with the primary / first border. (Blur / Layers)
"Fix fades" - Recalculates those \1a fades mentioned above.
Use this when you shift something like an episode title to a new episode and the duration of the sign is different.
"Change layer" - raises or lowers layer for all selected lines by the same amount. [This is separate from the other functions.]
Full manual: http://unanimated.xtreemhost.com/ts/scripts-manuals.htm#blurglow
]]
script_name="Blur and Glow"
script_description="Add blur and/or glow to signs"
script_author="unanimated"
script_url="http://unanimated.xtreemhost.com/ts/blur-and-glow.lua"
script_version="2.5"
script_namespace="ua.BlurAndGlow"
local haveDepCtrl,DependencyControl,depRec=pcall(require,"l0.DependencyControl")
if haveDepCtrl then
script_version="2.5.0"
depRec=DependencyControl{feed="https://raw.githubusercontent.com/TypesettingTools/unanimated-Aegisub-Scripts/master/DependencyControl.json"}
end
function glow(subs,sel)
if not res.rep then al=res.alfa bl=res.blur end
if res.glowcol then glowc=res.glc:gsub("#(%x%x)(%x%x)(%x%x)","&H%3%2%1&") end
if res.autod then if res.clr or res.bsize then res.double=true end end
for z=#sel,1,-1 do
i=sel[z]
progress("Glowing line: "..(#sel-z+1).."/"..#sel)
line=subs[i]
text=line.text
if defaref and line.style=="Default" then sr=defaref
elseif lastref and laststyle==line.style then sr=lastref
else sr=stylechk(line.style) end
lastref=sr laststyle=line.style
duration=line.end_time-line.start_time
-- get colors, border, shadow from style
stylinfo(text)
text=preprocess(text)
line.text=text
if border~="0" or text:match("\\[xy]bord") then
-- WITH TWO BORDERS
if res.double then
-- second border
line1=line
line1.text=text
line1.text=borderline2(line1.text)
line1.layer=line1.layer+1
subs.insert(i+1,line1)
-- first border
line2=line
line2.text=text
line2.text=borderline(line2.text)
if shadow~="0" then line2.text=line2.text:gsub("^({\\[^}]+)}","%1\\shad"..shadow.."}") end
if not res.s_mid then line2.text=line2.text:gsub("^({\\[^}]-)}","%1\\4a&HFF&}") end
line2.layer=line2.layer+1
subs.insert(i+2,line2)
-- top line
line3=line
line3.text=text
line3.text=topline(line3.text)
line3.layer=line3.layer+1
subs.insert(i+3,line3)
-- bottom / glow
text=borderline2(text)
text=glowlayer(text,"3c","3")
if res.botalpha and line.text:match("\\fad%(") then text=botalfa(text) end
line.layer=line.layer-3
line.text=text
sls=3
else
-- WITH ONE BORDER
-- border
line2=line
if not res.onlyg then
line2.text=text
line2.text=borderline(line2.text)
end
line2.layer=line2.layer+1
subs.insert(i+1,line2)
-- top line
line3=line
line3.layer=line3.layer+1
if not res.onlyg then
line3.text=text
line3.text=topline(line3.text)
subs.insert(i+2,line3)
end
-- bottom / glow
text=glowlayer(text,"3c","3")
if res.botalpha and line.text:match("\\fad%(") then text=botalfa(text) end
line.layer=line.layer-2
line.text=text
sls=2
end
else
-- WITHOUT BORDER
line2=line
line2.layer=line2.layer+1
subs.insert(i+1,line2)
text=glowlayer(text,"c","1")
line.layer=line.layer-1
line.text=text
sls=1
end
subs[i]=line
for s=z,#sel do sel[s]=sel[s]+sls end
end
progress("Blur & Glow: DONE")
return sel
end
function layerblur(subs,sel)
if res.autod then if res.clr or res.bsize then res.double=true end end
for z=#sel,1,-1 do
i=sel[z]
progress("Blurring line: "..(#sel-z+1).."/"..#sel)
line=subs[i]
text=line.text
if defaref~=nil and line.style=="Default" then sr=defaref
elseif lastref~=nil and laststyle==line.style then sr=lastref
else sr=stylechk(line.style) end
lastref=sr laststyle=line.style
duration=line.end_time-line.start_time
-- get colors, border, shadow from style
stylinfo(text)
text=preprocess(text)
line.text=text
-- TWO BORDERS
if res.double then
-- first border
line2=line
if not res.onlyb then
line2.text=text
line2.text=borderline(line2.text)
if not res.s_mid then line2.text=line2.text:gsub("^({\\[^}]-)}","%1\\4a&HFF&}") end
end
line2.layer=line2.layer+1
subs.insert(i+1,line2)
-- top line
line3=line
line3.layer=line3.layer+1
if not res.onlyb then
line3.text=text
line3.text=topline(line3.text)
subs.insert(i+2,line3)
end
-- second border
text=borderline2(text)
line.layer=line.layer-2
line.text=text
sls=2
-- ONE BORDER
else
-- top line
line3=line
line3.text=text
line3.text=topline(line3.text)
line3.layer=line3.layer+1
subs.insert(i+1,line3)
-- bottom line
text=borderline(text)
line.layer=line.layer-1
line.text=text
sls=1
end
subs[i]=line
for s=z,#sel do sel[s]=sel[s]+sls end
end
progress("Blur: DONE")
end
function topline(txt)
txt=txt
:gsub("(\\t%([^%)]*)\\bord[%d%.]+","%1")
:gsub("(\\t%([^%)]*)\\shad[%d%.]+","%1")
:gsub("\\t%([^\\]*%)","")
if not txt:match("^{[^}]-\\bord") then txt=txt:gsub("^{\\","{\\bord0\\") end
txt=txt
:gsub("\\bord[%d%.]+","\\bord0")
:gsub("(\\r[^}]-)}","%1\\bord0}")
txt=txt:gsub("(\\[xy]bord)[%d%.]+","") :gsub("\\3c&H%x+&","")
if shadow~="0" then txt=txt:gsub("^({\\[^}]+)}","%1\\shad"..shadow.."}") end
txt=txt
:gsub("^({\\[^}]-)}","%1\\4a&HFF&}")
:gsub("(\\r[^}]-)}","%1\\shad"..shadow.."\\4a&HFF&}")
:gsub("\\bord[%d%.%-]+([^}]-)(\\bord[%d%.%-]+)","%1%2")
:gsub("\\shad[%d%.%-]+([^}]-)(\\shad[%d%.%-]+)","%1%2")
if res.s_top then txt=txt:gsub("\\4a&HFF&","") end
txt=txt:gsub("{}","")
return txt
end
function borderline(txt)
txt=txt:gsub("\\c&H%x+&","")
-- transform check
if txt:match("^{[^}]-\\t%([^%)]-\\3c") then
pretrans=text:match("^{(\\[^}]-)\\t")
if not pretrans:match("^{[^}]-\\3c") then txt=txt:gsub("^{\\","{\\c"..soutline.."\\") end
end
if not txt:match("^{[^}]-\\3c&[^}]-}") then
txt=txt:gsub("^({\\[^}]+)}","%1\\c"..soutline.."}")
:gsub("(\\r[^}]-)}","%1\\c"..routline.."}")
end
txt=txt:gsub("(\\3c)(&H%x+&)","%1%2\\c%2")
:gsub("(\\r[^}]-)}","%1\\c"..routline.."}")
:gsub("(\\r[^}]-\\3c)(&H%x+&)([^}]-)}","%1%2\\c%2%3")
:gsub("\\c&H%x+&([^}]-)(\\c&H%x+&)",function(a,b) if not a:match("\\t") then return a..b end end)
:gsub("{%*?}","")
if res.bbl and not res.double then txt=txt:gsub("\\blur[%d%.]+","\\blur"..res.bblur) end
if res.botalpha and txt:match("\\fad%(") then txt=botalfa(txt) end
return txt
end
function borderline2(txt)
outlinetwo=primary
if res.clr then col3=res.c3:gsub("#(%x%x)(%x%x)(%x%x)","&H%3%2%1&") outlinetwo=col3 rimary=col3 end
bordertwo=border
if res.bsize then bordertwo=res.secbord end
-- transform check
if txt:match("^{[^}]-\\t%([^%)]-\\bord") then
pretrans=text:match("^{(\\[^}]-)\\t")
if not pretrans:match("^{[^}]-\\bord") then txt=txt:gsub("^{\\","{\\bord"..border.."\\") end
end
if not txt:match("^{[^}]-\\bord") then txt=txt:gsub("^{\\","{\\bord"..border.."\\") end
txt=txt:gsub("(\\r[^\\}]-)([\\}])","%1\\bord"..rbord.."%2")
:gsub("(\\r[^\\}]-)\\bord[%d%.%-]+([^}]-)(\\bord[%d%.%-]+)","%1%2%3")
:gsub("(\\bord)([%d%.]+)",function(a,b) if res.bsize then brd=bordertwo else brd=b end return a..b+brd end)
:gsub("(\\[xy]bord)([%d%.]+)",function(a,b) return a..b+b end)
:gsub("\\3c&H%x+&","")
:gsub("^({\\[^}]+)}","%1\\3c"..outlinetwo.."}")
:gsub("(\\3c)(&H%x+&)","%1"..outlinetwo)
if res.clr then txt=txt:gsub("\\c&H%x+&([^}]-)}","\\c"..rimary.."\\3c"..outlinetwo.."%1}")
else txt=txt:gsub("(\\c)(&H%x+&)([^}]-)}","%1%2%3\\3c%2}") end
txt=txt:gsub("(\\r[^}]+)}","%1\\3c"..rimary.."}")
:gsub("\\c&H%x+&([^}]-)(\\c&H%x+&)",function(a,b) if not a:match("\\t") then return a..b end end)
:gsub("\\3c&H%x+&([^}]-)(\\3c&H%x+&)",function(a,b) if not a:match("\\t") then return a..b end end)
:gsub("{%*?}","")
if res.bbl and res.double then txt=txt:gsub("\\blur[%d%.]+","\\blur"..res.bblur) end
if res.botalpha and txt:match("\\fad%(") then txt=botalfa(txt) end
return txt
end
function glowlayer(txt,kol,alf)
txt=txt:gsub("\\alpha&H(%x%x)&",function(a) if a>al then return "\\alpha&H"..a.."&" else return "\\alpha&H"..al.."&" end end)
:gsub("\\"..alf.."a&H(%x%x)&",function(a) if a>al then return "\\"..alf.."a&H"..a.."&" else return "\\"..alf.."a&H"..al.."&" end end)
:gsub("(\\blur)[%d%.]*([\\}])","%1"..bl.."%2")
:gsub("(\\r[^}]-)}","%1\\alpha&H"..al.."&}")
if not txt:match("^{[^}]-\\alpha") then txt=txt:gsub("^({\\[^}]-)}","%1\\alpha&H"..al.."&}") end
if res.alfa=="00" then txt=txt:gsub("^({\\[^}]-)\\alpha&H00&","%1") end
txt=txt:gsub("{%*?}","")
if res.glowcol then
if txt:match("^{\\[^}]-\\"..kol.."&") then txt=txt:gsub("\\"..kol.."&H%x+&","\\"..kol..glowc)
else txt=txt:gsub("\\"..kol.."&H%x+&","\\"..kol..glowc) txt=txt:gsub("^({\\[^}]-)}","%1\\"..kol..glowc.."}")
end
end
return txt
end
function botalfa(txt)
fadin,fadout=txt:match("\\fad%((%d+)%,(%d+)")
alfadin=res.alphade alfadout=res.alphade
if res.alphade=="max" then alfadin=fadin alfadout=fadout end
if fadin==nil or fadout==nil then aegisub.log("\n ERROR: Failed to capture fade times from line:\n "..text) end
if fadin~="0" then
txt=txt:gsub("^({\\[^}]-)}","%1\\1a&HFF&\\t("..fadin-alfadin..","..fadin..",\\1a&H00&)}")
end
if fadout~="0" then
txt=txt:gsub("^({\\[^}]-)}","%1\\t("..duration-fadout..","..duration-fadout+alfadout..",\\1a&HFF&)}")
end
return txt
end
function stylinfo(text)
startags=text:match("^{\\[^}]-}") or ""
startags=startags:gsub("\\t%b()","")
primary=startags:match("^{[^}]-\\c(&H%x+&)") or sr.color1:gsub("H%x%x","H")
soutline=sr.color3:gsub("H%x%x","H")
outline=startags:match("^{[^}]-\\3c(&H%x+&)") or soutline
border=startags:match("^{[^}]-\\bord([%d%.]+)") or tostring(sr.outline)
shadow=startags:match("^{[^}]-\\shad([%d%.]+)") or tostring(sr.shadow)
if text:match("\\r%a") then
rstyle=text:match("\\r([^\\}]+)")
reref=stylechk(rstyle)
rimary=reref.color1:gsub("H%x%x","H")
routline=reref.color3:gsub("H%x%x","H")
rbord=tostring(reref.outline)
else routline=soutline rimary=primary rbord=border
end
end
function preprocess(text)
if not text:match("^{\\") then text="{\\blur"..bdef.."}"..text -- default blur if no tags
text=text:gsub("(\\r[^}]-)}","%1\\blur"..bdef.."}")
end
if not text:match("\\blur") then text=text:gsub("^{\\","{\\blur"..bdef.."\\") -- default blur if missing in tags
text=text:gsub("(\\r[^}]-)}","%1\\blur"..bdef.."}")
end
if text:match("\\blur") and not text:match("^{[^}]*blur[^}]*}") then -- add blur if missing in first tag block
text=text:gsub("^{\\","{\\blur"..bdef.."\\")
end
if text:match("^{[^}]-\\t[^}]-}") and not text:match("^{[^}]-\\3c[^}]-\\t") then -- \t workaround
text=text:gsub("^{\\","{\\3c"..soutline.."\\")
end
text=text:gsub("\\1c","\\c")
return text
end
function fixfade(subs,sel)
for z=#sel,1,-1 do
i=sel[z]
line=subs[i]
text=line.text
sr=stylechk(line.style)
duration=line.end_time-line.start_time
border=tostring(sr.outline)
bord=text:match("^{[^}]-\\bord([%d%.]+)")
if bord then border=bord end
if border~="0" and line.text:match("\\fad%(") then
text=text:gsub("\\1a&H%x+&","") :gsub("\\t%([^\\%(%)]-%)","")
text=botalfa(text)
end
line.text=text
subs[i]=line
end
end
function layeraise(subs,sel)
for z=#sel,1,-1 do
i=sel[z]
line=subs[i]
if line.layer+res["layer"]>=0 then line.layer=line.layer+res["layer"] else t_error("You're dumb. Layers can't go below 0.",1) end
subs[i]=line
end
end
function styleget(subs)
styles={}
for i=1,#subs do
if subs[i].class=="style" then
table.insert(styles,subs[i])
end
if subs[i].class=="dialogue" then break end
end
end
function stylechk(sn)
for s=1,#styles do
if sn==styles[s].name then
sr=styles[s]
if styles[s].name=="Default" then defaref=styles[s] end
end
end
if sr==nil then t_error("Style '"..sn.."' doesn't exist.",1) end
return sr
end
function saveconfig()
bgconf="Blur & Glow config\n\n"
for key,val in ipairs(GUI) do
if val.class=="floatedit" or val.class=="dropdown" or val.class=="color" then
bgconf=bgconf..val.name..":"..res[val.name].."\n"
end
if val.class=="checkbox" and val.name~="save" then
bgconf=bgconf..val.name..":"..tf(res[val.name]).."\n"
end
end
blurkonfig=ADP("?user").."\\blurandglow.conf"
file=io.open(blurkonfig,"w")
file:write(bgconf)
file:close()
ADD({{class="label",label="Config saved to:\n"..blurkonfig}},{"OK"},{close='OK'})
end
function loadconfig()
blurkonfig=ADP("?user").."\\blurandglow.conf"
file=io.open(blurkonfig)
if file~=nil then
konf=file:read("*all")
io.close(file)
for key,val in ipairs(GUI) do
if val.class=="floatedit" or val.class=="checkbox" or val.class=="dropdown" or val.class=="color" then
if konf:match(val.name) then val.value=detf(konf:match(val.name..":(.-)\n")) end
end
end
end
end
function tf(val)
if val==true then ret="true"
elseif val==false then ret="false"
else ret=val end
return ret
end
function detf(txt)
if txt=="true" then ret=true
elseif txt=="false" then ret=false
else ret=txt end
return ret
end
function logg(m) m=tf(m) or "nil" aegisub.log("\n "..m) end
function progress(msg)
if aegisub.progress.is_cancelled() then ak() end
aegisub.progress.title(msg)
end
function t_error(message,cancel)
ADD({{class="label",label=message}},{"OK"},{close='OK'})
if cancel then ak() end
end
function blurandglow(subs,sel)
ADD=aegisub.dialog.display
ADP=aegisub.decode_path
ak=aegisub.cancel
GUI={
--left
{x=0,y=0,width=2,class="label",label=" = Blur and Glow version "..script_version.." ="},
{x=0,y=1,class="label",label="Glow blur:"},
{x=0,y=2,class="label",label="Glow alpha:"},
{x=1,y=1,width=2,class="floatedit",name="blur",value=3},
{x=1,y=2,width=2,class="dropdown",name="alfa",items={"00","20","30","40","50","60","70","80","90","A0","B0","C0","D0","F0"},value="80"},
{x=0,y=3,class="checkbox",name="glowcol",label="glow c.:",hint="glow colour"},
{x=1,y=3,width=2,class="color",name="glc"},
{x=0,y=4,width=2,class="checkbox",name="s_top",label="keep shadow on top layer"},
{x=0,y=5,width=5,class="checkbox",name="botalpha",label="fix \\1a for layers with border and fade --> transition:",value=true,
hint="uses \\1a&HFF& for bottom layer during fade"},
{x=5,y=5,class="dropdown",name="alphade",items={0,45,80,120,160,200,"max"},value=45},
{x=6,y=5,width=2,class="label",label="ms"},
{x=0,y=6,width=4,class="checkbox",name="onlyg",label="only add glow (layers w/ border)"},
-- right
{x=4,y=0,class="checkbox",name="double",label="double border"},
{x=5,y=0,width=2,class="checkbox",name="onlyb",label="only add 2nd border"},
{x=4,y=1,class="checkbox",name="bbl",label="bottom blur:",
hint="Blur for bottom layer \n[not the glow layer] \nif different from top layer."},
{x=5,y=1,width=2,class="floatedit",name="bblur",value=1},
{x=4,y=2,class="checkbox",name="bsize",label="2nd b. size:",
hint="Size for 2nd border \n[counts from first border out] \nif different from the current border."},
{x=5,y=2,width=2,class="floatedit",name="secbord",value=2},
{x=4,y=3,class="checkbox",name="clr",label="2nd b. colour:",hint="Colour for 2nd border \nif different from primary."},
{x=5,y=3,width=2,class="color",name="c3"},
{x=4,y=4,width=4,class="checkbox",name="s_mid",label="keep shadow on middle layer"},
{x=4,y=6,class="label",label=" Change layer:"},
{x=5,y=6,class="dropdown",name="layer",items={"-5","-4","-3","-2","-1","+1","+2","+3","+4","+5"},value="+1"},
{x=0,y=7,width=2,class="checkbox",name="rep",label="repeat with last settings"},
{x=4,y=7,class="checkbox",name="autod",label="auto double",value=true,
hint="automatically use double border\nif 2nd colour or 2nd border size is checked"},
{x=6,y=6,class="dropdown",name="def",items={"0.3","0.4","0.5","0.6","0.7","0.8","0.9","1"},value="0.6",hint="config: default blur"},
{x=5,y=7,width=2,class="checkbox",name="save",label="save configuration"},
}
loadconfig()
buttons={"Blur / Layers","Blur + Glow","Fix fades","Change layer","cancel"}
pressed,res=ADD(GUI,buttons,{ok='Blur / Layers',close='cancel'})
if pressed=="cancel" then ak() end
bdef=res.def
if res.onlyg then res.double=false end
if res.onlyb then res.double=true end
if res.save then saveconfig()
else
if res.rep then res=lastres end
styleget(subs)
if pressed=="Blur / Layers" then layerblur(subs,sel) end
if pressed=="Blur + Glow" then sel=glow(subs,sel) end
if pressed=="Fix fades" then fixfade(subs,sel) end
if pressed=="Change layer" then layeraise(subs,sel) end
end
if res.rep==false then lastres=res end
aegisub.set_undo_point(script_name)
return sel
end
if haveDepCtrl then depRec:registerMacro(blurandglow) else aegisub.register_macro(script_name,script_description,blurandglow) end

View File

@ -0,0 +1,148 @@
script_name="Change Case"
script_description="Capitalises text or makes it lowercase / uppercase"
script_author="unanimated"
script_version="3.0"
script_namespace="ua.ChangeCase"
local haveDepCtrl,DependencyControl,depRec=pcall(require,"l0.DependencyControl")
if haveDepCtrl then
script_version="3.0.0"
depRec=DependencyControl{feed="https://raw.githubusercontent.com/TypesettingTools/unanimated-Aegisub-Scripts/master/DependencyControl.json"}
end
re=require'aegisub.re'
unicode=require'aegisub.unicode'
function case(subs,sel)
for z,i in ipairs(sel) do
line=subs[i]
t=line.text
if P=="lowercase" then t=lowercase(t) end
if P=="UPPERCASE" then t=uppercase(t) end
if P=="Lines" then t=capitalines(t) end
if P=="Sentences" then
if res.mod then res.mod=false t=lowercase(t) res.mod=true end
t=sentences(t)
end
if P=="Words" then
if not res.mod then t=lowercase(t) end
t=capitalise(t)
end
line.text=t
subs[i]=line
end
end
function lowercase(t)
t=t
:gsub("\\[Nnh]","{%1}")
:gsub("^([^{]*)",function(l)
if res.mod then l=re.sub(l,[[\b(\u\u+'?\u*)]],function(u) return ulower(u) end) return l
else return ulower(l) end end)
:gsub("}([^{]*)",function(l)
if res.mod then l=re.sub(l,[[\b(\u\u+'?\u*)]],function(u) return ulower(u) end) return "}"..l
else return "}"..ulower(l) end end)
:gsub("{(\\[Nnh])}","%1")
return t
end
function uppercase(t)
t=t
:gsub("\\[Nnh]","{%1}")
:gsub("^([^{]*)",function(u) return uupper(u) end)
:gsub("}([^{]*)",function(u) return "}"..uupper(u) end)
:gsub("{(\\[Nnh])}","%1")
return t
end
function capitalines(t)
t=re.sub(t,[[^(["']?\l)]],function(l) return uupper(l) end)
t=re.sub(t,[[^\{[^}]*\}(["']?\l)]],function(l) return uupper(l) end)
if not res.mod then
t=t:gsub(" i([' %?!%.,])"," I%1"):gsub("\\Ni([' ])","\\NI%1")
end
return t
end
function sentences(t)
somewords={"English","Japanese","American","British","German","French","Spanish","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday","January","February","April","June","July","August","September","October","November","December"}
hnrfx={"%-san","%-kun","%-chan","%-sama","%-dono","%-se[nm]pai","%-on%a+an"}
t=re.sub(t,[[^(["']?\l)]],function(l) return uupper(l) end)
t=re.sub(t,[[^\{[^}]*\}(["']?\l)]],function(l) return uupper(l) end)
t=re.sub(t,[[[\.\?!](\s|\s\\N|\\N)["']?(\l)]],function(l) return uupper(l) end)
t=t
:gsub(" i([' %?!%.,])"," I%1")
:gsub("\\Ni([' ])","\\NI%1")
:gsub(" m(arch %d)"," M%1")
:gsub(" a(pril %d)"," A%1")
for l=1,#somewords do t=t:gsub(somewords[l]:lower(),somewords[l]) end
for h=1,#hnrfx do
t=t:gsub("([ %p]%l)(%l*"..hnrfx[h]..")",function(h,f) return h:upper()..f end)
t=t:gsub("(\\N%l)(%l*"..hnrfx[h]..")",function(h,f) return h:upper()..f end)
end
t=re.sub(t,"\\b(of|in|from|\\d+st|\\d+nd|\\d+rd|\\d+th) m(arch|ay)\\b","\\1 M\\2")
t=re.sub(t,"\\bm(r|rs|s)\\.","M\\1.")
t=re.sub(t,"\\bdr\\.","Dr.")
return t
end
function capitalise(txt)
word={"A","About","Above","Across","After","Against","Along","Among","Amongst","An","And","Around","As","At","Before","Behind","Below","Beneath","Beside","Between","Beyond","But","By","Despite","During","Except","For","From","In","Inside","Into","Near","Nor","Of","On","Onto","Or","Over","Per","Sans","Since","Than","The","Through","Throughout","Till","To","Toward","Towards","Under","Underneath","Unlike","Until","Unto","Upon","Versus","Via","With","Within","Without","According to","Ahead of","Apart from","Aside from","Because of","Inside of","Instead of","Next to","Owing to","Prior to","Rather than","Regardless of","Such as","Thanks to","Up to","and Yet"}
onore={"%-San","%-Kun","%-Chan","%-Sama","%-Dono","%-Se[nm]pai","%-On%a+an"}
nokom={"^( ?)([^{]*)","(})([^{]*)"}
for n=1,2 do
txt=txt:gsub(nokom[n],function(no_t,t)
t=t:gsub("\\[Nnh]","{%1}")
t=re.sub(t,[[\b\l]],function(l) return uupper(l) end)
t=re.sub(t,[[[I\l]'(\u)]],function(l) return ulower(l) end)
for r=1,#word do w=word[r]
t=t
:gsub("^ "..w.." "," "..w:lower().." ")
:gsub("([^%.:%?!]) "..w.." ","%1 "..w:lower().." ")
:gsub("([^%.:%?!]) (%b{})"..w.." ","%1 %2"..w:lower().." ")
:gsub("([^%.:%?!]) (%*Large_break%* ?)"..w.." ","%1 %2"..w:lower().." ")
end
-- Roman numbers (this may mismatch some legit words - sometimes there just are 2 options and it's a guess)
t=t
:gsub("$","#")
:gsub("(%s?)([IVXLCDM])([ivxlcdm]+)([%s%p#])",function(s,r,m,e) return s..r..m:upper()..e end)
:gsub("([DLM])ID","%1id")
:gsub("DIM","Dim")
:gsub("MIX","Mix")
:gsub("Ok([%s%p#])","OK%1")
for h=1,#onore do
t=t:gsub(onore[h].."([%s%p#])",onore[h]:lower().."%1")
end
t=t
:gsub("#$","")
:gsub("{(\\[Nnh])}","%1")
return no_t..t end)
end
return txt
end
ulower=unicode.to_lower_case
uupper=unicode.to_upper_case
function logg(m) m=m or "nil" aegisub.log("\n "..m) end
function capital(subs,sel)
GUI={
{x=1,y=0,class="label",label="Words - Capitalise Words Like in Titles"},
{x=1,y=1,class="label",label=" Lines - Capitalise first word in selected lines"},
{x=1,y=2,class="label",label=" Sentences - Capitalise first word in each sentence"},
{x=1,y=3,class="label",label=" Lowercase - make text in selected lines lowercase"},
{x=1,y=4,class="label",label=" Uppercase - MAKE TEXT IN SELECTED LINES UPPERCASE"},
{x=2,y=5,class="label",label=script_name.." v "..script_version},
{x=1,y=5,class="checkbox",name="mod",label="mod",hint="Words - leave uppercase words\nLines - don't capitalize 'i'\nSentences - run lowercase first\nlowercase - only for uppercase words"},
}
P,res=aegisub.dialog.display(GUI,{"Words","Lines","Sentences","lowercase","UPPERCASE","Cancel"},{ok='Words',close='Cancel'})
if P=="Cancel" then aegisub.cancel() end
case(subs,sel)
aegisub.set_undo_point(script_name)
return sel
end
if haveDepCtrl then depRec:registerMacro(capital) else aegisub.register_macro(script_name,script_description,capital) end

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,116 @@
-- Manual: http://unanimated.hostfree.pw/ts/scripts-manuals.htm#cycle
script_name="Cycles"
script_description="Cycles blur, border, shadow, alpha, alignment, font spacing"
script_author="unanimated"
script_version="2.0"
script_namespace="ua.Cycles"
local haveDepCtrl,DependencyControl,depRec=pcall(require,"l0.DependencyControl")
if haveDepCtrl then
script_version="2.0.0"
depRec=DependencyControl{feed="https://raw.githubusercontent.com/unanimated/luaegisub/master/DependencyControl.json"}
end
-- SETTINGS - You can change these sequences
blur_sequence={"0.6","0.8","1","1.2","1.5","2","2.5","3","4","5","6","8","10","0.4","0.5"}
bord_sequence={"0","1","1.5","2","2.5","3","4","5","6","7","8","9","10","11","12","15","20"}
shad_sequence={"0","1","1.5","2","2.5","3","4","5","6","7","8","9","10","11","12"}
alpha_sequence={"FF","00","10","30","60","80","A0","C0","E0"}
align_sequence={"1","2","3","4","5","6","7","8","9"}
fsp_sequence={"0","1","2","3","4","5","6","7","8","10","12","15","20","30"}
--[[ Adding more tags
You could make this also work for the following tags: frz, frx, fry, fax, fay, fs, fscx, fscy, be, xbord, xshad, ybord, yshad
by doing 3 things:
1. add a new sequence to the settings above for the tag you want to add
2. add a function below here based on what the others look like (it's adjusted for negative values too)
3. add "aegisub.register_macro("Cycles/YOUR_SCRIPT_NAME","Cycles WHATEVER_YOU_CHOOSE",FUNCTION_NAME_HERE)" at the end of the script
If you at least roughly understand the basics, this should be easy. The main cycle function remains the same for all tags.
Should you want to add other tags with different value patterns, check the existing exceptions for alpha in the cycle function.]]
function blur(subs,sel) cycle(subs,sel,"blur",blur_sequence) end
function bord(subs,sel) cycle(subs,sel,"bord",bord_sequence) end
function shad(subs,sel) cycle(subs,sel,"shad",shad_sequence) end
function alph(subs,sel) cycle(subs,sel,"alpha",alpha_sequence) end
function algn(subs,sel) cycle(subs,sel,"an",align_sequence) end
function fsp(subs,sel) cycle(subs,sel,"fsp",fsp_sequence) end
function cycle(subs,sel,tag,sequence)
if tag=="alpha" then base=16 else base=10 end
for z,i in ipairs(sel) do
line=subs[i]
text=line.text
local back
if line.comment or text:match'{switch}$' then back=true end
text=text:gsub("\\t(%b())",function(t) return "\\t"..t:gsub("\\","|") end)
if tag=="alpha" then val1=text:match("^{[^}]-\\alpha&H(%x%x)&") else val1=text:match("^{[^}]-\\"..tag.."(%-?[%d%.]+)") end
if val1 then
for n=1,#sequence do
N=n+1
if back then N=n-1 end
if N==0 then N=#sequence end
if val1==sequence[n] then val2=sequence[N] or sequence[1] break end
end
if val2==nil then
for n=1,#sequence do
if n>1 or sequence[1]~="FF" then
local N=n
if back then N=n-1 end
if N==0 then N=#sequence end
if tonumber(val1,base)<tonumber(sequence[n],base) then val2=sequence[N] break end
end
end
end
if val2==nil then if back then val2=sequence[#sequence] else val2=sequence[1] end end
if tag=="alpha" then
text=text:gsub("^({[^}]-\\alpha&H)%x%x","%1"..val2)
else
text=text:gsub("^({[^}]-\\"..tag..")%-?[%d%.]+","%1"..val2)
end
val2=nil
else
text="{\\"..tag..sequence[1].."}"..text
text=text:gsub("alpha(%x%x)}","alpha&H%1&}")
:gsub("{(\\.-)}{\\","{%1\\")
end
text=text:gsub("{\\[^}]-}",function(t) return t:gsub("|","\\") end)
line.text=text
subs[i]=line
end
end
function switch(subs,sel)
for z,i in ipairs(sel) do
l=subs[i]
t=l.text
t=t.."{switch}"
t=t:gsub("{switch}{switch}$","")
l.text=t
subs[i]=l
end
end
function logg(m) m=m or "nil" aegisub.log("\n "..m) end
if haveDepCtrl then
depRec:registerMacros({
{"Cycles/Blur Cycle","Cycles Blur",blur},
{"Cycles/Border Cycle","Cycles Border",bord},
{"Cycles/Shadow Cycle","Cycles Shadow",shad},
{"Cycles/Alpha Cycle","Cycles Alpha",alph},
{"Cycles/Alignment Cycle","Cycles Alignment",algn},
{"Cycles/FontSpacing Cycle","Cycles Font Spacing",fsp},
{"Cycles/Switch","Switches sequence direction",switch},
},false)
else
aegisub.register_macro("Cycles/Blur Cycle","Cycles Blur",blur)
aegisub.register_macro("Cycles/Border Cycle","Cycles Border",bord)
aegisub.register_macro("Cycles/Shadow Cycle","Cycles Shadow",shad)
aegisub.register_macro("Cycles/Alpha Cycle","Cycles Alpha",alph)
aegisub.register_macro("Cycles/Alignment Cycle","Cycles Alignment",algn)
aegisub.register_macro("Cycles/FontSpacing Cycle","Cycles Font Spacing",fsp)
aegisub.register_macro("Cycles/Switch","Switches sequence direction",switch)
end

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,758 @@
-- Disclaimer: RTFM! - http://unanimated.hostfree.pw/ts/scripts-manuals.htm#cleanup
script_name="Script Cleanup"
script_description="Garbage disposal and elimination of incriminating evidence"
script_author="unanimated"
script_version="5.0"
script_namespace="ua.ScriptCleanup"
local haveDepCtrl,DependencyControl,depRec=pcall(require,"l0.DependencyControl")
if haveDepCtrl then
script_version="5.0.0"
depRec=DependencyControl{feed="https://raw.githubusercontent.com/unanimated/luaegisub/master/DependencyControl.json"}
end
dont_delete_empty_tags=false -- option to not delete {}
re=require'aegisub.re'
function cleanlines(subs,sel)
if res.all then
for k,v in ipairs(GUI) do
if v.x==0 then res[v.name]=true end
end
end
for z,i in ipairs(sel) do
progress("Processing line: "..z.."/"..#sel)
prog=math.floor(z/#sel*100)
aegisub.progress.set(prog)
line=subs[i]
text=line.text
stl=line.style
if res.nots and not res.nocom then text=text:gsub("{TS[^}]*} *","") end
if res.nocom then
text=text:gsub("{[^\\}]-}","")
:gsub("{[^\\}]-\\N[^\\}]-}","")
:gsub("^({[^}]-}) *","%1")
:gsub(" *$","")
end
if res.clear_a then line.actor="" end
if res.clear_e then line.effect="" end
if res.layers and line.layer<5 then
if stl:match("Defa") or stl:match("Alt") or stl:match("Main") then line.layer=line.layer+5 end
end
if res.cleantag and text:match("{[*>]?\\") then
txt2=text
text=text:gsub("{\\\\k0}",""):gsub(">\\","\\"):gsub("{(\\[^}]-)} *\\N *{(\\[^}]-)}","\\N{%1%2}")
repeat text,r=text:gsub("{(\\[^}]-)}{(\\[^}]-)}","{%1%2}") until r==0
text=text:gsub("({\\[^}]-){(\\[^}]-})","%1%2"):gsub("{.-\\r","{\\r"):gsub("^{\\r([\\}])","{%1")
:gsub("\\fad%(0,0%)",""):gsub(ATAG.."$",""):gsub("^({\\[^}]-)\\frx0\\fry0","%1"):gsub("\\%a+%(%)","")
text=text:gsub(ATAG,function(tgs)
tgs2=tgs
:gsub("\\+([\\}])","%1")
:gsub("(\\[^\\})]+)",function(a) if not a:match'clip' and not a:match'\\fn' and not a:match'\\r' then a=a:gsub(' ','') end return a end)
:gsub("(\\%a+)([%d%-]+%.%d+)",function(a,b) if not a:match("\\fn") then b=rnd2dec(b) end return a..b end)
:gsub("(\\%a+)%(([%d%.%-]+),([%d%.%-]+)%)",function(a,b,c) b=rnd2dec(b) c=rnd2dec(c) return a.."("..b..","..c..")" end)
:gsub("(\\%a+)%(([%d%.%-]+),([%d%.%-]+),([%d%.%-]+),([%d%.%-]+)",function(a,b,c,d,e)
return a.."("..rnd2dec(b)..","..rnd2dec(c)..","..rnd2dec(d)..","..rnd2dec(e) end)
tgs2=duplikill(tgs2)
tgs2=extrakill(tgs2)
return tgs2
end)
if txt2~=text then kleen=kleen+1 end
end
if res.overlap then
if line.comment==false and stl:match("Defa") then
start=line.start_time
endt=line.end_time
if i<#subs then nextline=subs[i+1] nextart=nextline.start_time end
prevline=subs[i-1]
prevstart=prevline.start_time
prevend=prevline.end_time
dur=line.end_time-line.start_time
ms2fr=aegisub.frame_from_ms
fr2ms=aegisub.ms_from_frame
keyframes=aegisub.keyframes()
startf=ms2fr(start)
endf=ms2fr(endt)
prevendf=ms2fr(prevend)
nextartf=ms2fr(nextart)
-- start gaps/overlaps
if prevline.class=="dialogue" and prevline.style:match("Defa") and dur>50 then
-- get keyframes
kfst=0 kfprev=0
for k,kf in ipairs(keyframes) do
if kf==startf then kfst=1 end
if kf==prevendf then kfprev=1 end
end
-- start overlap
if start<prevend and prevend-start<=50 then
if kfst==0 or kfprev==1 then nstart=prevend end
end
-- start gap
if start>prevend and start-prevend<=50 then
if kfst==0 and kfprev==1 then nstart=prevend end
end
end
-- end gaps/overlaps
if i<#subs and nextline.style:match("Defa") and dur>50 then
--get keyframes
kfend=0 kfnext=0
for k,kf in ipairs(keyframes) do
if kf==endf then kfend=1 end
if kf==nextartf then kfnext=1 end
end
-- end overlap
if endt>nextart and endt-nextart<=50 then
if kfnext==1 and kfend==0 then nendt=nextart end
end
-- end gap
if endt<nextart and nextart-endt<=50 then
if kfend==0 or kfnext==1 then nendt=nextart end
end
end
end
if nstart then line.start_time=nstart end
if nendt then line.end_time=nendt end
nstart=nil nendt=nil
end
if res.spaces then text=text:gsub(" +"," ") :gsub(" *$","") :gsub("^({\\[^}]-}) *","%1") end
if res.nobreak2 then text=text:gsub("\\[Nn]","")
elseif res.nobreak then
text=text
:gsub(" *{\\i0}\\N{\\i1} *"," ")
:gsub("%*","_ast_")
:gsub("\\[Nn]","*")
:gsub(" *%*+ *"," ")
:gsub("_ast_","*")
end
if res.hspace then text=text:gsub("\\h","") end
if res.notag then text=text:gsub(ATAG,"") end
if res.allcol then text=text:gsub("\\[1234]?c[^\\})]*","") end
if res.alpha14 then text=text:gsub("\\[1234]a[^\\})]*","")
elseif res.allphas then text=text:gsub("\\[1234]a[^\\})]*","") :gsub("\\alpha[^\\})]*","") end
if res.xyshad then text=text:gsub("\\[xy]shad[^\\})]*","")
elseif res.allshad then text=text:gsub("\\[xy]?shad[^\\})]*","") end
if res.xyrot then text=text:gsub("\\fr[xy][^\\})]*","")
elseif res.allrot then text=text:gsub("\\fr[^\\})]*","") end
if res.allpers then text=text:gsub("\\f[ar][xyz][^\\})]*","") :gsub("\\org%b()","") end
if res.scales then text=text:gsub("\\fsc[xy][^\\})]*","")
elseif res.allsize then text=text:gsub("\\fs[%d.]+","") :gsub("\\fs([\\}%)])","%1") :gsub("\\fsc[xy][^\\})]*","") end
if res.parent2 then text=text:gsub("(\\%a%a+)(%b())",function(a,b) if a=='\\pos' then return a..b else return "" end end)
elseif res.parent then text=text:gsub("\\%a%a+%b()","") end
if res.ctrans then text=text:gsub(ATAG,function(tg) return cleantr(tg) end) end
if res.inline2 then repeat text,r=text:gsub("(.)"..ATAG.."(.-{%*?\\)","%1%2") until r==0
elseif res.inline then text=text:gsub("(.)"..ATAG,"%1") end
if res.alphacol then
text=text
:gsub("alpha&(%x%x)&","alpha&H%1&")
:gsub("alpha&?H?(%x%x)&?([\\}])","alpha&H%1&%2")
:gsub("alpha&H0&","alpha&H00&")
:gsub("alpha&H(%x%x)%x*&","alpha&H%1&")
:gsub("(\\[1234]a)&(%x%x)&","%1&H%2&")
:gsub("(\\[1234]a)(%x%x)([\\}])","%1&H%2&%3")
:gsub("(\\[1234]?c&)(%x%x%x%x%x%x)&","%1H%2&")
:gsub("(\\[1234]?c&H%x%x%x%x%x%x)([^&])","%1&%2")
:gsub("(\\i?clip%([^%)]-) ?([\\}])","%1)%2")
:gsub("(\\t%([^%)]-\\i?clip%([^%)]-%))([\\}])","%1)%2")
:gsub("(fad%([%d,]+)([\\}])","%1)%2")
:gsub("([1234]?[ac])H&(%x+)","%1&H%2")
:gsub("([1234]?c&H)00(%x%x%x%x%x%x)","%1%2")
end
text=text:gsub("^ *","") :gsub("\\t%([^\\%)]-%)","") :gsub("{%*}","")
if not dont_delete_empty_tags then text=text:gsub("{}","") end
if line.text~=text then chng=chng+1 end
line.text=text
subs[i]=line
end
if res.info then
infotxt="Lines with modified Text field: "..chng
if res.cleantag then infotxt=infotxt.."\nChanges from Clean Tags: "..kleen end
P,rez=ADD({{class="label",label=infotxt}},{"OK"},{close='OK'})
end
return sel
end
-- delete commented lines from selected lines
function nocom_line(subs,sel)
progress("Deleting commented lines")
ncl_sel={}
for s=#sel,1,-1 do
line=subs[sel[s]]
if line.comment then
for z,i in ipairs(ncl_sel) do ncl_sel[z]=i-1 end
subs.delete(sel[s])
else
table.insert(ncl_sel,sel[s])
end
end
return ncl_sel
end
-- delete empty lines
function noempty(subs,sel)
progress("Deleting empty lines")
noe_sel={}
for s=#sel,1,-1 do
line=subs[sel[s]]
if line.text=="" then
for z,i in ipairs(noe_sel) do noe_sel[z]=i-1 end
subs.delete(sel[s])
else
table.insert(noe_sel,sel[s])
end
end
return noe_sel
end
-- delete commented or empty lines
function noemptycom(subs,sel)
progress("Deleting commented/empty lines")
noecom_sel={}
for s=#sel,1,-1 do
line=subs[sel[s]]
if line.comment or line.text=="" then
for z,i in ipairs(noecom_sel) do noecom_sel[z]=i-1 end
subs.delete(sel[s])
else
table.insert(noecom_sel,sel[s])
end
end
return noecom_sel
end
-- delete unused styles
function nostyle(subs,sel)
stylist=",,"
for i=#subs,1,-1 do
if subs[i].class=="dialogue" then
line=subs[i]
text=line.text
st2=text:match("\\r([^\\}]*)")
st=line.style
if not stylist:match(","..esc(st)..",") then stylist=stylist..st..",," end
if st2 and st2~="" and not stylist:match(","..esc(st2)..",") then stylist=stylist..st2..",," end
end
if subs[i].class=="style" then
style=subs[i]
if res.nostyle2 and style.name:match("Defa") or res.nostyle2 and style.name:match("Alt") then nodel=1 else nodel=0 end
if not stylist:match(","..esc(style.name)..",") and nodel==0 then
subs.delete(i)
logg("\n Deleted style: "..style.name)
for s=1,#sel do sel[s]=sel[s]-1 end
end
end
end
return sel
end
-- kill everything
function killemall(subs,sel)
if res.inverse then
for k,v in ipairs(GUI) do
if v.x>4 and v.y>0 and v.name~="onlyt" then res[v.name]=not res[v.name] end
end
end
for z,i in ipairs(sel) do
progress("Processing line: "..z.."/"..#sel)
line=subs[i]
text=line.text
if res.onlyt then res.trans=false
text=text:gsub(ATAG,function(t) return t:gsub("\\","|") end)
:gsub("|t(%b())",function(t) return "\\t"..t:gsub("|","\\") end)
end
tags=text:match(STAG) or ""
inline=text:gsub(STAG,"")
if res.skill and res.ikill then trgt=text tg=3
elseif res.ikill then trgt=inline tg=2
else trgt=tags tg=1 end
if res.border then trgt=killtag("[xy]?bord",trgt) end
if res.shadow then trgt=killtag("shad",trgt) end
if res.blur then trgt=killtag("blur",trgt) end
if res.bee then trgt=killtag("be",trgt) end
if res.fsize then trgt=killtag("fs",trgt) end
if res.fspace then trgt=killtag("fsp",trgt) end
if res.scalex then trgt=killtag("fscx",trgt) end
if res.scaley then trgt=killtag("fscy",trgt) end
if res.fade then trgt=trgt:gsub("\\fade?%b()","") end
if res.posi then trgt=trgt:gsub("\\pos%b()","") end
if res.move then trgt=trgt:gsub("\\move%b()","") end
if res.org then trgt=trgt:gsub("\\org%b()","") end
if res.color1 then trgt=killctag("1?c",trgt) end
if res.color2 then trgt=killctag("2c",trgt) end
if res.color3 then trgt=killctag("3c",trgt) end
if res.color4 then trgt=killctag("4c",trgt) end
if res.alfa1 then trgt=killctag("1a",trgt) end
if res.alfa2 then trgt=killctag("2a",trgt) end
if res.alfa3 then trgt=killctag("3a",trgt) end
if res.alfa4 then trgt=killctag("4a",trgt) end
if res.alpha then trgt=killctag("alpha",trgt) end
if res.clip then trgt=trgt:gsub("\\i?clip%b()","") end
if res.fname then trgt=trgt:gsub("\\fn[^\\}]+","") end
if res.frz then trgt=killtag("frz",trgt) end
if res.frx then trgt=killtag("frx",trgt) end
if res.fry then trgt=killtag("fry",trgt) end
if res.fax then trgt=killtag("fax",trgt) end
if res.fay then trgt=killtag("fay",trgt) end
if res.anna then trgt=killtag("an",trgt) end
if res.align then trgt=killtag("a",trgt) end
if res.wrap then trgt=killtag("q",trgt) end
if res["return"] then trgt=trgt:gsub("\\r.+([\\}])","%1") end
if res.kara then trgt=trgt:gsub("\\[Kk][fo]?[%d%.]+([\\}])","%1") end
if res.ital then repeat trgt,r=trgt:gsub("\\i[01]?([\\}])","%1") until r==0 end
if res.bold then repeat trgt,r=trgt:gsub("\\b[01]?([\\}])","%1") until r==0 end
if res.under then repeat trgt,r=trgt:gsub("\\u[01]?([\\}])","%1") until r==0 end
if res.stri then repeat trgt,r=trgt:gsub("\\s[01]?([\\}])","%1") until r==0 end
if res.trans then trgt=trgt:gsub("\\t%b()","") end
trgt=trgt:gsub("\\t%([%d%.,]*%)","") :gsub("{%**}","")
if tg==1 then tags=trgt elseif tg==2 then inline=trgt elseif tg==3 then text=trgt end
if trgt~=text then text=tags..inline end
if res.onlyt then text=text:gsub("{%*?|[^}]-}",function(t) return t:gsub("|","\\") end) end
line.text=text
subs[i]=line
end
end
function killtag(tag,t) repeat t,r=t:gsub("\\"..tag.."[%d%.%-]-([\\}])","%1") until r==0 return t end
function killctag(tag,t) t=t:gsub("\\"..tag.."&H%x+&","") repeat t,r=t:gsub("\\"..tag.."([\\}])","%1") until r==0 return t end
-- hide tags
function hide_tags(subs,sel)
hide=true
if res.inverse then hide=nil end
local numbers="\\i\\b\\u\\s\\q\\a\\be\\blur\\bord\\fs\\fscx\\fscy\\shad\\an\\frz\\fry\\frx\\fsp\\fax\\fay\\"
local alphacol="\\1a\\2a\\3a\\4a\\1c\\2c\\3c\\4c\\alpha\\"
local parent="\\fad\\pos\\move\\org\\clip\\"
local fontret="\\r\\fn\\"
if hide then
hidem={}
for k,v in ipairs(GUI) do
if v.x>4 and v.y>0 and v.name~='onlyt' and v.name~='kara' then
nom=v.label:gsub("c, 1c","1c"):gsub("%(i%)","")
if res[v.name] then table.insert(hidem,nom) end
end
end
end
for x,i in ipairs(sel) do
line=subs[i]
text=line.text:gsub("\\c&","\\1c&")
startg=text:match("^{\\[^}]-}") or ""
startg=trem(startg)
t2=text:gsub("^{\\[^}]-}","")
if hide then
for t=1,#hidem do
local tag='\\'..hidem[t]
local htag='//'..hidem[t]
local chk=tag..'\\'
tg=nil
if numbers:match(chk) then
tg=startg:match(tag.."([%d.-]+)")
if tg then t2=t2.."{"..htag..tg.."}" end
startg=startg:gsub(tag.."[%d.-]+","")
if not tg and tag=="\\shad" then
tg1=startg:match("\\xshad([%d.-]+)")
tg2=startg:match("\\yshad([%d.-]+)")
if tg1 then t2=t2.."{//xshad"..tg1.."}" end
if tg2 then t2=t2.."{//yshad"..tg2.."}" end
startg=startg:gsub("\\[xy]shad[%d.-]+","")
end
elseif alphacol:match(chk) then
tg=startg:match(tag.."(&H%x+&)")
if tg then t2=t2.."{"..htag..tg.."}" end
startg=startg:gsub(tag.."&H%x+&","")
elseif parent:match(chk) then
tg=startg:match(tag.."(%b())")
if not tg and tag=="\\clip" then tg=startg:match("\\iclip(%b())") tag='\\iclip' htag='//iclip' end
if not tg and tag=="\\fad" then tg=startg:match("\\fade(%b())") tag='\\fade' htag='//fade' end
if tg then t2=t2.."{"..htag..tg.."}" end
startg=startg:gsub(tag.."%b()","")
elseif fontret:match(chk) then
tg=startg:match(tag.."([^\\}]*)")
if tg then t2=t2.."{"..htag..tg.."}" end
startg=startg:gsub(tag.."[^\\}]*","")
elseif tag=='\\t' then
t2=t2.."{"..trnsfrm:gsub("\\t","//t").."}"
end
end
if res.hidline then
-- hide inline
inT=inline_pos(t2)
t2=t2:gsub(ATAG,"")
for k,v in ipairs(inT) do
t2=t2..v.t:gsub("{%*?\\","{"..v.n.."//")
end
end
else
local vis1,vis2=t2:gsub("%b{}","")
local c=0
repeat
-- Unhide regular
if res.skill then
for hidden in t2:gmatch("{(//.-)}") do
t2=t2:gsub("{"..esc(hidden).."}","")
hidden=hidden:gsub("//","\\")
startg=startg.."{"..hidden.."}"
end
end
-- unhide inline
if t2:match("{%d+//[^}]+}") and res.ikill then
inT={}
stT=''
for num,tag in t2:gmatch("{(%d+)//([^}]+)}") do
table.insert(inT,{n=num,t=tag})
end
for tag in t2:gmatch("{//[^}]+}") do stT=stT..tag end
table.sort(inT,function(a,b) return tonumber(a.n)<tonumber(b.n) end)
t2=t2:gsub("{%d+//[^}]+}","")
if t2:match"{" then orig=t2 t2=t2:gsub("%b{}","") end
t2=inline_ret2(t2,inT)
if orig then t2=textmod(orig,t2) orig=nil end
t2=t2..stT
end
vis2=t2:gsub("%b{}","")
c=c+1
until vis1==vis2 or c==666
if vis1~=vis2 then logg('Error:\n '..vis1..'\n> '..vis2) end
end
if not hide or hide and not res.trans then startg=startg.."{"..trnsfrm.."}" end
text=duplikill(startg:gsub("}{",""):gsub("\\1c","\\c"))..t2
text=text:gsub("{}",""):gsub("\\1c","\\c")
if line.text~=text then line.text=text subs[i]=line end
end
return sel
end
-- save inline tags
function inline_pos(t)
inTags={}
tl=t:len()
if tl==0 then return {} end
p=0
t1=''
repeat
seg=t:match("^(%b{})") -- try to match tags/comments
if seg then
if seg:match("{%*?\\") then table.insert(inTags,{n=p,t=seg}) end
else
seg=t:match("^([^{]+)") -- or match text
if not seg then t_error("Error: There appears to be a problem with the brackets here...\n"..t1..t,1) end
SL=re.find(seg,".")
p=p+#SL -- position of next '{' [or end]
end
t1=t1..seg
t=t:gsub("^"..esc(seg),"")
tl=t:len()
until tl==0
return inTags
end
-- rebuild inline tags
function inline_ret2(t,tab)
tl=t:len()
nt=''
kill='_Z#W_' -- this is supposed to never match
for k,v in ipairs(tab) do
N=tonumber(v.n)
if N==0 then nt=nt..v.t
else
m='.'
-- match how many chars at the start
m=m:rep(N)
RS=re.find(t,m)
seg=RS[1].str
seg=re.sub(seg,'^'..kill,'')
nt=nt..seg..'{\\'..v.t..'}'
kill=m -- how many matched in the last round
end
end
-- the rest
seg=re.sub(t,'^'..kill,'')
nt=nt..seg
return nt
end
-- reanimatools -------
function esc(str) str=str:gsub("[%%%(%)%[%]%.%-%+%*%?%^%$]","%%%1") return str end
function rnd2dec(num) num=math.floor((num*100)+0.5)/100 return num end
function logg(m) m=m or "nil" aegisub.log("\n "..m) end
function wrap(str) return "{"..str.."}" end
function nobra(t) return t:gsub("%b{}","") end
function nobrea(t) return t:gsub("%b{}",""):gsub("\\[Nh]","") end
function nobrea1(t) return t:gsub("%b{}",""):gsub(" *\\[Nh] *"," ") end
function tagmerge(t) repeat t,r=t:gsub("({\\[^}]-)}{(\\[^}]-})","%1%2") until r==0 return t end
function progress(msg) if aegisub.progress.is_cancelled() then ak() end aegisub.progress.title(msg) end
function t_error(message,cancel) ADD({{class="label",label=message}},{"OK"},{close='OK'}) if cancel then ak() end end
function duplikill(tagz)
local tags1={"blur","be","bord","shad","xbord","xshad","ybord","yshad","fs","fsp","fscx","fscy","frz","frx","fry","fax","fay"}
local tags2={"c","2c","3c","4c","1a","2a","3a","4a","alpha"}
tagz=tagz:gsub("\\t%b()",function(t) return t:gsub("\\","|") end)
for i=1,#tags1 do
tag=tags1[i]
repeat tagz,c=tagz:gsub("|"..tag.."[%d%.%-]+([^}]-)(\\"..tag.."[%d%.%-]+)","%1%2") until c==0
repeat tagz,c=tagz:gsub("\\"..tag.."[%d%.%-]+([^}]-)(\\"..tag.."[%d%.%-]+)","%2%1") until c==0
end
tagz=tagz:gsub("\\1c&","\\c&")
for i=1,#tags2 do
tag=tags2[i]
repeat tagz,c=tagz:gsub("|"..tag.."&H%x+&([^}]-)(\\"..tag.."&H%x+&)","%1%2") until c==0
repeat tagz,c=tagz:gsub("\\"..tag.."&H%x+&([^}]-)(\\"..tag.."&H%x+&)","%2%1") until c==0
end
repeat tagz,c=tagz:gsub("\\fn[^\\}]+([^}]-)(\\fn[^\\}]+)","%2%1") until c==0
repeat tagz,c=tagz:gsub("(\\[ibusq])%d(.-)(%1%d)","%2%3") until c==0
repeat tagz,c=tagz:gsub("(\\an)%d(.-)(%1%d)","%3%2") until c==0
tagz=tagz:gsub("(|i?clip%(%A-%))(.-)(\\i?clip%(%A-%))","%2%3")
:gsub("(\\i?clip%b())(.-)(\\i?clip%b())",function(a,b,c)
if a:match("m") and c:match("m") or not a:match("m") and not c:match("m") then return b..c else return a..b..c end end)
tagz=tagz:gsub("|","\\"):gsub("\\t%([^\\%)]-%)","")
return tagz
end
function extrakill(text,o)
local tags3={"pos","move","org","fad"}
for i=1,#tags3 do
tag=tags3[i]
if o==2 then
repeat text,c=text:gsub("(\\"..tag.."[^\\}]+)([^}]-)(\\"..tag.."[^\\}]+)","%3%2") until c==0
else
repeat text,c=text:gsub("(\\"..tag.."[^\\}]+)([^}]-)(\\"..tag.."[^\\}]+)","%1%2") until c==0
end
end
repeat text,c=text:gsub("(\\pos[^\\}]+)([^}]-)(\\move[^\\}]+)","%1%2") until c==0
repeat text,c=text:gsub("(\\move[^\\}]+)([^}]-)(\\pos[^\\}]+)","%1%2") until c==0
return text
end
function trem(tags)
trnsfrm=""
for t in tags:gmatch("\\t%b()") do trnsfrm=trnsfrm..t end
tags=tags:gsub("\\t%b()","")
return tags
end
function cleantr(tags)
trnsfrm=""
zerotf=""
for t in tags:gmatch("\\t%b()") do
if t:match("\\t%(\\") then
zerotf=zerotf..t:match("\\t%((.*)%)$")
else
trnsfrm=trnsfrm..t
end
end
zerotf="\\t("..zerotf..")"
tags=tags:gsub("\\t%b()",""):gsub("^({[^}]*)}","%1"..zerotf..trnsfrm.."}"):gsub("\\t%(%)","")
return tags
end
function retextmod(orig,text)
local v1,v2,c,t2
v1=nobrea(orig)
c=0
repeat
t2=textmod(orig,text)
v2=nobrea(text)
c=c+1
until v1==v2 or c==666
if v1~=v2 then logg("Something went wrong with the text...") logg(v1) logg(v2) end
return t2
end
function textmod(orig,text)
if text=="" then return orig end
tk={}
tg={}
text=text:gsub("{\\\\k0}","")
text=tagmerge(text)
vis=nobra(text)
ltrmatches=re.find(vis,".")
if not ltrmatches then logg("text: "..text..'\nvisible: '..vis)
logg("If you're seeing this, something really weird is happening with the re module.\nTry this again or rescan Autoload.")
end
for l=1,#ltrmatches do
table.insert(tk,ltrmatches[l].str)
end
stags=text:match(STAG) or ""
text=text:gsub(STAG,"") :gsub("{[^\\}]-}","")
orig=orig:gsub("{([^\\}]+)}",function(c) return wrap("\\\\"..c.."|||") end)
count=0
for seq in orig:gmatch("[^{]-{%*?\\[^}]-}") do
chars,as,tak=seq:match("([^{]-){(%*?)(\\[^}]-)}")
pos=re.find(chars,".")
if pos==nil then ps=0+count else ps=#pos+count end
tgl={p=ps,t=tak,a=as}
table.insert(tg,tgl)
count=ps
end
count=0
for seq in text:gmatch("[^{]-{%*?\\[^}]-}") do
chars,as,tak=seq:match("([^{]-){(%*?)(\\[^}]-)}")
pos=re.find(chars,".")
if pos==nil then ps=0+count else ps=#pos+count end
tgl={p=ps,t=tak,a=as}
table.insert(tg,tgl)
count=ps
end
newline=""
for i=1,#tk do
newline=newline..tk[i]
newt=""
for n,t in ipairs(tg) do
if t.p==i then newt=newt..t.a..t.t end
end
if newt~="" then newline=newline.."{"..as..newt.."}" end
end
newtext=stags..newline:gsub("(|||)(\\\\)","%1}{%2"):gsub("({[^}]-)\\\\([^\\}]-)|||","{%2}%1")
text=newtext:gsub("{}","")
return text
end
function cleanup(subs,sel,act)
ADD=aegisub.dialog.display
ak=aegisub.cancel
if #sel==0 then t_error("No selection",1) end
ATAG="{[*>]?\\[^}]-}"
STAG="^{>?\\[^}]-}"
if act==0 then act=sel[1] end
chng=0 kleen=0
GUI={
{x=0,y=0,class="checkbox",name="nots",label="Remove TS timecodes",hint="Removes timecodes like {TS 12:36}"},
{x=0,y=1,class="checkbox",name="clear_a",label="Clear Actor field"},
{x=0,y=2,class="checkbox",name="clear_e",label="Clear Effect field"},
{x=0,y=3,class="checkbox",name="layers",label="Raise dialogue layer by 5"},
{x=0,y=4,class="checkbox",name="cleantag",label="Clean up tags",hint="Fixes duplicates, \\\\, \\}, }{, and other garbage"},
{x=0,y=5,class="checkbox",name="ctrans",label="Clean up transforms"},
{x=0,y=6,class="checkbox",name="overlap",label="Fix 1-frame gaps/overlaps"},
{x=0,y=7,class="checkbox",name="nocomline",label="Delete commented lines"},
{x=0,y=8,class="checkbox",name="noempty",label="Delete empty lines"},
{x=0,y=9,class="checkbox",name="alphacol",label="Try to fix alpha / colour tags"},
{x=0,y=10,class="checkbox",name="spaces",label="Fix start/end/double spaces"},
{x=0,y=12,class="checkbox",name="info",label="Print info"},
{x=0,y=13,class="checkbox",name="all",label="ALL OF THE ABOVE"},
{x=1,y=0,class="label",label=" "},
{x=2,y=0,width=2,class="checkbox",name="allcol",label="Remove all colour tags"},
{x=2,y=1,class="checkbox",name="allphas",label="Remove all alphas"},
{x=3,y=1,class="checkbox",name="alpha14",label="Only 1a-4a"},
{x=2,y=2,class="checkbox",name="allrot",label="Remove all rotations",hint="frx, fry, frz"},
{x=3,y=2,class="checkbox",name="xyrot",label="Only x, y",hint="remove frx, fry"},
{x=2,y=3,class="checkbox",name="allsize",label="Remove size/scaling",hint="fs, fscx, fscy"},
{x=3,y=3,class="checkbox",name="scales",label="Only scaling",hint="remove fscx, fscy"},
{x=2,y=4,class="checkbox",name="allshad",label="Remove all shadows",hint="shad, xshad, yshad"},
{x=3,y=4,class="checkbox",name="xyshad",label="Only x, y",hint="remove xshad, yshad"},
{x=2,y=5,class="checkbox",name="parent",label="Remove parentheses",hint="fad(e), (i)clip, pos, move, org\n(but not t)"},
{x=3,y=5,class="checkbox",name="parent2",label="Except \\pos",hint="fad(e), (i)clip, move, org\n(but not t or pos)"},
{x=2,y=6,width=2,class="checkbox",name="allpers",label="Remove all perspective",hint="frx, fry, frz, fax, fay, org"},
{x=2,y=7,width=2,class="label",label=" ~ Script Cleanup v"..script_version.." ~"},
{x=2,y=8,width=2,class="checkbox",name="hspace",label="Remove hard spaces - \\h"},
{x=2,y=9,class="checkbox",name="nobreak",label="Remove line breaks"},
{x=3,y=9,class="checkbox",name="nobreak2",label="...no space",hint="Remove line breaks, leave no spaces"},
{x=2,y=10,class="checkbox",name="nostyle",label="Delete unused styles"},
{x=3,y=10,class="checkbox",name="nostyle2",label="Except Def.",hint="Delete unused styles except Default"},
{x=2,y=11,class="checkbox",name="inline",label="Remove inline tags"},
{x=3,y=11,class="checkbox",name="inline2",label="Except last",hint="Remove inline tags except the last one"},
{x=2,y=12,width=2,class="checkbox",name="nocom",label="Remove comments from lines",hint="Removes {comments} (not tags)"},
{x=2,y=13,width=2,class="checkbox",name="notag",label="Remove all {\\tags} from selected lines"},
{x=4,y=0,height=14,class="label",label="| \n|\n|\n|\n|\n|\n|\n|\n|\n|\n|\n|\n|\n|\n|\n|\n|\n|"},
{x=5,y=0,class="checkbox",name="skill",label="[start]",value=true},
{x=6,y=0,class="checkbox",name="ikill",label="[inline]",value=true,hint="only kill, not hide"},
{x=7,y=0,width=2,class="checkbox",name="inverse",label="[inverse/unhide]",hint="kill all except checked ones\n\n'Unhide' for 'Hide Tags'"},
{x=7,y=1,width=2,class="checkbox",name="onlyt",label="[from \\t]",hint="remove only from transforms\n\n n/a for 'Hide Tags'"},
{x=5,y=1,class="checkbox",name="blur",label="blur"},
{x=5,y=2,class="checkbox",name="border",label="bord",hint="includes xbord and ybord [not for Hide]"},
{x=5,y=3,class="checkbox",name="shadow",label="shad",hint="includes xshad and yshad for Hide"},
{x=5,y=4,class="checkbox",name="fsize",label="fs"},
{x=5,y=5,class="checkbox",name="fspace",label="fsp"},
{x=5,y=6,class="checkbox",name="scalex",label="fscx"},
{x=5,y=7,class="checkbox",name="scaley",label="fscy"},
{x=5,y=8,class="checkbox",name="fname",label="fn"},
{x=5,y=9,class="checkbox",name="ital",label="i"},
{x=5,y=10,class="checkbox",name="bold",label="b"},
{x=5,y=11,class="checkbox",name="under",label="u"},
{x=5,y=12,class="checkbox",name="stri",label="s"},
{x=5,y=13,class="checkbox",name="wrap",label="q"},
{x=6,y=1,class="checkbox",name="bee",label="be"},
{x=6,y=2,class="checkbox",name="color1",label="c, 1c"},
{x=6,y=3,class="checkbox",name="color2",label="2c"},
{x=6,y=4,class="checkbox",name="color3",label="3c"},
{x=6,y=5,class="checkbox",name="color4",label="4c"},
{x=6,y=6,class="checkbox",name="alpha",label="alpha"},
{x=6,y=7,class="checkbox",name="alfa1",label="1a"},
{x=6,y=8,class="checkbox",name="alfa2",label="2a"},
{x=6,y=9,class="checkbox",name="alfa3",label="3a"},
{x=6,y=10,class="checkbox",name="alfa4",label="4a"},
{x=6,y=11,class="checkbox",name="align",label="a"},
{x=6,y=12,class="checkbox",name="anna",label="an"},
{x=6,y=13,class="checkbox",name="clip",label="(i)clip"},
{x=7,y=2,class="checkbox",name="fade",label="fad"},
{x=7,y=3,class="checkbox",name="posi",label="pos"},
{x=7,y=4,class="checkbox",name="move",label="move"},
{x=7,y=5,class="checkbox",name="org",label="org"},
{x=7,y=6,class="checkbox",name="frz",label="frz"},
{x=7,y=7,class="checkbox",name="frx",label="frx"},
{x=7,y=8,class="checkbox",name="fry",label="fry"},
{x=7,y=9,class="checkbox",name="fax",label="fax"},
{x=7,y=10,class="checkbox",name="fay",label="fay"},
{x=7,y=11,width=2,class="checkbox",name="kara",label="k/kf/ko"},
{x=7,y=12,class="checkbox",name="return",label="r"},
{x=7,y=13,class="checkbox",name="trans",label="t"},
{x=8,y=12,height=2,class="checkbox",name="hidline",label="hide\ninline",hint='Hide ALL inline tags'},
}
P,res=ADD(GUI,
{"Run selected","Comments","Tags","Dial 5","Clean Tags","^ Kill Tags","Hide Tags","Cancer"},{ok='Run selected',cancel='Cancer'})
if P=="Cancer" then ak() end
if P=="^ Kill Tags" then killemall(subs,sel) end
if P=="Hide Tags" then hide_tags(subs,sel) end
if P=="Comments" then res.nocom=true cleanlines(subs,sel) end
if P=="Tags" then res.notag=true cleanlines(subs,sel) end
if P=="Dial 5" then res.layers=true cleanlines(subs,sel) end
if P=="Clean Tags" then res.cleantag=true cleanlines(subs,sel) end
if P=="Run selected" then
C=0 for key,v in ipairs(GUI) do if v.x<=3 and res[v.name] then C=1 end end
if C==0 then t_error("Run Selected: Error - nothing selected",1) end
if res.all then
for key,v in ipairs(GUI) do if v.x>0 and v.name then res[v.name]=false end end
cleanlines(subs,sel)
sel=noemptycom(subs,sel)
else cleanlines(subs,sel)
if res.nocomline and res.noempty then sel=noemptycom(subs,sel)
else
if res.nocomline then sel=nocom_line(subs,sel) end
if res.noempty then sel=noempty(subs,sel) end
end
table.sort(sel)
if res.nostyle or res.nostyle2 then sel=nostyle(subs,sel) end
end
end
if act>#subs then act=#subs end
return sel,act
end
if haveDepCtrl then depRec:registerMacro(cleanup) else aegisub.register_macro(script_name,script_description,cleanup) end

View File

@ -0,0 +1,43 @@
local tr = aegisub.gettext
script_name = tr"unkf"
script_description = tr"replace kf/ko tags in selected lines by regular k tags"
script_author = "amoethyst"
script_version = "1.0"
function split_line(subs, sel)
local expr_kof = "^(.-{[^}]*\\k)[of](.*)$"
local expr_K = "^(.-{[^}]*\\)K(.*)$"
local before, after
for _, i in ipairs(sel) do
line = subs[i]
-- replace ko and kf tags
while true do
before, after = line.text:match(expr_kof)
if before == nil then
break
else
line.text = before .. after
end
end
-- replace K tags
while true do
before, after = line.text:match(expr_K)
if before == nil then
break
else
line.text = before .. "k" .. after
end
end
subs[i] = line
end
aegisub.set_undo_point(script_name)
end
aegisub.register_macro(script_name, script_description, split_line)

View File

@ -22,7 +22,6 @@ namespace agi {
line_iterator_base::line_iterator_base(std::istream &stream, std::string encoding)
: stream(&stream)
{
boost::to_lower(encoding);
if (encoding != "utf-8") {
agi::charset::IconvWrapper c("utf-8", encoding.c_str());
c.Convert("\r", 1, reinterpret_cast<char *>(&cr), sizeof(int));

View File

@ -50,6 +50,8 @@ ArchitecturesAllowed=x64
#include "fragment_automation.iss"
#include "fragment_translations.iss"
#include "fragment_spelling.iss"
#include "fragment_fonts.iss"
#ifdef DEPCTRL
#include "fragment_runtimes.iss"
[Code]

View File

@ -36,10 +36,22 @@
[Files]
DestDir: {app}\automation\autoload; Source: ..\..\automation\autoload\cleantags-autoload.lua; Flags: ignoreversion overwritereadonly uninsremovereadonly; Attribs: readonly; Components: macros\bundled
DestDir: {app}\automation\autoload; Source: ..\..\automation\autoload\karaoke-auto-leadin.lua; Flags: ignoreversion overwritereadonly uninsremovereadonly; Attribs: readonly; Components: macros\bundled
DestDir: {app}\automation\autoload; Source: ..\..\automation\autoload\kara-templater.lua; Flags: ignoreversion overwritereadonly uninsremovereadonly; Attribs: readonly; Components: macros\bundled
DestDir: {app}\automation\autoload; Source: ..\..\automation\autoload\select-overlaps.moon; Flags: ignoreversion overwritereadonly uninsremovereadonly; Attribs: readonly; Components: macros\bundled
DestDir: {app}\automation\autoload; Source: ..\..\automation\autoload\strip-tags.lua; Flags: ignoreversion overwritereadonly uninsremovereadonly; Attribs: readonly; Components: macros\bundled
DestDir: {app}\automation\autoload; Source: ..\..\automation\autoload\cleantags-autoload.lua; Flags: ignoreversion overwritereadonly uninsremovereadonly; Attribs: readonly; Components: macros\bundled
DestDir: {app}\automation\autoload; Source: ..\..\automation\autoload\duetto-meika.lua; Flags: ignoreversion overwritereadonly uninsremovereadonly; Attribs: readonly; Components: macros\bundled
DestDir: {app}\automation\autoload; Source: ..\..\automation\autoload\karaoke-adjust-1sec.lua; Flags: ignoreversion overwritereadonly uninsremovereadonly; Attribs: readonly; Components: macros\bundled
DestDir: {app}\automation\autoload; Source: ..\..\automation\autoload\karaoke-split.lua; Flags: ignoreversion overwritereadonly uninsremovereadonly; Attribs: readonly; Components: macros\bundled
DestDir: {app}\automation\autoload; Source: ..\..\automation\autoload\kara-templater.lua; Flags: ignoreversion overwritereadonly uninsremovereadonly; Attribs: readonly; Components: macros\bundled
DestDir: {app}\automation\autoload; Source: ..\..\automation\autoload\ua.BlurAndGlow.lua; Flags: ignoreversion overwritereadonly uninsremovereadonly; Attribs: readonly; Components: macros\bundled
DestDir: {app}\automation\autoload; Source: ..\..\automation\autoload\ua.ChangeCase.lua; Flags: ignoreversion overwritereadonly uninsremovereadonly; Attribs: readonly; Components: macros\bundled
DestDir: {app}\automation\autoload; Source: ..\..\automation\autoload\ua.Colorize.lua; Flags: ignoreversion overwritereadonly uninsremovereadonly; Attribs: readonly; Components: macros\bundled
DestDir: {app}\automation\autoload; Source: ..\..\automation\autoload\ua.Cycles.lua; Flags: ignoreversion overwritereadonly uninsremovereadonly; Attribs: readonly; Components: macros\bundled
DestDir: {app}\automation\autoload; Source: ..\..\automation\autoload\ua.FadeWorks.lua; Flags: ignoreversion overwritereadonly uninsremovereadonly; Attribs: readonly; Components: macros\bundled
DestDir: {app}\automation\autoload; Source: ..\..\automation\autoload\ua.HYDRA.lua; Flags: ignoreversion overwritereadonly uninsremovereadonly; Attribs: readonly; Components: macros\bundled
DestDir: {app}\automation\autoload; Source: ..\..\automation\autoload\ua.ScriptCleanup.lua; Flags: ignoreversion overwritereadonly uninsremovereadonly; Attribs: readonly; Components: macros\bundled
DestDir: {app}\automation\autoload; Source: ..\..\automation\autoload\unkf.lua; Flags: ignoreversion overwritereadonly uninsremovereadonly; Attribs: readonly; Components: macros\bundled
DestDir: {app}\automation\demos; Source: ..\..\automation\demos\future-windy-blur.lua; Flags: ignoreversion overwritereadonly uninsremovereadonly; Attribs: readonly; Components: macros\demos
DestDir: {app}\automation\demos; Source: ..\..\automation\demos\raytracer.lua; Flags: ignoreversion overwritereadonly uninsremovereadonly; Attribs: readonly; Components: macros\demos

View File

@ -34,8 +34,8 @@
[Files]
; Avisynth
DestDir: {app}; Source: vendor\AvisynthPlus64\devil.dll; Flags: ignoreversion; Components: main
DestDir: {app}; Source: vendor\AvisynthPlus64\avisynth.dll; Flags: ignoreversion; Components: main
DestDir: {app}; Source: vendor\AvisynthPlus64\DirectShowSource.dll; Flags: ignoreversion; Components: main
DestDir: {app}; Source: ..\..\bin\devil.dll; Flags: ignoreversion; Components: main
DestDir: {app}; Source: ..\..\bin\avisynth.dll; Flags: ignoreversion; Components: main
DestDir: {app}; Source: ..\..\bin\DirectShowSource.dll; Flags: ignoreversion; Components: main
; VSFilter
DestDir: {app}\csri; Source: vendor\xy-vsfilter\xy-vsfilter-aegisub64.dll; Flags: ignoreversion; Components: main
DestDir: {app}\csri; Source: ..\..\bin\csri\xy-vsfilter-aegisub64.dll; Flags: ignoreversion; Components: main

View File

@ -0,0 +1,7 @@
[Files]
DestDir: {app}\FontsLicenses; DestName: Amaranth-OFL.txt; Source: ..\..\vendor\japan7-fonts\Amaranth\OFL.txt; Flags: ignoreversion; Components: fonts
DestDir: "{fonts}"; FontInstall: "Amaranth"; Source: ..\..\vendor\japan7-fonts\Amaranth\Amaranth-Regular.ttf; Flags: onlyifdoesntexist uninsneveruninstall; Components: fonts
DestDir: "{fonts}"; FontInstall: "Amaranth"; Source: ..\..\vendor\japan7-fonts\Amaranth\Amaranth-Bold.ttf; Flags: onlyifdoesntexist uninsneveruninstall; Components: fonts
DestDir: "{fonts}"; FontInstall: "Amaranth"; Source: ..\..\vendor\japan7-fonts\Amaranth\Amaranth-Italic.ttf; Flags: onlyifdoesntexist uninsneveruninstall; Components: fonts
DestDir: "{fonts}"; FontInstall: "Amaranth"; Source: ..\..\vendor\japan7-fonts\Amaranth\Amaranth-BoldItalic.ttf; Flags: onlyifdoesntexist uninsneveruninstall; Components: fonts

View File

@ -46,6 +46,7 @@ Name: "macros\modules\luajson"; Description: "LuaJSON"; Types: full
Name: "dictionaries"; Description: "Spellcheck Dictionaries"; Types: full
Name: "dictionaries\en_US"; Description: "English (US)"; Types: full
Name: "translations"; Description: "Aegisub Translations"; Types: full
Name: "fonts"; Description: "Bundled fonts"; Types: full
[Tasks]
Name: "startmenuicon"; Description: "{cm:StartMenuIcon}"; GroupDescription: "{cm:AdditionalIcons}"
@ -55,6 +56,8 @@ Name: "checkforupdates"; Description: "{cm:CheckForUpdates}"; GroupDescription:
; main
DestDir: {app}; Source: ..\..\bin\aegisub{#ARCH}.exe; Flags: ignoreversion; Components: main
DestDir: {app}; Source: license.txt; Flags: ignoreversion; Components: main
DestDir: {app}; Source: ..\..\bin\libcrypto-1_1-x64.dll; Flags: ignoreversion; Components: main
DestDir: {app}; Source: ..\..\bin\libssl-1_1-x64.dll; Flags: ignoreversion; Components: main
[Icons]
Name: {commonprograms}\Aegisub; Filename: {app}\aegisub{#ARCH}.exe; WorkingDir: {app}; IconIndex: 0; Tasks: startmenuicon; Comment: Create and edit subtitle files

View File

@ -32,7 +32,8 @@
; Contact: mailto:nielsm@indvikleren.dk
;
#include "../../build/git_version.h"
#define BUILD_GIT_VERSION_STRING "Japan7 0.9"
#define INSTALLER_VERSION 1
#define CURRENT_YEAR GetDateTimeString('yyyy', '', '');
@ -64,27 +65,22 @@ UninstallDisplayIcon={app}\aegisub{#ARCH}.exe
WizardImageFile=welcome-large.bmp
WizardSmallImageFile=aegisub-large.bmp
OutputBaseFilename=Aegisub-{#BUILD_GIT_VERSION_STRING}-{#ARCH}
VersionInfoDescription=Aegisub {#BUILD_GIT_VERSION_STRING} {#ARCH}-bit
OutputBaseFilename=Aegisub-Japan7-x64
VersionInfoDescription=Aegisub {#BUILD_GIT_VERSION_STRING} x64
[Languages]
Name: "en"; MessagesFile: "compiler:Default.isl"
Name: "bg"; MessagesFile: "compiler:Languages\Bulgarian.isl"
Name: "ca"; MessagesFile: "compiler:Languages\Catalan.isl"
Name: "cz"; MessagesFile: "compiler:Languages\Czech.isl"
Name: "da"; MessagesFile: "compiler:Languages\Danish.isl"
Name: "de"; MessagesFile: "compiler:Languages\German.isl"
Name: "el"; MessagesFile: "compiler:Languages\Greek.isl"
Name: "es"; MessagesFile: "compiler:Languages\Spanish.isl"
Name: "eu"; MessagesFile: "compiler:Languages\Basque.isl"
Name: "fi"; MessagesFile: "compiler:Languages\Finnish.isl"
Name: "fr_FR"; MessagesFile: "compiler:Languages\French.isl"
Name: "gl"; MessagesFile: "compiler:Languages\Galician.isl"
Name: "hu"; MessagesFile: "compiler:Languages\Hungarian.isl"
Name: "id"; MessagesFile: "compiler:Languages\Indonesian.isl"
Name: "it"; MessagesFile: "compiler:Languages\Italian.isl"
Name: "ja"; MessagesFile: "compiler:Languages\Japanese.isl"
Name: "ko"; MessagesFile: "compiler:Languages\Korean.isl"
Name: "nl"; MessagesFile: "compiler:Languages\Dutch.isl"
Name: "pl"; MessagesFile: "compiler:Languages\Polish.isl"
Name: "pt_BR"; MessagesFile: "compiler:Languages\BrazilianPortuguese.isl"
@ -93,8 +89,6 @@ Name: "ru"; MessagesFile: "compiler:Languages\Russian.isl"
Name: "sr_RS"; MessagesFile: "compiler:Languages\SerbianCyrillic.isl"
Name: "sr_RS_latin"; MessagesFile: "compiler:Languages\SerbianLatin.isl"
Name: "uk_UA"; MessagesFile: "compiler:Languages\Ukrainian.isl"
Name: "zh_CN"; MessagesFile: "compiler:Languages\ChineseSimplified.isl"
Name: "zh_TW"; MessagesFile: "compiler:Languages\ChineseTraditional.isl"
[Files]
; small bitmaps (used by beautify code)

View File

@ -1,44 +1,24 @@
[CustomMessages]
InstallRuntime=Installing runtime libraries...
el.InstallRuntime=Εγκατάσταση βιβλιοθηκών...
eu.InstallRuntime=Runtime liburutegiak ezartzen...
id.InstallRuntime=Memasang runtime libraries...
pt_PT.InstallRuntime=A instalar livrarias de runtime...
uk_UA.InstallRuntime=Встановлюю бібліотеки реального часу...
zh_CN.InstallRuntime=正在安装运行库……
zh_TW.InstallRuntime=正在安裝運行庫……
StartMenuIcon=Create a start menu icon
el.StartMenuIcon=Δημιουργία εικονιδίου στο μενού έναρξης
eu.StartMenuIcon=Sortu hasiera menuko ikur bat
id.StartMenuIcon=Buat ikon di menu awal
pt_PT.StartMenuIcon=Criar ícone no menu iniciar
uk_UA.StartMenuIcon=Створити піктограму в меню Запустити
zh_CN.StartMenuIcon=创建开始菜单图标
zh_TW.StartMenuIcon=創建開始功能表圖示
CheckForUpdates=Automatically check for new versions of Aegisub
el.CheckForUpdates=Αυτόματος έλεγχος για καινούριες εκδόσεις του Aegisub
eu.CheckForUpdates=Berezgaitasunez egiaztatu Aegisub-ren bertsio berririk dagoen
id.CheckForUpdates=Otomatis cek versi terbaru Aegisub
pt_PT.CheckForUpdates=Verifica automaticamente a existência de novas versões do Aegisub
uk_UA.CheckForUpdates=Автоматично перевіряти Aegisub на нові версії
zh_CN.CheckForUpdates=自动检查Aegisub的新版本
zh_TW.CheckForUpdates=自動檢查Aegisub的新版本
UpdatesGroup=Update Checker:
el.UpdatesGroup=Έλεγχος Ενημερώσεων:
eu.UpdatesGroup=Eguneraketa Egiaztatzailea:
id.UpdatesGroup=Pemeriksa Pembaharuan
pt_PT.UpdatesGroup=Verificar Actualizações:
uk_UA.UpdatesGroup=Модуль Перевірки на Оновлення:
zh_CN.UpdatesGroup=自动更新:
zh_TW.UpdatesGroup=自動更新:
; Replacement for License page, no need to bother the user with legal mumbo-jumbo
[Messages]
WelcomeLabel2=This will install Aegisub {#BUILD_GIT_VERSION_STRING} on your computer.%n%nAegisub is covered by the GNU General Public License version 2. This means you may use the application for any purpose without charge, but that no warranties of any kind are given either.%n%nSee the Aegisub website for information on obtaining the source code.
el.WelcomeLabel2=Αυτό θα εγκαταστήσει το Aegisub {#BUILD_GIT_VERSION_STRING} στον υπολογιστή σας.%n%nΤο Aegisub καλύπτεται από τον άδεια GNU General Public License version 2. Αυτό σημαίνει ότι μπορείτε να χρησιμοποιήσετε την εφαρμογή για κάθε σκοπό χωρίς χρέωση, αλλά δεν υπάρχουν εγγυήσεις καμίας φύσης.%n%nΔείτε την ιστοσελίδα του Aegisub για πληροφορίες σχετικά με την απόκτηση του πηγαίου κώδικα.
eu.WelcomeLabel2=Honek Aegisub {#BUILD_GIT_VERSION_STRING} ezarriko du zure ordenagailuan.%n%nAegisub GNU Baimen Publiko Orokorra 2. bertsioa Baimenak estalia dago. Honek esanahi du aplikazio hau edozein asmotarako erabili dezakezula ordaindu behar izan gabe, baina ez da inolako berme motarik ematen.%n%nIkusi Aegisub webgunea iturburu kodea lortzeko argibideetarako.
id.WelcomeLabel2=Ini akan memasang Aegisub {#BUILD_GIT_VERSION_STRING} di komputer Anda.%n%nAegisub dilindungi oleh Lisensi Publik Umum GNU versi 2. Artinya Anda bisa menggunakan aplikasi ini untuk tujuan apa pun tanpad dipungut biaya, tapi tidak ada jaminan yang bisa diberikan.%n%nLihat laman situs Aegisub untuk memperoleh informasi sumber kode.
pt_PT.WelcomeLabel2=Irá ser instalado no seu computador a versão {#BUILD_GIT_VERSION_STRING} do Aegisub.%n%nO Aegisub está protegido sob a Licença Pública Geral GNU (GPL version 2). O que significa que poderá fazer uso da aplicação para qualquer propósito, sem que seja cobrado, mas não serão dadas quaisquer tipos de garantias.%n%nVeja a página do Aegisub para mais informações sobre como obter o código-fonte.
uk_UA.WelcomeLabel2=Зараз буде встанвлено Aegisub {#BUILD_GIT_VERSION_STRING} на ваш комп'ютер.%n%nAegisub захищено універсальною громадською ліцензією GNU, версія 2. Це означає, що ви можете використосувати цю програму для будь яких цілей безкоштовно, але, в будь-якому випадку, ми не даємо жодних гарантій.%n%nДивіться сайт Aegisub для інформації щодо отримання вихідного коду.
zh_CN.WelcomeLabel2=将会在您的电脑上安装Aegisub {#BUILD_GIT_VERSION_STRING} 。%n%n Aegisub适用于GNU通用公共许可证第二版(GPLv2),这意味着您可以将该应用程序用于任何目的而不需要支付费用,但同时也不会得到任何形式的担保。%n%n您可以到Aegisub官网获取源代码信息。
zh_TW.WelcomeLabel2=將會在您的電腦上安裝Aegisub {#BUILD_GIT_VERSION_STRING} 。%n%n Aegisub適用於GNU通用公共許可證第二版(GPLv2),這意味著您可以將該應用程式用於任何目的而不需要支付費用,但同時也不會得到任何形式的擔保。%n%n您可以到Aegisub官網獲取原始程式碼資訊。

View File

@ -38,61 +38,61 @@
[Files]
; localization (commented out ones are out of date; some don't have wxstd.mo)
Source: ..\..\po\ar.mo; DestDir: {app}\locale\ar; DestName: aegisub.mo; Flags: ignoreversion; Components: translations
Source: src\mo\wxstd-ar.mo; DestDir: {app}\locale\ar; DestName: wxstd.mo; Flags: ignoreversion; Components: translations
Source: ..\..\po\wxstd-ar.mo; DestDir: {app}\locale\ar; DestName: wxstd.mo; Flags: ignoreversion; Components: translations
Source: ..\..\po\bg.mo; DestDir: {app}\locale\bg; DestName: aegisub.mo; Flags: ignoreversion; Components: translations
; Missing wxstd for Bulgarian
Source: ..\..\po\ca.mo; DestDir: {app}\locale\ca; DestName: aegisub.mo; Flags: ignoreversion; Components: translations
Source: src\mo\wxstd-ca.mo; DestDir: {app}\locale\ca; DestName: wxstd.mo; Flags: ignoreversion; Components: translations
Source: ..\..\po\wxstd-ca.mo; DestDir: {app}\locale\ca; DestName: wxstd.mo; Flags: ignoreversion; Components: translations
Source: ..\..\po\cs.mo; DestDir: {app}\locale\cs; DestName: aegisub.mo; Flags: ignoreversion; Components: translations
Source: src\mo\wxstd-cs.mo; DestDir: {app}\locale\cs; DestName: wxstd.mo; Flags: ignoreversion; Components: translations
Source: ..\..\po\wxstd-cs.mo; DestDir: {app}\locale\cs; DestName: wxstd.mo; Flags: ignoreversion; Components: translations
Source: ..\..\po\da.mo; DestDir: {app}\locale\da; DestName: aegisub.mo; Flags: ignoreversion; Components: translations
Source: src\mo\wxstd-da.mo; DestDir: {app}\locale\da; DestName: wxstd.mo; Flags: ignoreversion; Components: translations
Source: ..\..\po\wxstd-da.mo; DestDir: {app}\locale\da; DestName: wxstd.mo; Flags: ignoreversion; Components: translations
Source: ..\..\po\de.mo; DestDir: {app}\locale\de; DestName: aegisub.mo; Flags: ignoreversion; Components: translations
Source: src\mo\wxstd-de.mo; DestDir: {app}\locale\de; DestName: wxstd.mo; Flags: ignoreversion; Components: translations
Source: ..\..\po\wxstd-de.mo; DestDir: {app}\locale\de; DestName: wxstd.mo; Flags: ignoreversion; Components: translations
Source: ..\..\po\el.mo; DestDir: {app}\locale\el; DestName: aegisub.mo; Flags: ignoreversion; Components: translations
Source: src\mo\wxstd-el.mo; DestDir: {app}\locale\el; DestName: wxstd.mo; Flags: ignoreversion; Components: translations
Source: ..\..\po\wxstd-el.mo; DestDir: {app}\locale\el; DestName: wxstd.mo; Flags: ignoreversion; Components: translations
Source: ..\..\po\es.mo; DestDir: {app}\locale\es; DestName: aegisub.mo; Flags: ignoreversion; Components: translations
Source: src\mo\wxstd-es.mo; DestDir: {app}\locale\es; DestName: wxstd.mo; Flags: ignoreversion; Components: translations
Source: ..\..\po\wxstd-es.mo; DestDir: {app}\locale\es; DestName: wxstd.mo; Flags: ignoreversion; Components: translations
Source: ..\..\po\eu.mo; DestDir: {app}\locale\eu; DestName: aegisub.mo; Flags: ignoreversion; Components: translations
Source: src\mo\wxstd-eu.mo; DestDir: {app}\locale\eu; DestName: wxstd.mo; Flags: ignoreversion; Components: translations
Source: ..\..\po\wxstd-eu.mo; DestDir: {app}\locale\eu; DestName: wxstd.mo; Flags: ignoreversion; Components: translations
Source: ..\..\po\fa.mo; DestDir: {app}\locale\fa; DestName: aegisub.mo; Flags: ignoreversion; Components: translations
; Farsi wxstd missing
;Source: src\mo\wxstd-fa.mo; DestDir: {app}\locale\fa; DestName: wxstd.mo; Flags: ignoreversion; Components: translations
;Source: ..\..\po\wxstd-fa.mo; DestDir: {app}\locale\fa; DestName: wxstd.mo; Flags: ignoreversion; Components: translations
Source: ..\..\po\fi.mo; DestDir: {app}\locale\fi; DestName: aegisub.mo; Flags: ignoreversion; Components: translations
Source: src\mo\wxstd-fi.mo; DestDir: {app}\locale\fi; DestName: wxstd.mo; Flags: ignoreversion; Components: translations
Source: ..\..\po\wxstd-fi.mo; DestDir: {app}\locale\fi; DestName: wxstd.mo; Flags: ignoreversion; Components: translations
Source: ..\..\po\fr_FR.mo; DestDir: {app}\locale\fr_FR; DestName: aegisub.mo; Flags: ignoreversion; Components: translations
Source: src\mo\wxstd-fr.mo; DestDir: {app}\locale\fr_FR; DestName: wxstd.mo; Flags: ignoreversion; Components: translations
Source: ..\..\po\wxstd-fr.mo; DestDir: {app}\locale\fr_FR; DestName: wxstd.mo; Flags: ignoreversion; Components: translations
Source: ..\..\po\gl.mo; DestDir: {app}\locale\gl; DestName: aegisub.mo; Flags: ignoreversion; Components: translations
Source: src\mo\wxstd-gl_ES.mo; DestDir: {app}\locale\gl; DestName: wxstd.mo; Flags: ignoreversion; Components: translations
Source: ..\..\po\wxstd-gl_ES.mo; DestDir: {app}\locale\gl; DestName: wxstd.mo; Flags: ignoreversion; Components: translations
Source: ..\..\po\hu.mo; DestDir: {app}\locale\hu; DestName: aegisub.mo; Flags: ignoreversion; Components: translations
Source: src\mo\wxstd-hu.mo; DestDir: {app}\locale\hu; DestName: wxstd.mo; Flags: ignoreversion; Components: translations
Source: ..\..\po\wxstd-hu.mo; DestDir: {app}\locale\hu; DestName: wxstd.mo; Flags: ignoreversion; Components: translations
Source: ..\..\po\id.mo; DestDir: {app}\locale\id; DestName: aegisub.mo; Flags: ignoreversion; Components: translations
Source: src\mo\wxstd-id.mo; DestDir: {app}\locale\id; DestName: wxstd.mo; Flags: ignoreversion; Components: translations
Source: ..\..\po\wxstd-id.mo; DestDir: {app}\locale\id; DestName: wxstd.mo; Flags: ignoreversion; Components: translations
Source: ..\..\po\it.mo; DestDir: {app}\locale\it; DestName: aegisub.mo; Flags: ignoreversion; Components: translations
Source: src\mo\wxstd-it.mo; DestDir: {app}\locale\it; DestName: wxstd.mo; Flags: ignoreversion; Components: translations
Source: ..\..\po\wxstd-it.mo; DestDir: {app}\locale\it; DestName: wxstd.mo; Flags: ignoreversion; Components: translations
Source: ..\..\po\ja.mo; DestDir: {app}\locale\ja; DestName: aegisub.mo; Flags: ignoreversion; Components: translations
Source: src\mo\wxstd-ja.mo; DestDir: {app}\locale\ja; DestName: wxstd.mo; Flags: ignoreversion; Components: translations
Source: ..\..\po\wxstd-ja.mo; DestDir: {app}\locale\ja; DestName: wxstd.mo; Flags: ignoreversion; Components: translations
Source: ..\..\po\ko.mo; DestDir: {app}\locale\ko; DestName: aegisub.mo; Flags: ignoreversion; Components: translations
Source: src\mo\wxstd-ko_KR.mo; DestDir: {app}\locale\ko; DestName: wxstd.mo; Flags: ignoreversion; Components: translations
Source: ..\..\po\wxstd-ko_KR.mo; DestDir: {app}\locale\ko; DestName: wxstd.mo; Flags: ignoreversion; Components: translations
Source: ..\..\po\nl.mo; DestDir: {app}\locale\nl; DestName: aegisub.mo; Flags: ignoreversion; Components: translations
Source: src\mo\wxstd-nl.mo; DestDir: {app}\locale\nl; DestName: wxstd.mo; Flags: ignoreversion; Components: translations
Source: ..\..\po\wxstd-nl.mo; DestDir: {app}\locale\nl; DestName: wxstd.mo; Flags: ignoreversion; Components: translations
Source: ..\..\po\pl.mo; DestDir: {app}\locale\pl; DestName: aegisub.mo; Flags: ignoreversion; Components: translations
Source: src\mo\wxstd-pl.mo; DestDir: {app}\locale\pl; DestName: wxstd.mo; Flags: ignoreversion; Components: translations
Source: ..\..\po\wxstd-pl.mo; DestDir: {app}\locale\pl; DestName: wxstd.mo; Flags: ignoreversion; Components: translations
Source: ..\..\po\pt_BR.mo; DestDir: {app}\locale\pt_BR; DestName: aegisub.mo; Flags: ignoreversion; Components: translations
Source: src\mo\wxstd-pt_BR.mo; DestDir: {app}\locale\pt_BR; DestName: wxstd.mo; Flags: ignoreversion; Components: translations
Source: ..\..\po\wxstd-pt_BR.mo; DestDir: {app}\locale\pt_BR; DestName: wxstd.mo; Flags: ignoreversion; Components: translations
Source: ..\..\po\pt_PT.mo; DestDir: {app}\locale\pt_PT; DestName: aegisub.mo; Flags: ignoreversion; Components: translations
Source: src\mo\wxstd-pt.mo; DestDir: {app}\locale\pt_PT; DestName: wxstd.mo; Flags: ignoreversion; Components: translations
Source: ..\..\po\wxstd-pt.mo; DestDir: {app}\locale\pt_PT; DestName: wxstd.mo; Flags: ignoreversion; Components: translations
Source: ..\..\po\ru.mo; DestDir: {app}\locale\ru; DestName: aegisub.mo; Flags: ignoreversion; Components: translations
Source: src\mo\wxstd-ru.mo; DestDir: {app}\locale\ru; DestName: wxstd.mo; Flags: ignoreversion; Components: translations
Source: ..\..\po\wxstd-ru.mo; DestDir: {app}\locale\ru; DestName: wxstd.mo; Flags: ignoreversion; Components: translations
Source: ..\..\po\sr_RS.mo; DestDir: {app}\locale\sr_RS; DestName: aegisub.mo; Flags: ignoreversion; Components: translations
Source: ..\..\po\sr_RS@latin.mo; DestDir: {app}\locale\sr_RS@latin; DestName: aegisub.mo; Flags: ignoreversion; Components: translations
; Missing wxstd for Serbian
Source: ..\..\po\uk_UA.mo; DestDir: {app}\locale\uk_UA; DestName: aegisub.mo; Flags: ignoreversion; Components: translations
Source: src\mo\wxstd-uk_UA.mo; DestDir: {app}\locale\uk_UA; DestName: wxstd.mo; Flags: ignoreversion; Components: translations
Source: ..\..\po\wxstd-uk_UA.mo; DestDir: {app}\locale\uk_UA; DestName: wxstd.mo; Flags: ignoreversion; Components: translations
Source: ..\..\po\vi.mo; DestDir: {app}\locale\vi; DestName: aegisub.mo; Flags: ignoreversion; Components: translations
Source: src\mo\wxstd-vi.mo; DestDir: {app}\locale\vi; DestName: wxstd.mo; Flags: ignoreversion; Components: translations
Source: ..\..\po\wxstd-vi.mo; DestDir: {app}\locale\vi; DestName: wxstd.mo; Flags: ignoreversion; Components: translations
Source: ..\..\po\zh_CN.mo; DestDir: {app}\locale\zh_CN; DestName: aegisub.mo; Flags: ignoreversion; Components: translations
Source: src\mo\wxstd-zh_CN.mo; DestDir: {app}\locale\zh_CN; DestName: wxstd.mo; Flags: ignoreversion; Components: translations
Source: ..\..\po\wxstd-zh_CN.mo; DestDir: {app}\locale\zh_CN; DestName: wxstd.mo; Flags: ignoreversion; Components: translations
Source: ..\..\po\zh_TW.mo; DestDir: {app}\locale\zh_TW; DestName: aegisub.mo; Flags: ignoreversion; Components: translations
Source: src\mo\wxstd-zh_TW.mo; DestDir: {app}\locale\zh_TW; DestName: wxstd.mo; Flags: ignoreversion; Components: translations
Source: ..\..\po\wxstd-zh_TW.mo; DestDir: {app}\locale\zh_TW; DestName: wxstd.mo; Flags: ignoreversion; Components: translations

View File

@ -3069,6 +3069,18 @@ msgstr ""
msgid "Website"
msgstr ""
#: ../src/command/help.cpp
msgid "&Joysound Exporter"
msgstr ""
#: ../src/command/help.cpp
msgid "Joysound Exporter"
msgstr ""
#: ../src/command/help.cpp
msgid "Export karaoke from Joysound"
msgstr ""
#: ../src/command/help.cpp:119
msgid "Visit Aegisub's official website"
msgstr ""

View File

@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Aegisub 3.2.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-08-24 16:41+0200\n"
"POT-Creation-Date: 2014-07-01 10:53-0700\n"
"PO-Revision-Date: \n"
"Last-Translator: Cirrus Wazza <cirrus_wazza@gmx.fr>\n"
"Language-Team: Céréales Killer <cerkil@free.fr>\n"
@ -12,7 +12,7 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"X-Poedit-SourceCharset: UTF-8\n"
"X-Poedit-Bookmarks: -1,596,-1,-1,-1,-1,-1,-1,-1,-1\n"
"X-Generator: Poedit 1.8.4\n"
"X-Generator: Poedit 2.2.4\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
#: ../src/dialog_shift_times.cpp:92
@ -3189,6 +3189,18 @@ msgstr "Site &web"
msgid "Website"
msgstr "Site web"
#: ../src/command/help.cpp
msgid "&Joysound Exporter"
msgstr "&Joysound Exporter"
#: ../src/command/help.cpp
msgid "Joysound Exporter"
msgstr "Joysound Exporter"
#: ../src/command/help.cpp
msgid "Export karaoke from Joysound"
msgstr "Exporter un karaoke Joysound"
#: ../src/command/help.cpp:119
msgid "Visit Aegisub's official website"
msgstr "Visitez le site officiel d'Aegisub"

View File

@ -6,7 +6,7 @@ src_CPPFLAGS := -I$(d) -I.. -I$(d)include -I$(TOP)libaegisub/include -I$(TOP)bui
$(CFLAGS_PTHREAD) $(CFLAGS_FFTW3) $(CFLAGS_ICU) $(CPPFLAGS_BOOST)
src_CXXFLAGS := $(CXXFLAGS_WX)
src_LIBS := $(LIBS_GL) $(LIBS_PTHREAD) $(LIBS_WX) $(LIBS_FREETYPE) \
$(LIBS_LIBASS) $(LIBS_FONTCONFIG) $(LIBS_FFTW3) $(LIBS_BOOST) $(LIBS_ICU)
$(LIBS_LIBASS) $(LIBS_FONTCONFIG) $(LIBS_FFTW3) $(LIBS_BOOST) $(LIBS_ICU)
src_PCH := $(d)agi_pre.h
src_INSTALLNAME := $(AEGISUB_COMMAND)
@ -111,11 +111,16 @@ src_OBJ := \
$(d)video_provider_yuv4mpeg.o \
$(d)video_slider.o \
$(d)visual_feature.o \
$(LIBS_LUA) \
$(TOP)lib/libaegisub.a \
$(TOP)lib/libluabins.a \
$(TOP)lib/libresrc.a \
ifeq (no, $(SYSTEM_LUAJIT))
src_OBJ += $(LIBS_LUA)
else
src_LIBS += $(LIBS_LUA)
endif
ifeq (yes, $(BUILD_DARWIN))
src_OBJ += $(d)font_file_lister_coretext.o
src_OBJ += $(patsubst %.mm,%.o,$(sort $(wildcard $(d)osx/*.mm)))

View File

@ -1088,8 +1088,9 @@ static void parseSegmentInfo(MatroskaFile *mf,uint64_t toplen) {
static void parseFirstCluster(MatroskaFile *mf,uint64_t toplen) {
uint64_t end = filepos(mf) + toplen;
int tracknum = -1;
int i = 0;
mf->seen.Cluster = 1;
mf->firstTimecode = 0;
FOREACH(mf,toplen)
@ -1097,22 +1098,40 @@ static void parseFirstCluster(MatroskaFile *mf,uint64_t toplen) {
mf->firstTimecode += readUInt(mf,(unsigned)len);
break;
case 0xa3: // BlockEx
readVLUInt(mf); // track number
mf->firstTimecode += readSInt(mf, 2);
start = filepos(mf);
tracknum = readVLUInt(mf); // track number
skipbytes(mf,end - filepos(mf));
return;
for (i = 0; i < mf->nTracks; ++i) {
if (mf->Tracks[i]->Number == tracknum && mf->Tracks[i]->Type == TT_VIDEO) {
mf->firstTimecode += readSInt(mf, 2);
mf->seen.Cluster = 1;
skipbytes(mf,end - filepos(mf));
return;
}
}
skipbytes(mf, len - (filepos(mf) - start));
break;
case 0xa0: // BlockGroup
FOREACH(mf,len)
case 0xa1: // Block
readVLUInt(mf); // track number
mf->firstTimecode += readSInt(mf,2);
case 0xa1: // Block
start = filepos(mf);
tracknum = readVLUInt(mf); // track number
skipbytes(mf,end - filepos(mf));
return;
for (i = 0; i < mf->nTracks; ++i) {
if (mf->Tracks[i]->Number == tracknum && mf->Tracks[i]->Type == TT_VIDEO) {
mf->firstTimecode += readSInt(mf, 2);
mf->seen.Cluster = 1;
skipbytes(mf,end - filepos(mf));
return;
}
}
skipbytes(mf, len - (filepos(mf) - start));
break;
ENDFOR(mf);
break;
ENDFOR(mf);
}
static void parseVideoInfo(MatroskaFile *mf,uint64_t toplen,struct TrackInfo *ti) {

View File

@ -262,3 +262,11 @@ void AssKaraoke::SetLineTimes(int start_time, int end_time) {
}
syls[idx].duration = end_time - syls[idx].start_time;
}
std::string AssKaraoke::GetStrippedText(int syl_idx) const {
return syls[syl_idx].text;
}
void AssKaraoke::SetStrippedText(int syl_idx, std::string new_text) {
syls[syl_idx].text = new_text;
}

View File

@ -82,5 +82,10 @@ public:
/// Set the tag type for all karaoke tags in this line
void SetTagType(std::string const& new_type);
/// Get syllab's text stripped of k tag
std::string GetStrippedText(int syl_idx) const;
/// Set syllab's text stripped of k tag
void SetStrippedText(int syl_idx, std::string new_text);
DEFINE_SIGNAL_ADDERS(AnnounceSyllablesChanged, AddSyllablesChangedListener)
};

View File

@ -45,7 +45,7 @@
#include <wx/intl.h>
AssStyle::AssStyle() {
std::fill(Margin.begin(), Margin.end(), 10);
std::fill(Margin.begin(), Margin.end(), 30);
UpdateData();
}

View File

@ -40,11 +40,11 @@ class AssStyle final : public AssEntry, public AssEntryListHook {
public:
std::string name = "Default"; ///< Name of the style; must be case-insensitively unique within a file despite being case-sensitive
std::string font = "Arial"; ///< Font face name
double fontsize = 20.; ///< Font size
std::string font = "Amaranth"; ///< Font face name
double fontsize = 60.; ///< Font size
agi::Color primary{ 255, 255, 255 }; ///< Default text color
agi::Color secondary{ 255, 0, 0 }; ///< Text color for not-yet-reached karaoke syllables
agi::Color primary{ 255, 132, 0 }; ///< Default text color
agi::Color secondary{ 255, 255, 255 }; ///< Text color for not-yet-reached karaoke syllables
agi::Color outline{ 0, 0, 0 }; ///< Outline color
agi::Color shadow{ 0, 0, 0 }; ///< Shadow color
@ -60,7 +60,7 @@ public:
int borderstyle = 1; ///< 1: Normal; 3: Opaque box; others are unused in Aegisub
double outline_w = 2.; ///< Outline width in pixels
double shadow_w = 2.; ///< Shadow distance in pixels
int alignment = 2; ///< \an-style line alignment
int alignment = 8; ///< \an-style line alignment
std::array<int, 3> Margin; ///< Left / Right / Vertical
int encoding = 1; ///< ASS font encoding needed for some non-unicode fonts

View File

@ -891,6 +891,14 @@ void AudioDisplay::PaintMarkers(wxDC &dc, TimeRange updtime)
if (marker->GetFeet() & AudioMarker::Feet_Right)
PaintFoot(dc, marker_x, 1);
}
if (OPT_GET("Timing/Tap To Time")->GetBool()) {
dc.SetBrush(wxBrush(*wxGREEN));
dc.SetPen(*wxTRANSPARENT_PEN);
int marker_x = RelativeXFromTime(controller->GetTimingController()->GetTapMarkerPosition());
PaintTapMarker(dc, marker_x);
}
}
void AudioDisplay::PaintFoot(wxDC &dc, int marker_x, int dir)
@ -901,6 +909,12 @@ void AudioDisplay::PaintFoot(wxDC &dc, int marker_x, int dir)
dc.DrawPolygon(3, foot_bot, marker_x, audio_top+audio_height);
}
void AudioDisplay::PaintTapMarker(wxDC &dc, int marker_x)
{
wxPoint arrow[3] = { wxPoint(-foot_size * 2, 0), wxPoint(0, -foot_size * 2), wxPoint(foot_size * 2, 0) };
dc.DrawPolygon(3, arrow, marker_x, audio_top+audio_height);
}
void AudioDisplay::PaintLabels(wxDC &dc, TimeRange updtime)
{
std::vector<AudioLabelProvider::AudioLabel> labels;
@ -1229,6 +1243,7 @@ void AudioDisplay::OnAudioOpen(agi::AudioProvider *provider)
OPT_SUB("Colour/Audio Display/Spectrum", &AudioDisplay::ReloadRenderingSettings, this),
OPT_SUB("Colour/Audio Display/Waveform", &AudioDisplay::ReloadRenderingSettings, this),
OPT_SUB("Audio/Renderer/Spectrum/Quality", &AudioDisplay::ReloadRenderingSettings, this),
OPT_SUB("Timing/Tap To Time", &AudioDisplay::OnTapMarkerChanged, this),
});
OnTimingController();
}
@ -1254,10 +1269,12 @@ void AudioDisplay::OnTimingController()
timing_controller->AddMarkerMovedListener(&AudioDisplay::OnMarkerMoved, this);
timing_controller->AddUpdatedPrimaryRangeListener(&AudioDisplay::OnSelectionChanged, this);
timing_controller->AddUpdatedStyleRangesListener(&AudioDisplay::OnStyleRangesChanged, this);
timing_controller->AddUpdatedTapMarkerListener(&AudioDisplay::OnTapMarkerChanged, this);
OnStyleRangesChanged();
OnMarkerMoved();
OnSelectionChanged();
OnTapMarkerChanged();
}
}
@ -1341,6 +1358,12 @@ void AudioDisplay::OnStyleRangesChanged()
RefreshRect(wxRect(0, audio_top, GetClientSize().GetWidth(), audio_height), false);
}
void AudioDisplay::OnTapMarkerChanged()
{
RefreshRect(wxRect(0, audio_top, GetClientSize().GetWidth(), audio_height), false);
}
void AudioDisplay::OnMarkerMoved()
{
RefreshRect(wxRect(0, audio_top, GetClientSize().GetWidth(), audio_height), false);

View File

@ -169,6 +169,11 @@ class AudioDisplay: public wxWindow {
/// @param dir -1 for left, 1 for right
void PaintFoot(wxDC &dc, int marker_x, int dir);
/// Draw an indicator for the tap marker
/// @param dc DC to paint to
/// @param marker_x Position of the tap marker
void PaintTapMarker(wxDC &dc, int marker_x);
/// Paint the labels in a time range
/// @param dc DC to paint to
/// @param updtime Time range to repaint
@ -205,6 +210,7 @@ class AudioDisplay: public wxWindow {
void OnStyleRangesChanged();
void OnTimingController();
void OnMarkerMoved();
void OnTapMarkerChanged();
public:
AudioDisplay(wxWindow *parent, AudioController *controller, agi::Context *context);

View File

@ -64,6 +64,7 @@ AudioKaraoke::AudioKaraoke(wxWindow *parent, agi::Context *c)
, file_changed(c->ass->AddCommitListener(&AudioKaraoke::OnFileChanged, this))
, audio_opened(c->project->AddAudioProviderListener(&AudioKaraoke::OnAudioOpened, this))
, active_line_changed(c->selectionController->AddActiveLineListener(&AudioKaraoke::OnActiveLineChanged, this))
, tap_to_time_toggled(OPT_SUB("Timing/Tap To Time", &AudioKaraoke::OnTapMarkerChanged, this))
, kara(agi::make_unique<AssKaraoke>())
{
using std::bind;
@ -134,6 +135,7 @@ void AudioKaraoke::SetEnabled(bool en) {
if (enabled) {
LoadFromLine();
c->audioController->SetTimingController(CreateKaraokeTimingController(c, kara.get(), file_changed));
c->audioController->GetTimingController()->AddUpdatedTapMarkerListener(&AudioKaraoke::OnTapMarkerChanged, this);
Refresh(false);
}
else {
@ -218,7 +220,16 @@ void AudioKaraoke::RenderText() {
// Draw each character in the line
int y = (bmp_size.GetHeight() - char_height) / 2;
for (size_t i = 0; i < spaced_text.size(); ++i)
for (size_t i = 0; i < spaced_text.size(); ++i) {
if (!(tap_syl_start <= i && i < tap_syl_end)) {
// Only draw with normal color if _not_ the tap syllable
dc.DrawText(spaced_text[i], char_x[i], y);
}
}
// Draw marked syllable
dc.SetTextForeground(*wxGREEN);
for (size_t i = tap_syl_start; i < tap_syl_end; ++i)
dc.DrawText(spaced_text[i], char_x[i], y);
// Draw the lines between each syllable
@ -329,6 +340,26 @@ void AudioKaraoke::OnScrollTimer(wxTimerEvent &) {
split_area->Refresh(false);
}
void AudioKaraoke::OnTapMarkerChanged() {
tap_syl_start = 0;
tap_syl_end = 0;
if (OPT_GET("Timing/Tap To Time")->GetBool() && kara->size() > 0) {
const AudioTimingController *tc = c->audioController->GetTimingController();
const size_t marker_idx = tc->GetTapMarkerIndex();
if (marker_idx > 0) {
tap_syl_start = syl_start_points[marker_idx - 1];
tap_syl_end =
(marker_idx < syl_start_points.size() ?
syl_start_points[marker_idx] :
spaced_text.size());
}
}
RenderText();
Refresh(false);
}
void AudioKaraoke::LoadFromLine() {
scroll_x = 0;
scroll_timer.Stop();

View File

@ -67,6 +67,7 @@ class AudioKaraoke final : public wxWindow {
agi::signal::Connection audio_opened; ///< Audio opened connection
agi::signal::Connection audio_closed; ///< Audio closed connection
agi::signal::Connection active_line_changed;
agi::signal::Connection tap_to_time_toggled;
/// Currently active dialogue line
AssDialogue *active_line = nullptr;
@ -105,6 +106,9 @@ class AudioKaraoke final : public wxWindow {
wxFont split_font; ///< Font used in the split/join interface
size_t tap_syl_start = 0; ///< Tap-to-time syllable start character index
size_t tap_syl_end = 0; ///< Tap-to-time syllable end character index
bool enabled = false; ///< Is karaoke mode enabled?
wxButton *accept_button; ///< Accept pending splits button
@ -143,6 +147,7 @@ class AudioKaraoke final : public wxWindow {
void OnSize(wxSizeEvent &event);
void OnAudioOpened(agi::AudioProvider *provider);
void OnScrollTimer(wxTimerEvent &event);
void OnTapMarkerChanged();
public:
/// Constructor

View File

@ -57,6 +57,9 @@ protected:
/// One or more rendering style ranges have changed in the timing controller.
agi::signal::Signal<> AnnounceUpdatedStyleRanges;
/// The tap marker has changed in the timing controller.
agi::signal::Signal<> AnnounceUpdatedTapMarker;
public:
/// @brief Get any warning message to show in the audio display
/// @return The warning message to show, may be empty if there is none
@ -86,6 +89,12 @@ public:
/// @param[out] ranges Rendering ranges will be added to this
virtual void GetRenderingStyles(AudioRenderingStyleRanges &ranges) const = 0;
/// @brief Return the position of the tap marker
virtual int GetTapMarkerPosition() const = 0;
/// @brief Return the index of the tap marker
virtual size_t GetTapMarkerIndex() const = 0;
enum NextMode {
/// Advance to the next timing unit, whether it's a line or a sub-part
/// of a line such as a karaoke syllable
@ -138,6 +147,15 @@ public:
/// @param delta Amount to add in centiseconds
virtual void ModifyStart(int delta) = 0;
/// Move tap marker position to given position
/// @param position to move marker to
virtual void MoveTapMarker(int ms) = 0;
/// Go to next tap marker
/// @return True if moved to the next marker, False if tap marker is already
/// the last marker of the line
virtual bool NextTapMarker() = 0;
/// @brief Determine if a position is close to a draggable marker
/// @param ms The time in milliseconds to test
/// @param sensitivity Distance in milliseconds to consider markers as nearby
@ -147,9 +165,16 @@ public:
/// controlling the mouse cursor.
virtual bool IsNearbyMarker(int ms, int sensitivity, bool alt_down) const = 0;
/// @brief Return the text of the currently selected syllab
virtual std::string GetCurrentSylText() const { return ""; }
/// @ brief Set the text for the currently selected syllab
virtual void SetCurrentSylText(std::string new_text) {}
/// @brief The user pressed the left mouse button on the audio
/// @param ms The time in milliseconds the user clicked
/// @param ctrl_down Is the user currently holding the ctrl key down?
/// @param alt_down Is the user currently holding the alt key down?
/// @param sensitivity Distance in milliseconds to consider existing markers
/// @param snap_range Maximum snapping range in milliseconds
/// @return All audio markers at the clicked position which are eligible
@ -177,6 +202,7 @@ public:
DEFINE_SIGNAL_ADDERS(AnnounceUpdatedPrimaryRange, AddUpdatedPrimaryRangeListener)
DEFINE_SIGNAL_ADDERS(AnnounceUpdatedStyleRanges, AddUpdatedStyleRangesListener)
DEFINE_SIGNAL_ADDERS(AnnounceUpdatedTapMarker, AddUpdatedTapMarkerListener)
};
/// @brief Create a standard dialogue audio timing controller

View File

@ -29,6 +29,7 @@
#include "ass_dialogue.h"
#include "ass_file.h"
#include "audio_controller.h"
#include "audio_marker.h"
#include "audio_rendering_style.h"
#include "audio_timing.h"
@ -327,6 +328,12 @@ class AudioTimingControllerDialogue final : public AudioTimingController {
/// The time which was clicked on for alt-dragging mode
int clicked_ms;
/// Index of marker serving as tap marker
/// For AudioTimingControllerDialogue:
/// - 0 is left marker
/// - 1 is right marker
size_t tap_marker_idx = 0;
/// Autocommit option
const agi::OptionValue *auto_commit = OPT_GET("Audio/Auto/Commit");
const agi::OptionValue *inactive_line_mode = OPT_GET("Audio/Inactive Lines Display Mode");
@ -384,6 +391,8 @@ class AudioTimingControllerDialogue final : public AudioTimingController {
public:
// AudioMarkerProvider interface
void GetMarkers(const TimeRange &range, AudioMarkerVector &out_markers) const override;
int GetTapMarkerPosition() const override;
size_t GetTapMarkerIndex() const override;
// AudioTimingController interface
void GetRenderingStyles(AudioRenderingStyleRanges &ranges) const override;
@ -395,9 +404,11 @@ public:
void AddLeadOut() override;
void ModifyLength(int delta, bool shift_following) override;
void ModifyStart(int delta) override;
void MoveTapMarker(int ms) override;
bool NextTapMarker() override;
bool IsNearbyMarker(int ms, int sensitivity, bool alt_down) const override;
std::vector<AudioMarker*> OnLeftClick(int ms, bool ctrl_down, bool alt_down, int sensitivity, int snap_range) override;
std::vector<AudioMarker*> OnRightClick(int ms, bool, int sensitivity, int snap_range) override;
std::vector<AudioMarker*> OnRightClick(int ms, bool ctrl_down, int sensitivity, int snap_range) override;
void OnMarkerDrag(std::vector<AudioMarker*> const& markers, int new_position, int snap_range) override;
// We have no warning messages currently, maybe add the old "Modified" message back later?
@ -447,6 +458,24 @@ void AudioTimingControllerDialogue::GetMarkers(const TimeRange &range, AudioMark
video_position_provider.GetMarkers(range, out_markers);
}
int AudioTimingControllerDialogue::GetTapMarkerPosition() const
{
assert(tap_marker_idx <= 1);
if (tap_marker_idx == 0) {
return *active_line.GetLeftMarker();
}
else {
return *active_line.GetRightMarker();
}
}
size_t AudioTimingControllerDialogue::GetTapMarkerIndex() const
{
assert(tap_marker_idx <= 1);
return tap_marker_idx;
}
void AudioTimingControllerDialogue::OnSelectedSetChanged()
{
RegenerateSelectedLines();
@ -526,6 +555,7 @@ void AudioTimingControllerDialogue::DoCommit(bool user_triggered)
void AudioTimingControllerDialogue::Revert()
{
commit_id = -1;
tap_marker_idx = 0;
if (AssDialogue *line = context->selectionController->GetActiveLine())
{
@ -535,6 +565,7 @@ void AudioTimingControllerDialogue::Revert()
AnnounceUpdatedPrimaryRange();
if (inactive_line_mode->GetInt() == 0)
AnnounceUpdatedStyleRanges();
AnnounceUpdatedTapMarker();
}
else
{
@ -570,6 +601,35 @@ void AudioTimingControllerDialogue::ModifyStart(int delta) {
std::min<int>(*m + delta * 10, *active_line.GetRightMarker()), 0);
}
void AudioTimingControllerDialogue::MoveTapMarker(int ms) {
// Fix rounding error
ms = (ms + 5) / 10 * 10;
DialogueTimingMarker *left = active_line.GetLeftMarker();
DialogueTimingMarker *right = active_line.GetRightMarker();
clicked_ms = INT_MIN;
if (tap_marker_idx == 0) {
// Moving left marker (start time of the line)
if (ms > *right) SetMarkers({ right }, ms, 0);
SetMarkers({ left }, ms, 0);
}
else {
// Moving right marker (end time of the line)
if (ms < *left) SetMarkers({ left }, ms, 0);
SetMarkers({ right }, ms, 0);
}
}
bool AudioTimingControllerDialogue::NextTapMarker() {
if (tap_marker_idx == 0) {
tap_marker_idx = 1;
AnnounceUpdatedTapMarker();
return true;
}
return false;
}
bool AudioTimingControllerDialogue::IsNearbyMarker(int ms, int sensitivity, bool alt_down) const
{
assert(sensitivity >= 0);
@ -609,6 +669,8 @@ std::vector<AudioMarker*> AudioTimingControllerDialogue::OnLeftClick(int ms, boo
ret = drag_timing->GetBool() ? GetRightMarkers() : jump;
// Get ret before setting as setting may swap left/right
SetMarkers(jump, ms, snap_range);
// Also change tap marker to left marker
tap_marker_idx = 0;
return ret;
}
@ -627,18 +689,36 @@ std::vector<AudioMarker*> AudioTimingControllerDialogue::OnLeftClick(int ms, boo
// Left-click within drag range should still move the left marker to the
// clicked position, but not the right marker
if (clicked == left)
if (clicked == left) {
SetMarkers(ret, ms, snap_range);
}
// Also change tap marker
if (clicked == left) {
tap_marker_idx = 0;
}
else {
tap_marker_idx = 1;
}
return ret;
}
std::vector<AudioMarker*> AudioTimingControllerDialogue::OnRightClick(int ms, bool, int sensitivity, int snap_range)
std::vector<AudioMarker*> AudioTimingControllerDialogue::OnRightClick(int ms, bool ctrl_down, int sensitivity, int snap_range)
{
clicked_ms = INT_MIN;
std::vector<AudioMarker*> ret = GetRightMarkers();
SetMarkers(ret, ms, snap_range);
return ret;
if (ctrl_down) {
// Ctrl-right-click: play audio
context->audioController->PlayToEnd(ms);
return {};
}
else {
// Normal right-click: move right marker
clicked_ms = INT_MIN;
std::vector<AudioMarker*> ret = GetRightMarkers();
SetMarkers(ret, ms, snap_range);
tap_marker_idx = 1;
return ret;
}
}
void AudioTimingControllerDialogue::OnMarkerDrag(std::vector<AudioMarker*> const& markers, int new_position, int snap_range)

View File

@ -81,6 +81,13 @@ class AudioTimingControllerKaraoke final : public AudioTimingController {
size_t cur_syl = 0; ///< Index of currently selected syllable in the line
/// Index of marker serving as tap marker
/// For AudioControllerTimingKaraoke:
/// - 0 is start marker
/// - 1 to markers.size() is a regular syllable marker
/// - markers.size() + 1 is end marker
size_t tap_marker_idx = 0;
/// Pen used for the mid-syllable markers
Pen separator_pen{"Colour/Audio Display/Syllable Boundaries", "Audio/Line Boundaries Thickness", wxPENSTYLE_DOT};
/// Pen used for the start-of-line marker
@ -112,11 +119,16 @@ class AudioTimingControllerKaraoke final : public AudioTimingController {
void DoCommit();
void ApplyLead(bool announce_primary);
int MoveMarker(KaraokeMarker *marker, int new_position);
void AnnounceChanges(int syl);
void MoveStartMarker(int new_position);
void MoveEndMarker(int new_position);
void CompressMarkers(size_t from, size_t to, int new_position);
void AnnounceChanges(bool announce_primary);
public:
// AudioTimingController implementation
void GetMarkers(const TimeRange &range, AudioMarkerVector &out_markers) const override;
int GetTapMarkerPosition() const override;
size_t GetTapMarkerIndex() const override;
wxString GetWarningMessage() const override { return ""; }
TimeRange GetIdealVisibleTimeRange() const override;
void GetRenderingStyles(AudioRenderingStyleRanges &ranges) const override;
@ -131,10 +143,14 @@ public:
void AddLeadOut() override;
void ModifyLength(int delta, bool shift_following) override;
void ModifyStart(int delta) override;
void MoveTapMarker(int ms) override;
bool NextTapMarker() override;
bool IsNearbyMarker(int ms, int sensitivity, bool) const override;
std::vector<AudioMarker*> OnLeftClick(int ms, bool, bool, int sensitivity, int) override;
std::vector<AudioMarker*> OnRightClick(int ms, bool, int, int) override;
std::vector<AudioMarker*> OnRightClick(int ms, bool ctrl_down, int, int) override;
void OnMarkerDrag(std::vector<AudioMarker*> const& marker, int new_position, int) override;
std::string GetCurrentSylText() const override;
void SetCurrentSylText(std::string new_text) override;
AudioTimingControllerKaraoke(agi::Context *c, AssKaraoke *kara, agi::signal::Connection& file_changed);
};
@ -235,10 +251,29 @@ void AudioTimingControllerKaraoke::GetMarkers(TimeRange const& range, AudioMarke
video_position_provider.GetMarkers(range, out);
}
int AudioTimingControllerKaraoke::GetTapMarkerPosition() const {
assert(tap_marker_idx <= markers.size() + 1);
if (tap_marker_idx == 0) {
return start_marker;
}
else if (tap_marker_idx < markers.size() + 1) {
return markers[tap_marker_idx-1];
}
else {
return end_marker;
}
}
size_t AudioTimingControllerKaraoke::GetTapMarkerIndex() const {
assert(tap_marker_idx <= markers.size() + 1);
return tap_marker_idx;
}
void AudioTimingControllerKaraoke::DoCommit() {
active_line->Text = kara->GetText();
file_changed_slot.Block();
commit_id = c->ass->Commit(_("karaoke timing"), AssFile::COMMIT_DIAG_TEXT, commit_id, active_line);
commit_id = c->ass->Commit(_("karaoke timing"), AssFile::COMMIT_DIAG_TEXT | AssFile::COMMIT_DIAG_TIME, commit_id, active_line);
file_changed_slot.Unblock();
pending_changes = false;
}
@ -254,6 +289,7 @@ void AudioTimingControllerKaraoke::Revert() {
cur_syl = 0;
commit_id = -1;
pending_changes = false;
tap_marker_idx = 0;
start_marker.Move(active_line->Start);
end_marker.Move(active_line->End);
@ -273,6 +309,7 @@ void AudioTimingControllerKaraoke::Revert() {
AnnounceUpdatedPrimaryRange();
AnnounceUpdatedStyleRanges();
AnnounceMarkerMoved();
AnnounceUpdatedTapMarker();
}
void AudioTimingControllerKaraoke::AddLeadIn() {
@ -293,7 +330,7 @@ void AudioTimingControllerKaraoke::ApplyLead(bool announce_primary) {
kara->SetLineTimes(start_marker, end_marker);
if (!announce_primary)
AnnounceUpdatedStyleRanges();
AnnounceChanges(announce_primary ? cur_syl : cur_syl + 2);
AnnounceChanges(announce_primary);
}
void AudioTimingControllerKaraoke::ModifyLength(int delta, bool shift_following) {
@ -314,13 +351,63 @@ void AudioTimingControllerKaraoke::ModifyLength(int delta, bool shift_following)
for (; cur != end; cur += step) {
MoveMarker(&markers[cur], markers[cur] + delta * 10);
}
AnnounceChanges(cur_syl);
AnnounceChanges(true);
}
void AudioTimingControllerKaraoke::ModifyStart(int delta) {
if (cur_syl == 0) return;
MoveMarker(&markers[cur_syl - 1], markers[cur_syl - 1] + delta * 10);
AnnounceChanges(cur_syl);
AnnounceChanges(true);
}
void AudioTimingControllerKaraoke::MoveTapMarker(int ms) {
// Fix rounding error
ms = (ms + 5) / 10 * 10;
// Get syllable this time falls within
const size_t syl = distance(markers.begin(), lower_bound(markers.begin(), markers.end(), ms));
// Tapping automatically moves all of the necessary markers for the tap
// marker to land at the current audio position. Intuitively, it "pushes" or
// "compresses" the markers blocking the tap marker's way so they all end up
// in the same position. The expectation is that the markers will reach their
// proper position once the user finishes tapping to the line
if (tap_marker_idx == 0) {
// Moving the start time of first syllable (i.e. start time of the line)
if (ms > end_marker) MoveEndMarker(ms);
if (syl > 0) CompressMarkers(syl-1, 0, ms);
MoveStartMarker(ms);
}
else if (tap_marker_idx < markers.size() + 1) {
// Moving the end time of a non-end syllable
if (ms < start_marker) MoveStartMarker(ms);
else if (ms > end_marker) MoveEndMarker(ms);
if (syl < tap_marker_idx) {
// Moving markers left
CompressMarkers(syl, tap_marker_idx-1, ms);
}
else {
// Moving markers right
CompressMarkers(syl-1, tap_marker_idx-1, ms);
}
}
else {
// Moving the end time of last syllable (i.e. end time of the line)
if (ms < start_marker) MoveStartMarker(ms);
if (syl < markers.size()) CompressMarkers(0, markers.size()-1, ms);
MoveEndMarker(ms);
}
AnnounceChanges(true);
}
bool AudioTimingControllerKaraoke::NextTapMarker() {
if (tap_marker_idx < markers.size() + 1) {
++tap_marker_idx;
AnnounceUpdatedTapMarker();
return true;
}
return false;
}
bool AudioTimingControllerKaraoke::IsNearbyMarker(int ms, int sensitivity, bool) const {
@ -350,18 +437,36 @@ std::vector<AudioMarker*> AudioTimingControllerKaraoke::OnLeftClick(int ms, bool
cur_syl = syl;
// Change tap marker
// Selecting a syllable moves the marker to the _end_ of that syllable, such
// that the next tap determines when that syllable ends. This behavior is
// more intuitive when coupled with AudioKaraoke's tap syllable highlight.
if (ms < start_marker.GetPosition()) {
tap_marker_idx = 0;
}
else {
tap_marker_idx = cur_syl + 1;
}
AnnounceUpdatedPrimaryRange();
AnnounceUpdatedStyleRanges();
AnnounceUpdatedTapMarker();
return {};
}
std::vector<AudioMarker*> AudioTimingControllerKaraoke::OnRightClick(int ms, bool, int, int) {
cur_syl = distance(markers.begin(), lower_bound(markers.begin(), markers.end(), ms));
AnnounceUpdatedPrimaryRange();
AnnounceUpdatedStyleRanges();
c->audioController->PlayPrimaryRange();
std::vector<AudioMarker*> AudioTimingControllerKaraoke::OnRightClick(int ms, bool ctrl_down, int, int) {
if (ctrl_down) {
// Ctrl-right-click: play audio
c->audioController->PlayToEnd(ms);
}
else {
// Normal right-click: select new syllable and play range
cur_syl = distance(markers.begin(), lower_bound(markers.begin(), markers.end(), ms));
AnnounceUpdatedPrimaryRange();
AnnounceUpdatedStyleRanges();
c->audioController->PlayPrimaryRange();
}
return {};
}
@ -379,7 +484,7 @@ int AudioTimingControllerKaraoke::MoveMarker(KaraokeMarker *marker, int new_posi
marker->Move(new_position);
size_t syl = marker - &markers.front() + 1;
kara->SetStartTime(syl, (new_position + 5) / 10 * 10);
kara->SetStartTime(syl, new_position);
labels[syl - 1].range = TimeRange(labels[syl - 1].range.begin(), new_position);
labels[syl].range = TimeRange(new_position, labels[syl].range.end());
@ -387,10 +492,58 @@ int AudioTimingControllerKaraoke::MoveMarker(KaraokeMarker *marker, int new_posi
return syl;
}
void AudioTimingControllerKaraoke::AnnounceChanges(int syl) {
if (syl < 0) return;
void AudioTimingControllerKaraoke::MoveStartMarker(int new_position) {
// No rearranging of syllables allowed
new_position = mid(
0,
new_position,
markers[0].GetPosition());
if (syl == cur_syl || syl == cur_syl + 1) {
if (new_position == start_marker.GetPosition())
return;
start_marker.Move(new_position);
active_line->Start = (int)start_marker;
kara->SetLineTimes(start_marker, end_marker);
labels.front().range = TimeRange(start_marker, labels.front().range.end());
}
void AudioTimingControllerKaraoke::MoveEndMarker(int new_position) {
// No rearranging of syllables allowed
new_position = mid(
markers.back().GetPosition(),
new_position,
INT_MAX);
if (new_position == end_marker.GetPosition())
return;
end_marker.Move(new_position);
active_line->End = (int)end_marker;
kara->SetLineTimes(start_marker, end_marker);
labels.back().range = TimeRange(labels.back().range.begin(), end_marker);
}
void AudioTimingControllerKaraoke::CompressMarkers(size_t from, size_t to, int new_position) {
int incr = (from < to ? 1 : -1);
size_t i = from;
for (;;) {
MoveMarker(&markers[i], new_position);
if (i == to) {
break;
}
else {
i += incr;
}
}
}
void AudioTimingControllerKaraoke::AnnounceChanges(bool announce_primary) {
if (announce_primary) {
AnnounceUpdatedPrimaryRange();
AnnounceUpdatedStyleRanges();
}
@ -406,18 +559,21 @@ void AudioTimingControllerKaraoke::AnnounceChanges(int syl) {
}
void AudioTimingControllerKaraoke::OnMarkerDrag(std::vector<AudioMarker*> const& m, int new_position, int) {
// Fix rounding error
new_position = (new_position + 5) / 10 * 10;
int old_position = m[0]->GetPosition();
int syl = MoveMarker(static_cast<KaraokeMarker *>(m[0]), new_position);
if (syl < 0) return;
bool announce_primary = (syl == cur_syl || syl == cur_syl + 1);
if (m.size() > 1) {
int delta = m[0]->GetPosition() - old_position;
for (AudioMarker *marker : m | boost::adaptors::sliced(1, m.size()))
MoveMarker(static_cast<KaraokeMarker *>(marker), marker->GetPosition() + delta);
syl = cur_syl;
announce_primary = true;
}
AnnounceChanges(syl);
AnnounceChanges(announce_primary);
}
void AudioTimingControllerKaraoke::GetLabels(TimeRange const& range, std::vector<AudioLabel> &out) const {
@ -425,3 +581,12 @@ void AudioTimingControllerKaraoke::GetLabels(TimeRange const& range, std::vector
return range.overlaps(l.range);
}), back_inserter(out));
}
std::string AudioTimingControllerKaraoke::GetCurrentSylText() const {
return kara->GetStrippedText(cur_syl);
}
void AudioTimingControllerKaraoke::SetCurrentSylText(std::string new_text) {
kara->SetStrippedText(cur_syl, new_text);
AnnounceChanges(true);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 859 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

@ -441,6 +441,21 @@ button/substart_to_video_24.png
button/substart_to_video_32.png
button/substart_to_video_48.png
button/substart_to_video_64.png
button/time_tap_connect_16.png
button/time_tap_connect_24.png
button/time_tap_connect_32.png
button/time_tap_connect_48.png
button/time_tap_connect_64.png
button/time_tap_no_connect_16.png
button/time_tap_no_connect_24.png
button/time_tap_no_connect_32.png
button/time_tap_no_connect_48.png
button/time_tap_no_connect_64.png
button/time_opt_tap_to_time_16.png
button/time_opt_tap_to_time_24.png
button/time_opt_tap_to_time_32.png
button/time_opt_tap_to_time_48.png
button/time_opt_tap_to_time_64.png
button/timing_processor_toolbutton_16.png
button/timing_processor_toolbutton_24.png
button/timing_processor_toolbutton_32.png

View File

@ -47,8 +47,11 @@ namespace CharSetDetect {
std::string GetEncoding(agi::fs::path const& filename) {
auto encoding = agi::charset::Detect(filename);
if (!encoding.empty())
if (!encoding.empty()) {
if (!encoding.compare("ASCII") || !encoding.compare("UTF-8"))
encoding = "utf-8";
return encoding;
}
auto choices = agi::charset::GetEncodingsList<wxArrayString>();
int choice = wxGetSingleChoiceIndex(

View File

@ -110,8 +110,22 @@ struct help_website final : public Command {
wxLaunchDefaultBrowser("http://www.aegisub.org/", wxBROWSER_NEW_WINDOW);
}
};
struct help_joysound_export final : public Command {
CMD_NAME("help/joysound_exporter")
CMD_ICON(website_button)
STR_MENU("&Joysound Exporter")
STR_DISP("Joysound Exporter")
STR_HELP("Export karaoke from Joysound")
void operator()(agi::Context *) override {
wxLaunchDefaultBrowser("https://joysound.rhiobet.ninja/", wxBROWSER_NEW_WINDOW);
}
};
}
namespace cmd {
void init_help() {
reg(agi::make_unique<help_bugs>());
@ -119,5 +133,6 @@ namespace cmd {
reg(agi::make_unique<help_irc>());
reg(agi::make_unique<help_video>());
reg(agi::make_unique<help_website>());
reg(agi::make_unique<help_joysound_export>());
}
}

View File

@ -39,6 +39,7 @@
#include "../dialogs.h"
#include "../include/aegisub/context.h"
#include "../libresrc/libresrc.h"
#include "../options.h"
#include "../project.h"
#include "../selection_controller.h"
#include "../video_controller.h"
@ -50,6 +51,10 @@
namespace {
using cmd::Command;
static inline void toggle(const char *opt) {
OPT_SET(opt)->SetBool(!OPT_GET(opt)->GetBool());
}
struct validate_video_loaded : public Command {
CMD_TYPE(COMMAND_VALIDATE)
bool Validate(const agi::Context *c) override {
@ -373,6 +378,107 @@ struct time_prev final : public Command {
c->audioController->GetTimingController()->Prev();
}
};
struct time_tap_connect final : public Command {
CMD_NAME("time/tap/connect")
CMD_ICON(time_tap_connect)
STR_MENU("Time tap connect")
STR_DISP("Time tap connect")
STR_HELP("Set tap marker to audio position, connect next line's start")
CMD_TYPE(COMMAND_VALIDATE)
bool Validate(const agi::Context *c) override {
return
OPT_GET("Timing/Tap To Time")->GetBool() &&
c->audioController->IsPlaying();
}
void operator()(agi::Context *c) override {
if (c->audioController->IsPlaying()) {
AudioTimingController *tc = c->audioController->GetTimingController();
if (tc) {
int ms = c->audioController->GetPlaybackPosition();
tc->MoveTapMarker(ms);
bool moved_marker = tc->NextTapMarker();
if (!moved_marker &&
OPT_GET("Audio/Auto/Commit")->GetBool() &&
OPT_GET("Audio/Next Line on Commit")->GetBool()) {
// go to next line, and then tap again to connect start to the same
// time
c->selectionController->NextLine();
tc->MoveTapMarker(ms);
tc->NextTapMarker();
}
}
}
}
};
struct time_tap_no_connect final : public Command {
CMD_NAME("time/tap/no_connect")
CMD_ICON(time_tap_no_connect)
STR_MENU("Tap marker no connect")
STR_DISP("Tap marker no connect")
STR_HELP("Set tap marker to audio position, do not connect next line's start")
CMD_TYPE(COMMAND_VALIDATE)
bool Validate(const agi::Context *c) override {
return
OPT_GET("Timing/Tap To Time")->GetBool() &&
c->audioController->IsPlaying();
}
void operator()(agi::Context *c) override {
if (c->audioController->IsPlaying()) {
AudioTimingController *tc = c->audioController->GetTimingController();
if (tc) {
int ms = c->audioController->GetPlaybackPosition();
tc->MoveTapMarker(ms);
bool moved_marker = tc->NextTapMarker();
if (!moved_marker &&
OPT_GET("Audio/Auto/Commit")->GetBool() &&
OPT_GET("Audio/Next Line on Commit")->GetBool()) {
// go to next line, but don't do anything more
c->selectionController->NextLine();
}
}
}
}
};
struct time_opt_tap_to_time final : public Command {
CMD_NAME("time/opt/tap_to_time")
CMD_ICON(time_opt_tap_to_time)
STR_MENU("Enable tap-to-time UI")
STR_DISP("Enable tap-to-time UI")
STR_HELP("Enable tap-to-time UI")
CMD_TYPE(COMMAND_TOGGLE)
bool IsActive(const agi::Context *) override {
return OPT_GET("Timing/Tap To Time")->GetBool();
}
void operator()(agi::Context *) override {
toggle("Timing/Tap To Time");
}
};
struct time_add_space final : public Command {
CMD_NAME("time/add_space")
STR_MENU("Add Space")
STR_DISP("Add Space")
STR_HELP("Add a space at the end of the current syllab")
void operator()(agi::Context *c) override {
if (c->audioController->GetTimingController()) {
AudioTimingController *tc = c->audioController->GetTimingController();
tc->SetCurrentSylText(tc->GetCurrentSylText() + " ");
// tc->Next(AudioTimingController::TIMING_UNIT);
}
}
};
}
namespace cmd {
@ -387,7 +493,10 @@ namespace cmd {
reg(agi::make_unique<time_length_decrease_shift>());
reg(agi::make_unique<time_length_increase>());
reg(agi::make_unique<time_length_increase_shift>());
reg(agi::make_unique<time_tap_connect>());
reg(agi::make_unique<time_tap_no_connect>());
reg(agi::make_unique<time_next>());
reg(agi::make_unique<time_opt_tap_to_time>());
reg(agi::make_unique<time_prev>());
reg(agi::make_unique<time_shift>());
reg(agi::make_unique<time_snap_end_video>());
@ -395,5 +504,6 @@ namespace cmd {
reg(agi::make_unique<time_snap_start_video>());
reg(agi::make_unique<time_start_decrease>());
reg(agi::make_unique<time_start_increase>());
reg(agi::make_unique<time_add_space>());
}
}

View File

@ -46,7 +46,13 @@
#include <libaegisub/split.h>
#include <ctime>
#include <boost/beast/core.hpp>
#include <boost/beast/http.hpp>
#include <boost/beast/version.hpp>
#include <boost/asio/connect.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/ssl/error.hpp>
#include <boost/asio/ssl/stream.hpp>
#include <functional>
#include <mutex>
#include <vector>
@ -67,15 +73,65 @@
#include <CoreFoundation/CoreFoundation.h>
#endif
namespace {
std::mutex VersionCheckLock;
namespace ssl = boost::asio::ssl;
namespace http = boost::beast::http;
struct AegisubUpdateDescription {
std::string url;
std::string friendly_name;
int major;
int minor;
int patch;
std::string extra;
std::string description;
};
AegisubUpdateDescription ParseVersionString(std::string version_string) {
std::vector<std::string> maj_min;
std::vector<std::string> patch;
agi::Split(maj_min, version_string, '.');
agi::Split(patch, maj_min[2], '-');
std::string extra = "";
if (patch.size() > 1) {
extra = patch[1];
}
return AegisubUpdateDescription{
atoi(maj_min[0].c_str()),
atoi(maj_min[1].c_str()),
atoi(patch[0].c_str()),
extra,
""
};
}
bool IsNewer(AegisubUpdateDescription update) {
AegisubUpdateDescription current = ParseVersionString(GetReleaseVersion());
if (update.major != current.major)
return update.major > current.major;
if (update.minor != current.minor)
return update.minor > current.minor;
if (update.patch != current.patch)
return update.patch > current.patch;
return update.extra.compare(current.extra) > 0;
}
std::string AegisubVersion(AegisubUpdateDescription update) {
std::ostringstream s;
s << update.major << "." << update.minor << "." << update.patch;
if (!update.extra.empty())
s << "-" << update.extra;
return s.str();
}
class VersionCheckerResultDialog final : public wxDialog {
void OnCloseButton(wxCommandEvent &evt);
void OnRemindMeLater(wxCommandEvent &evt);
@ -84,12 +140,12 @@ class VersionCheckerResultDialog final : public wxDialog {
wxCheckBox *automatic_check_checkbox;
public:
VersionCheckerResultDialog(wxString const& main_text, const std::vector<AegisubUpdateDescription> &updates);
VersionCheckerResultDialog(wxString const& main_text, const AegisubUpdateDescription update);
bool ShouldPreventAppExit() const override { return false; }
};
VersionCheckerResultDialog::VersionCheckerResultDialog(wxString const& main_text, const std::vector<AegisubUpdateDescription> &updates)
VersionCheckerResultDialog::VersionCheckerResultDialog(wxString const& main_text, const AegisubUpdateDescription update)
: wxDialog(nullptr, -1, _("Version Checker"))
{
const int controls_width = 500;
@ -100,10 +156,10 @@ VersionCheckerResultDialog::VersionCheckerResultDialog(wxString const& main_text
text->Wrap(controls_width);
main_sizer->Add(text, 0, wxBOTTOM|wxEXPAND, 6);
for (auto const& update : updates) {
main_sizer->Add(new wxStaticLine(this), 0, wxEXPAND|wxALL, 6);
main_sizer->Add(new wxStaticLine(this), 0, wxEXPAND|wxALL, 6);
text = new wxStaticText(this, -1, to_wx(update.friendly_name));
if (IsNewer(update)) {
text = new wxStaticText(this, -1, to_wx("Aegisub-Japan7"));
wxFont boldfont = text->GetFont();
boldfont.SetWeight(wxFONTWEIGHT_BOLD);
text->SetFont(boldfont);
@ -112,21 +168,25 @@ VersionCheckerResultDialog::VersionCheckerResultDialog(wxString const& main_text
wxTextCtrl *descbox = new wxTextCtrl(this, -1, to_wx(update.description), wxDefaultPosition, wxSize(controls_width,60), wxTE_MULTILINE|wxTE_READONLY);
main_sizer->Add(descbox, 0, wxEXPAND|wxBOTTOM, 6);
main_sizer->Add(new wxHyperlinkCtrl(this, -1, to_wx(update.url), to_wx(update.url)), 0, wxALIGN_LEFT|wxBOTTOM, 6);
std::ostringstream surl;
surl << "https://" << UPDATE_CHECKER_SERVER << UPDATE_CHECKER_BASE_URL << "/Aegisub-Japan7-" << AegisubVersion(update) << "-x64.exe";
std::string url = surl.str();
main_sizer->Add(new wxHyperlinkCtrl(this, -1, to_wx(url), to_wx(url)), 0, wxALIGN_LEFT|wxBOTTOM, 6);
}
automatic_check_checkbox = new wxCheckBox(this, -1, _("&Auto Check for Updates"));
automatic_check_checkbox->SetValue(OPT_GET("App/Auto/Check For Updates")->GetBool());
wxButton *remind_later_button = nullptr;
if (updates.size() > 0)
if (IsNewer(update))
remind_later_button = new wxButton(this, wxID_NO, _("Remind me again in a &week"));
wxButton *close_button = new wxButton(this, wxID_OK, _("&Close"));
SetAffirmativeId(wxID_OK);
SetEscapeId(wxID_OK);
if (updates.size())
if (IsNewer(update))
main_sizer->Add(new wxStaticLine(this), 0, wxEXPAND|wxALL, 6);
main_sizer->Add(automatic_check_checkbox, 0, wxEXPAND|wxBOTTOM, 6);
@ -280,72 +340,82 @@ static wxString GetAegisubLanguage() {
return to_wx(OPT_GET("App/Language")->GetString());
}
void DoCheck(bool interactive) {
boost::asio::ip::tcp::iostream stream;
stream.connect(UPDATE_CHECKER_SERVER, "http");
if (!stream)
throw VersionCheckError(from_wx(_("Could not connect to updates server.")));
AegisubUpdateDescription GetLatestVersion() {
agi::format(stream,
"GET %s?rev=%d&rel=%d&os=%s&lang=%s&aegilang=%s HTTP/1.0\r\n"
"User-Agent: Aegisub %s\r\n"
"Host: %s\r\n"
"Accept: */*\r\n"
"Connection: close\r\n\r\n"
, UPDATE_CHECKER_BASE_URL
, GetSVNRevision()
, (GetIsOfficialRelease() ? 1 : 0)
, GetOSShortName()
, GetSystemLanguage()
, GetAegisubLanguage()
, GetAegisubLongVersionString()
, UPDATE_CHECKER_SERVER);
boost::asio::io_context ioc;
boost::asio::ssl::context ctx(ssl::context::method::sslv23_client);
std::string http_version;
stream >> http_version;
int status_code;
stream >> status_code;
if (!stream || http_version.substr(0, 5) != "HTTP/")
throw VersionCheckError(from_wx(_("Could not download from updates server.")));
if (status_code != 200)
throw VersionCheckError(agi::format(_("HTTP request failed, got HTTP response %d."), status_code));
boost::asio::ip::tcp::resolver resolver(ioc);
ssl::stream<boost::asio::ip::tcp::socket> stream(ioc, ctx);
stream.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
if(! SSL_set_tlsext_host_name(stream.native_handle(), UPDATE_CHECKER_SERVER)) {
boost::system::error_code ec{static_cast<int>(::ERR_get_error()), boost::asio::error::get_ssl_category()};
throw boost::system::system_error{ec};
}
// Skip the headers since we don't care about them
for (auto const& header : agi::line_iterator<std::string>(stream))
if (header.empty()) break;
auto const results = resolver.resolve(UPDATE_CHECKER_SERVER, "443");
std::vector<AegisubUpdateDescription> results;
for (auto const& line : agi::line_iterator<std::string>(stream)) {
if (line.empty()) continue;
boost::asio::connect(stream.next_layer(), results.begin(), results.end());
stream.handshake(boost::asio::ssl::stream_base::handshake_type::client);
std::vector<std::string> parsed;
agi::Split(parsed, line, '|');
if (parsed.size() != 6) continue;
std::ostringstream s;
s << UPDATE_CHECKER_BASE_URL;
s << "/latest";
std::string target = s.str();
http::request<http::string_body> req(http::verb::get, target, 11);
req.set(http::field::host, UPDATE_CHECKER_SERVER);
req.set(http::field::user_agent, "Aegisub-Japan7");
if (atoi(parsed[1].c_str()) <= GetSVNRevision())
continue;
http::write(stream, req);
// 0 and 2 being things that never got used
results.push_back(AegisubUpdateDescription{
inline_string_decode(parsed[3]),
inline_string_decode(parsed[4]),
inline_string_decode(parsed[5])
});
boost::beast::flat_buffer buffer;
http::response<http::string_body> res;
http::read(stream, buffer, res);
// Gracefully close the stream
boost::system::error_code ec;
stream.shutdown(ec);
if(ec == boost::asio::error::eof)
{
// http://stackoverflow.com/questions/25587403/boost-asio-ssl-async-shutdown-always-finishes-with-an-error
ec.assign(0, ec.category());
}
if(ec)
throw boost::system::system_error{ec};
std::string line;
std::stringstream body(res.body().data());
std::getline(body, line, '\n');
AegisubUpdateDescription version = ParseVersionString(line);
std::ostringstream desc;
while (std::getline(body, line, '\n')) {
desc << line;
}
if (!results.empty() || interactive) {
version.description = desc.str();
return version;
throw VersionCheckError(from_wx(_("Could not get update from updates server.")));
}
void DoCheck(bool interactive) {
AegisubUpdateDescription update = GetLatestVersion();
if (IsNewer(update) || interactive) {
agi::dispatch::Main().Async([=]{
wxString text;
if (results.size() == 1)
if (IsNewer(update))
text = _("An update to Aegisub was found.");
else if (results.size() > 1)
text = _("Several possible updates to Aegisub were found.");
else
text = _("There are no updates to Aegisub.");
new VersionCheckerResultDialog(text, results);
new VersionCheckerResultDialog(text, update);
});
}
}

View File

@ -28,6 +28,47 @@
#include <unicode/utf16.h>
#include <Usp10.h>
static void read_fonts_from_key(HKEY hkey, agi::fs::path font_dir, std::vector<agi::fs::path> &files) {
static const auto fonts_key_name = L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts";
HKEY key;
auto ret = RegOpenKeyExW(hkey, fonts_key_name, 0, KEY_QUERY_VALUE, &key);
if (ret != ERROR_SUCCESS) return;
BOOST_SCOPE_EXIT_ALL(=) { RegCloseKey(key); };
DWORD name_buf_size = SHRT_MAX;
DWORD data_buf_size = MAX_PATH;
auto font_name = new wchar_t[name_buf_size];
auto font_filename = new wchar_t[data_buf_size];
for (DWORD i = 0;; ++i) {
retry:
DWORD name_len = name_buf_size;
DWORD data_len = data_buf_size;
ret = RegEnumValueW(key, i, font_name, &name_len, NULL, NULL, reinterpret_cast<BYTE*>(font_filename), &data_len);
if (ret == ERROR_MORE_DATA) {
data_buf_size = data_len;
delete font_filename;
font_filename = new wchar_t[data_buf_size];
goto retry;
}
if (ret == ERROR_NO_MORE_ITEMS) break;
if (ret != ERROR_SUCCESS) continue;
agi::fs::path font_path(font_filename);
if (!agi::fs::FileExists(font_path))
// Doesn't make a ton of sense to do this with user fonts, but they seem to be stored as full paths anyway
font_path = font_dir / font_path;
if (agi::fs::FileExists(font_path)) // The path might simply be invalid
files.push_back(font_path);
}
delete font_name;
delete font_filename;
}
namespace {
uint32_t murmur3(const char *data, uint32_t len) {
static const uint32_t c1 = 0xcc9e2d51;
@ -62,33 +103,17 @@ uint32_t murmur3(const char *data, uint32_t len) {
}
std::vector<agi::fs::path> get_installed_fonts() {
static const auto fonts_key_name = L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts";
std::vector<agi::fs::path> files;
HKEY key;
auto ret = RegOpenKeyExW(HKEY_LOCAL_MACHINE, fonts_key_name, 0, KEY_QUERY_VALUE, &key);
if (ret != ERROR_SUCCESS) return files;
BOOST_SCOPE_EXIT_ALL(=) { RegCloseKey(key); };
wchar_t fdir[MAX_PATH];
SHGetFolderPathW(NULL, CSIDL_FONTS, NULL, 0, fdir);
agi::fs::path font_dir(fdir);
for (DWORD i = 0;; ++i) {
wchar_t font_name[SHRT_MAX], font_filename[MAX_PATH];
DWORD name_len = sizeof(font_name);
DWORD data_len = sizeof(font_filename);
// System fonts
read_fonts_from_key(HKEY_LOCAL_MACHINE, font_dir, files);
ret = RegEnumValueW(key, i, font_name, &name_len, NULL, NULL, reinterpret_cast<BYTE *>(font_filename), &data_len);
if (ret == ERROR_NO_MORE_ITEMS) break;
if (ret != ERROR_SUCCESS) continue;
agi::fs::path font_path(font_filename);
if (!agi::fs::FileExists(font_path))
font_path = font_dir / font_path;
files.push_back(font_path);
}
// User fonts
read_fonts_from_key(HKEY_CURRENT_USER, font_dir, files);
return files;
}

View File

@ -52,6 +52,12 @@ namespace {
{nullptr}
};
const char *added_hotkeys_time_tap[][3] = {
{"time/tap/connect", "Audio", "I"},
{"time/tap/no_connect", "Audio", "O"},
{nullptr}
};
void migrate_hotkeys(const char *added[][3]) {
auto hk_map = hotkey::inst->GetHotkeyMap();
bool changed = false;
@ -121,6 +127,11 @@ void init() {
}
#endif
if (boost::find(migrations, "time/tap") == end(migrations)) {
migrate_hotkeys(added_hotkeys_time_tap);
migrations.emplace_back("time/tap");
}
OPT_SET("App/Hotkey Migrations")->SetListString(std::move(migrations));
}

View File

@ -22,8 +22,8 @@
"Audio" : {
"Auto" : {
"Commit" : false,
"Focus" : false,
"Commit" : true,
"Focus" : true,
"Scroll" : true
},
"Cache" : {
@ -49,7 +49,7 @@
"Waveform Style" : 0
},
"Downmixer" : "ConvertToMono",
"Drag Timing" : true,
"Drag Timing" : false,
"Inactive Lines Display Mode" : 3,
"Karaoke" : {
"Font Face" : "Verdana",
@ -60,7 +60,7 @@
"OUT" : 350
},
"Line Boundaries Thickness" : 2,
"Link" : true,
"Link" : false,
"Lock Scroll on Cursor" : false,
"Medusa Timing Hotkeys" : false,
"Next Line on Commit" : true,
@ -76,7 +76,7 @@
},
"Snap" : {
"Distance" : 8,
"Enable" : true
"Enable" : false
},
"Spectrum" : true,
"Start Drag Sensitivity" : 8,
@ -366,7 +366,7 @@
},
"Character Limit" : 40,
"Default Resolution" : {
"Auto" : true,
"Auto" : false,
"Height" : 720,
"Width" : 1280
},
@ -428,7 +428,8 @@
},
"Timing" : {
"Default Duration" : 3000
"Default Duration" : 3000,
"Tap To Time" : false
},
"Tool" : {
@ -606,11 +607,11 @@
"Open Audio" : true,
"Overscan Mask" : false,
"Provider" : "ffmpegsource",
"Script Resolution Mismatch" : 1,
"Script Resolution Mismatch" : 0,
"Slider" : {
"Fast Jump Step" : 10,
"Show Keyframes" : true
},
"Subtitle Sync" : true
}
}
}

View File

@ -16,10 +16,10 @@
"KP_8"
],
"time/length/decrease" : [
"KP_7"
"Z"
],
"time/length/increase" : [
"KP_9"
"E"
],
"time/next" : [
"KP_2"
@ -28,10 +28,16 @@
"KP_0"
],
"time/start/decrease" : [
"KP_4"
"Shift-Z"
],
"time/start/increase" : [
"KP_6"
"Shift-E"
],
"time/mark/connect" : [
"I"
],
"time/mark/no_connect" : [
"O"
]
},
"Audio" : {
@ -46,20 +52,20 @@
"Shift-G"
],
"audio/play/line" : [
"R"
"C"
],
"audio/play/selection" : [
"S",
"Space"
"Space",
"X"
],
"audio/play/selection/after" : [
"W"
"F"
],
"audio/play/selection/before" : [
"Q"
],
"audio/play/selection/begin" : [
"E"
"S"
],
"audio/play/selection/end" : [
"D"
@ -71,10 +77,10 @@
"B"
],
"audio/scroll/left" : [
"A"
"W"
],
"audio/scroll/right" : [
"F"
"V"
],
"audio/stop" : [
"H"
@ -98,12 +104,15 @@
"Shift-KP_Add"
],
"time/next" : [
"Right",
"X"
"R",
"Right"
],
"time/prev" : [
"Left",
"Z"
"A",
"Left"
],
"time/add_space" : [
"Ctrl-Space"
]
},
"Default" : {
@ -113,6 +122,33 @@
"app/options" : [
"Alt-O"
],
"automation/lua/duetto-meika/Deduetto Meika" : [
"Ctrl-Shift-D"
],
"automation/lua/duetto-meika/Duetto Meika" : [
"Ctrl-D"
],
"automation/lua/kara-templater/Apply karaoke template" : [
"Ctrl-Alt-Shift-K"
],
"automation/lua/karaoke-adjust-1sec/Karaoke 1sec adjust lead-in" : [
"Ctrl-K"
],
"automation/lua/karaoke-adjust-1sec/Mugenizer" : [
"Ctrl-Shift-K"
],
"automation/lua/karaoke-split/Split karaoke line" : [
"Ctrl-Shift-P"
],
"automation/lua/ua.ChangeCase/Change Case" : [
"Ctrl-Shift-C"
],
"automation/lua/ua.HYDRA/HYDRA" : [
"Ctrl-Shift-H"
],
"automation/lua/ua.ScriptCleanup/Script Cleanup" : [
"Ctrl-Shift-O"
],
"edit/find_replace" : [
"Ctrl-H"
],
@ -125,18 +161,18 @@
"edit/line/delete" : [
"Ctrl-Delete"
],
"edit/line/duplicate/shift" : [
"Ctrl-D"
],
"edit/line/duplicate/shift_back" : [
"Ctrl-Shift-D"
],
"edit/line/paste" : [
"Ctrl-V"
],
"edit/line/paste/over" : [
"Ctrl-Shift-V"
],
"edit/line/split/after" : [
"Ctrl-Alt-Shift-D"
],
"edit/line/split/before" : [
"Ctrl-Alt-D"
],
"edit/redo" : [
"Ctrl-Y"
],
@ -193,7 +229,7 @@
"Ctrl-3"
],
"video/focus_seek" : [
"Ctrl-Space"
"Alt-Space"
],
"video/frame/next" : [
"Ctrl-KP_6"
@ -359,4 +395,4 @@
"J"
]
}
}
}

View File

@ -203,6 +203,7 @@
{ "command" : "help/contents" },
{},
{ "command" : "help/website" },
{ "command" : "help/joysound_exporter" },
{ "command" : "help/bugs" },
{},
{ "command" : "help/irc" },

View File

@ -15,6 +15,9 @@
"time/lead/in",
"time/lead/out",
"",
"time/tap/connect",
"time/tap/no_connect",
"",
"audio/commit",
"audio/go_to",
"",
@ -23,6 +26,7 @@
"audio/opt/autoscroll",
"audio/opt/spectrum",
"app/toggle/global_hotkeys",
"time/opt/tap_to_time",
"",
"audio/karaoke"
],

View File

@ -428,7 +428,8 @@
},
"Timing" : {
"Default Duration" : 3000
"Default Duration" : 3000,
"Tap To Time" : false
},
"Tool" : {

View File

@ -16,10 +16,10 @@
"KP_8"
],
"time/length/decrease" : [
"KP_7"
"Z"
],
"time/length/increase" : [
"KP_9"
"E"
],
"time/next" : [
"KP_2"
@ -28,10 +28,10 @@
"KP_0"
],
"time/start/decrease" : [
"KP_4"
"Shift-Z"
],
"time/start/increase" : [
"KP_6"
"Shift-E"
]
},
"Audio" : {
@ -46,20 +46,20 @@
"Shift-G"
],
"audio/play/line" : [
"R"
"C"
],
"audio/play/selection" : [
"S",
"Space"
"Space",
"X"
],
"audio/play/selection/after" : [
"W"
"F"
],
"audio/play/selection/before" : [
"Q"
],
"audio/play/selection/begin" : [
"E"
"S"
],
"audio/play/selection/end" : [
"D"
@ -71,10 +71,10 @@
"B"
],
"audio/scroll/left" : [
"A"
"W"
],
"audio/scroll/right" : [
"F"
"V"
],
"audio/stop" : [
"H"
@ -98,12 +98,12 @@
"Shift-KP_Add"
],
"time/next" : [
"Right",
"X"
"R",
"Right"
],
"time/prev" : [
"Left",
"Z"
"A",
"Left"
]
},
"Default" : {
@ -116,6 +116,33 @@
"app/toggle/toolbar" : [
"Ctrl-Alt-T"
],
"automation/lua/duetto-meika/Deduetto Meika" : [
"Ctrl-Shift-D"
],
"automation/lua/duetto-meika/Duetto Meika" : [
"Ctrl-D"
],
"automation/lua/kara-templater/Apply karaoke template" : [
"Ctrl-Alt-Shift-K"
],
"automation/lua/karaoke-adjust-1sec/Karaoke 1sec adjust lead-in" : [
"Ctrl-K"
],
"automation/lua/karaoke-adjust-1sec/Mugenizer" : [
"Ctrl-Shift-K"
],
"automation/lua/karaoke-split/Split karaoke line" : [
"Ctrl-Shift-P"
],
"automation/lua/ua.ChangeCase/Change Case" : [
"Ctrl-Shift-C"
],
"automation/lua/ua.HYDRA/HYDRA" : [
"Ctrl-Shift-H"
],
"automation/lua/ua.ScriptCleanup/Script Cleanup" : [
"Ctrl-Shift-O"
],
"edit/find_replace" : [
"Ctrl-Alt-F"
],
@ -126,13 +153,7 @@
"Ctrl-X"
],
"edit/line/delete" : [
"Ctrl-Backspace"
],
"edit/line/duplicate/shift" : [
"Ctrl-D"
],
"edit/line/duplicate/shift_back" : [
"Ctrl-Shift-D"
"Ctrl-Delete"
],
"edit/line/paste" : [
"Ctrl-V"
@ -140,6 +161,12 @@
"edit/line/paste/over" : [
"Ctrl-Shift-V"
],
"edit/line/split/after" : [
"Ctrl-Alt-Shift-D"
],
"edit/line/split/before" : [
"Ctrl-Alt-D"
],
"edit/redo" : [
"Ctrl-Shift-Z"
],

View File

@ -213,6 +213,7 @@
{ "command" : "help/contents" },
{},
{ "command" : "help/website" },
{ "command" : "help/joysound_exporter" },
{ "command" : "help/bugs" },
{},
{ "command" : "help/irc" },

View File

@ -74,6 +74,10 @@ const char *GetVersionNumber() {
return BUILD_GIT_VERSION_STRING;
}
const char *GetReleaseVersion() {
return RELEASE_VERSION;
}
int GetSVNRevision() {
#ifdef BUILD_GIT_VERSION_NUMBER
return BUILD_GIT_VERSION_NUMBER;

View File

@ -46,3 +46,5 @@ bool GetIsOfficialRelease();
const char *GetVersionNumber();
/// Get SVN revision
int GetSVNRevision();
/// Get Release Version
const char *GetReleaseVersion();

@ -0,0 +1 @@
Subproject commit 74ef0dea87e3c10bbf0b4df90b663b8868d9cbd5

View File

@ -12,6 +12,8 @@ repack-thes-dict_CPPFLAGS := -I$(TOP) -I$(TOP)libaegisub/include $(CFLAGS_ICU)
PROGRAM += $(d)repack-thes-dict
$(TOP)tools/respack.lua: $(shell command -v "$(BIN_LUA)")
ifeq (no, $(SYSTEM_LUAJIT))
$(TOP)tools/respack.lua: $(BIN_LUA)
endif
include $(TOP)Makefile.target

View File

@ -45,10 +45,13 @@ else
tagged_release=0
fi
last_release=$(git describe --tags)
new_version_h="\
#define BUILD_GIT_VERSION_NUMBER ${git_revision}
#define BUILD_GIT_VERSION_STRING \"${git_version_str}\"
#define RELEASE_VERSION \"${last_release#v}\"
#define TAGGED_RELEASE ${tagged_release}
#define INSTALLER_VERSION \"${installer_version}\"
#define RESOURCE_BASE_VERSION ${resource_version}"
@ -68,7 +71,7 @@ export VERSION_SOURCE="from git"
cat << EOF > "${builddir}/git_version.xml"
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<GitVersionNumber>${git_revision}</GitVersionNumber>
<GitVersionString>${git_version_str}</GitVersionString>