├── .github └── workflows │ └── lint-aegisub.yml ├── .gitignore ├── .prettierrc.json ├── Aegisub ├── .gitignore ├── README.md ├── automation │ ├── autoload │ │ ├── 0x.DeriveTrack.moon │ │ ├── 0x.KaraTemplater.moon │ │ ├── ILL.ChangeAlign.moon │ │ ├── ILL.EnvelopeDistort.moon │ │ ├── ILL.MakeImage.moon │ │ ├── ILL.Shapery.moon │ │ ├── ILL.SplitText.moon │ │ ├── a-mo.Aegisub-Motion.moon │ │ ├── aka.Sandbox.lua │ │ ├── arch.AegisubChain.moon │ │ ├── arch.DerivePerspTrack.moon │ │ ├── arch.FocusLines.moon │ │ ├── arch.GitSigns.moon │ │ ├── arch.Line2Fbf.moon │ │ ├── arch.PerspectiveMotion.moon │ │ ├── arch.Resample.moon │ │ ├── l0.ASSWipe.moon │ │ ├── l0.DependencyControl.Toolbox.moon │ │ ├── l0.Nudge.moon │ │ ├── lightarrowsexe.tagstripper.moon │ │ ├── lightarrowsexe.weebswap.moon │ │ ├── lyger.GradientByChar.lua │ │ ├── lyger.GradientEverything.moon │ │ ├── lyger.LuaInterpret.lua │ │ ├── petzku.Autowrapper.moon │ │ ├── petzku.CombineGradientLines.lua │ │ ├── petzku.EncodeClip.lua │ │ ├── petzku.ExtrapolateMove.lua │ │ ├── petzku.NewClipShape.moon │ │ ├── petzku.Phantom.moon │ │ ├── petzku.PosToMargin.moon │ │ ├── petzku.SplitTimer.moon │ │ ├── petzku.ToggleTemplates.moon │ │ ├── phos.AddGrain.moon │ │ ├── phos.AutoFade.moon │ │ ├── phos.ChromaticAbberation.moon │ │ ├── phos.ExtrapolateTracking.moon │ │ ├── phos.FitTextInClip.moon │ │ ├── phos.RotateGradient.moon │ │ ├── phos.TimingAssistant.moon │ │ ├── phos.svg2ass.moon │ │ ├── ua.Recalculator.lua │ │ ├── ua.Selectrix.lua │ │ ├── zah.aegi-color-track.lua │ │ └── zah.autoclip.lua │ ├── include │ │ ├── 0x │ │ │ └── color.lua │ │ ├── BM │ │ │ ├── BadMutex.lua │ │ │ └── BadMutex │ │ │ │ └── BadMutex.dll │ │ ├── DM │ │ │ ├── DownloadManager.lua │ │ │ └── DownloadManager │ │ │ │ └── DownloadManager.dll │ │ ├── ILL │ │ │ ├── ILL.moon │ │ │ ├── ILL │ │ │ │ ├── Aegi.moon │ │ │ │ ├── Ass │ │ │ │ │ ├── Ass.moon │ │ │ │ │ ├── Line.moon │ │ │ │ │ ├── Shape │ │ │ │ │ │ ├── Curve.moon │ │ │ │ │ │ ├── Path.moon │ │ │ │ │ │ ├── Point.moon │ │ │ │ │ │ └── Segment.moon │ │ │ │ │ └── Text │ │ │ │ │ │ ├── Tag.moon │ │ │ │ │ │ ├── Tags.moon │ │ │ │ │ │ └── Text.moon │ │ │ │ ├── Config.moon │ │ │ │ ├── Font │ │ │ │ │ ├── Font.moon │ │ │ │ │ ├── Init.moon │ │ │ │ │ ├── Unx.moon │ │ │ │ │ └── Win.moon │ │ │ │ ├── Math.moon │ │ │ │ ├── Table.moon │ │ │ │ ├── UTF8.moon │ │ │ │ └── Util.moon │ │ │ ├── IMG.moon │ │ │ └── IMG │ │ │ │ ├── Potrace.moon │ │ │ │ ├── Tracer.moon │ │ │ │ ├── bitmap │ │ │ │ └── bitmap.moon │ │ │ │ ├── buffer │ │ │ │ └── buffer.moon │ │ │ │ ├── giflib │ │ │ │ ├── giflib.moon │ │ │ │ └── giflib │ │ │ │ │ └── giflib.dll │ │ │ │ ├── lodepng │ │ │ │ ├── lodepng.moon │ │ │ │ └── lodepng │ │ │ │ │ └── lodepng.dll │ │ │ │ └── turbojpeg │ │ │ │ ├── turbojpeg.moon │ │ │ │ └── turbojpeg │ │ │ │ └── turbojpeg.dll │ │ ├── PT │ │ │ ├── PreciseTimer.lua │ │ │ └── PreciseTimer │ │ │ │ └── PreciseTimer.dll │ │ ├── SubInspector │ │ │ ├── Inspector.moon │ │ │ └── Inspector │ │ │ │ └── SubInspector.dll │ │ ├── Yutils.lua │ │ ├── a-mo │ │ │ ├── ConfigHandler.moon │ │ │ ├── DataHandler.moon │ │ │ ├── DataWrapper.moon │ │ │ ├── Line.moon │ │ │ ├── LineCollection.moon │ │ │ ├── Log.moon │ │ │ ├── Math.moon │ │ │ ├── MotionHandler.moon │ │ │ ├── ShakeShapeHandler.moon │ │ │ ├── Statistics.moon │ │ │ ├── Tags.moon │ │ │ ├── Transform.moon │ │ │ └── TrimHandler.moon │ │ ├── aka │ │ │ ├── StackTracePlus │ │ │ │ ├── StackTracePlus.lua │ │ │ │ └── init.lua │ │ │ ├── command │ │ │ │ └── init.lua │ │ │ ├── config │ │ │ │ ├── config.lua │ │ │ │ └── init.lua │ │ │ ├── config2 │ │ │ │ ├── config2.lua │ │ │ │ ├── init.lua │ │ │ │ └── json.lua │ │ │ ├── outcome │ │ │ │ └── init.lua │ │ │ ├── uikit │ │ │ │ ├── buttons.lua │ │ │ │ ├── dialog.lua │ │ │ │ ├── display.moon │ │ │ │ └── init.lua │ │ │ ├── unicode │ │ │ │ └── init.lua │ │ │ └── unsemantic │ │ │ │ └── init.lua │ │ ├── arch │ │ │ ├── Math.moon │ │ │ ├── Perspective.moon │ │ │ └── Util.moon │ │ ├── clipper2 │ │ │ ├── clipper2.moon │ │ │ └── clipper2 │ │ │ │ └── clipper2.dll │ │ ├── json.lua │ │ ├── json │ │ │ ├── decode.lua │ │ │ ├── decode │ │ │ │ ├── composite.lua │ │ │ │ ├── number.lua │ │ │ │ ├── others.lua │ │ │ │ ├── state.lua │ │ │ │ ├── strings.lua │ │ │ │ └── util.lua │ │ │ ├── encode.lua │ │ │ ├── encode │ │ │ │ ├── array.lua │ │ │ │ ├── calls.lua │ │ │ │ ├── number.lua │ │ │ │ ├── object.lua │ │ │ │ ├── others.lua │ │ │ │ ├── output.lua │ │ │ │ ├── output_utility.lua │ │ │ │ └── strings.lua │ │ │ └── util.lua │ │ ├── l0 │ │ │ ├── ASSFoundation.moon │ │ │ ├── ASSFoundation │ │ │ │ ├── Base.moon │ │ │ │ ├── ClassFactory.lua │ │ │ │ ├── Draw │ │ │ │ │ ├── Bezier.moon │ │ │ │ │ ├── Close.moon │ │ │ │ │ ├── CommandBase.moon │ │ │ │ │ ├── Contour.moon │ │ │ │ │ ├── DrawingBase.moon │ │ │ │ │ ├── Line.moon │ │ │ │ │ ├── Move.moon │ │ │ │ │ └── MoveNc.moon │ │ │ │ ├── FoundationMethods.moon │ │ │ │ ├── LineBounds.moon │ │ │ │ ├── LineBoundsBatch.moon │ │ │ │ ├── LineContents.moon │ │ │ │ ├── Parser │ │ │ │ │ ├── Drawing.moon │ │ │ │ │ ├── LineText.moon │ │ │ │ │ └── Sections.moon │ │ │ │ ├── Primitive │ │ │ │ │ ├── Number.moon │ │ │ │ │ ├── Point.moon │ │ │ │ │ ├── String.moon │ │ │ │ │ └── Time.moon │ │ │ │ ├── Section │ │ │ │ │ ├── Comment.moon │ │ │ │ │ ├── Drawing.moon │ │ │ │ │ ├── Tag.moon │ │ │ │ │ └── Text.moon │ │ │ │ ├── Tag │ │ │ │ │ ├── Align.moon │ │ │ │ │ ├── Base.moon │ │ │ │ │ ├── ClipRect.moon │ │ │ │ │ ├── ClipVect.moon │ │ │ │ │ ├── Color.moon │ │ │ │ │ ├── Fade.moon │ │ │ │ │ ├── Indexed.moon │ │ │ │ │ ├── Move.moon │ │ │ │ │ ├── String.moon │ │ │ │ │ ├── Toggle.moon │ │ │ │ │ ├── Transform.moon │ │ │ │ │ ├── Unknown.moon │ │ │ │ │ └── Weight.moon │ │ │ │ └── TagList.moon │ │ │ ├── DependencyControl.moon │ │ │ ├── DependencyControl │ │ │ │ ├── ConfigHandler.moon │ │ │ │ ├── FileOps.moon │ │ │ │ ├── Logger.moon │ │ │ │ ├── UnitTestSuite.moon │ │ │ │ ├── UpdateFeed.moon │ │ │ │ └── Updater.moon │ │ │ └── Functional.moon │ │ ├── ln │ │ │ └── kara.lua │ │ ├── lyger │ │ │ └── LibLyger.moon │ │ ├── myaa │ │ │ └── ASSParser.moon │ │ ├── petzku │ │ │ ├── easings.moon │ │ │ ├── tags.moon │ │ │ └── util.moon │ │ ├── phos │ │ │ ├── AegiGui.moon │ │ │ └── AssfPlus.moon │ │ └── requireffi │ │ │ └── requireffi.lua │ └── tests │ │ └── DepUnit │ │ └── modules │ │ └── l0 │ │ └── Functional.moon ├── catalog │ └── Default.sty ├── config.json ├── config │ ├── ILL.ShaperyConfig.json │ ├── ILL.ShaperyManipulate.json │ ├── ILL.ShaperyOffsetting.json │ ├── ILL.ShaperyPathfinder.json │ ├── ILL.ShaperyTransform.json │ ├── ILL.ShaperyUtilities.json │ ├── aka.Sandbox │ │ ├── dialog.json │ │ └── presets.json │ ├── arch.AegisubChain.json │ ├── l0.ASSWipe.json │ ├── l0.DependencyControl.json │ ├── l0.Nudge.json │ ├── lightarrowsexe.weebswap.json │ ├── lyger.GradientEverything.json │ ├── petzku.EncodeClip.json │ └── phos.TimingAssistant.json ├── dictionaries │ ├── en_GB.aff │ └── en_GB.dic ├── hotkey.json └── luaint-presets.config ├── LICENSE ├── README.md └── mpv ├── .gitignore ├── README.md ├── github └── img │ ├── dscale │ ├── bilinear.png │ ├── catrom.png │ ├── dpid.png │ ├── lanczos.png │ ├── mitchell.png │ ├── spline36.png │ ├── ssim.png │ └── zewiacubic.png │ └── dscale_supersample │ ├── bilinear.png │ ├── catrom.png │ ├── dpid.png │ ├── lanczos.png │ ├── mitchell.png │ ├── spline36.png │ ├── src.png │ ├── ssim.png │ └── zewiacubic.png ├── input.conf ├── mpv.conf ├── mpv_switch.conf ├── playlistmanager.conf ├── scripts ├── autoload.lua ├── boss-key.lua ├── cycle-profile.lua ├── reload.lua ├── sponsorblock.lua ├── status-line.lua ├── thumbfast.conf ├── thumbfast.lua └── webm.lua ├── shaders ├── ArtCNN_C4F32.glsl ├── FSRCNNX_x2_16-0-4-1.glsl ├── FSRCNNX_x2_56-16-4-1.glsl ├── KrigBilateral.glsl ├── SSimDownscaler.glsl ├── nnedi3-nns256-win8x4.hook ├── nnedi3-nns256-win8x6.hook ├── nnedi3-nns32-win8x6.hook ├── nnedi3-nns64-win8x4.hook ├── nnedi3-nns64-win8x6.hook ├── ravu-r3.hook └── ravu-r4.hook └── vs ├── color_correction ├── 601to709.py ├── 709to601.py ├── drc.py └── gamma.py ├── filter ├── simulcast.py └── swift_denoise.py ├── funcs ├── __init__.py ├── colors.py ├── diagnostics.py └── filters.py ├── histogram ├── classic.py ├── color.py ├── color2.py └── levels.py └── info ├── frameinfo.py └── globals.py /.github/workflows/lint-aegisub.yml: -------------------------------------------------------------------------------- 1 | name: Lint and Fix Aegisub JSON config files 2 | 3 | on: 4 | push: 5 | paths: 6 | - 'Aegisub/**/*.json' 7 | - '.github/workflows/**' 8 | - '.prettierrc.json' 9 | pull_request: 10 | paths: 11 | - 'Aegisub/**/*.json' 12 | - '.github/workflows/**' 13 | - '.prettierrc.json' 14 | 15 | jobs: 16 | auto-fix: 17 | name: Auto-fix JSON formatting on push 18 | if: github.event_name == 'push' 19 | runs-on: ubuntu-latest 20 | 21 | steps: 22 | - name: Checkout repository 23 | uses: actions/checkout@v3 24 | 25 | - name: Set up Node.js 26 | uses: actions/setup-node@v4 27 | with: 28 | node-version: '18' 29 | 30 | - name: Install Prettier 31 | run: npm install -g prettier 32 | 33 | - name: Format JSON files with Prettier 34 | run: | 35 | prettier --write "Aegisub/**/*.json" 36 | 37 | - name: Commit and push changes 38 | run: | 39 | git config --global user.name 'github-actions[bot]' 40 | git config --global user.email 'github-actions[bot]@users.noreply.github.com' 41 | git add Aegisub/**/*.json 42 | git diff --cached --quiet || git commit -m "style: auto-format JSON files with Prettier" 43 | git push 44 | env: 45 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 46 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | mpv/.config/mpv/scripts/*shared*/* 2 | mpv/.config/mpv/watch_later/* 3 | *cookies*.txt 4 | *.7z 5 | mpv/.config/mpv/lua-settings/myshows.conf 6 | mpv/.config/mpv/7z/* 7 | *.pyc 8 | *.exe 9 | *.bat 10 | mpv/.config/mpv/installer/updater.ps1 11 | mpv/.config/mpv/settings.xml 12 | *.com 13 | mpv/.config/mpv/d3dcompiler_43.dll 14 | Aegisub/config.json 15 | -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 80, 3 | "tabWidth": 2, 4 | "useTabs": false, 5 | "semi": true, 6 | "singleQuote": true, 7 | "trailingComma": "none" 8 | } 9 | -------------------------------------------------------------------------------- /Aegisub/.gitignore: -------------------------------------------------------------------------------- 1 | # Autosaves and backups 2 | autoback/**/* 3 | autosave/**/* 4 | 5 | # Logs 6 | /feedDump/**/* 7 | /log/**/* 8 | 9 | # Random files 10 | mru.json 11 | shift_history.json 12 | config_tmp_*.json 13 | 14 | -------------------------------------------------------------------------------- /Aegisub/README.md: -------------------------------------------------------------------------------- 1 | # Aegisub 2 | 3 | My Aegisub configuration files. 4 | This setup is very free-flowing, 5 | unlike my mpv config, 6 | since new tooling is made semi-frequently 7 | and new techniques are found from time to time too. 8 | -------------------------------------------------------------------------------- /Aegisub/automation/autoload/0x.DeriveTrack.moon: -------------------------------------------------------------------------------- 1 | require 'karaskel' 2 | 3 | check_cancel = () -> 4 | if aegisub.progress.is_cancelled! 5 | aegisub.cancel! 6 | 7 | main = (subs, sel, active) -> 8 | meta, styles = karaskel.collect_head subs, false 9 | 10 | positions = {} 11 | scales = {} 12 | rotations = {} 13 | 14 | for i in *sel 15 | line = subs[i] 16 | style = styles[line.style] 17 | 18 | insert = (t, v) -> 19 | 20 | local pos, fscx, fscy, frz 21 | for block in line.text\gmatch '{.-}' 22 | if pos_tag = block\match '\\pos%([0-9.-]+,[0-9.-]+%)' 23 | x, y = pos_tag\match '([0-9.-]+),([0-9.-]+)' 24 | pos = {x: x, y: y} 25 | 26 | fscx = block\match('\\fscx([0-9.-]+)') 27 | fscy = block\match('\\fscy([0-9.-]+)') 28 | frz = block\match('\\frz([0-9.-]+)') 29 | 30 | if pos == nil 31 | aegisub.log 'missing pos tag\n' 32 | fscx or= style.scale_x 33 | fscy or= style.scale_y 34 | frz or= style.angle 35 | 36 | start_frame = aegisub.frame_from_ms line.start_time 37 | end_frame = aegisub.frame_from_ms line.end_time 38 | for _ = start_frame, end_frame - 1 39 | table.insert positions, pos 40 | table.insert scales, {x: fscx, y: fscy} 41 | table.insert rotations, frz 42 | 43 | data = {} 44 | println = (fmt, ...) -> table.insert data, string.format(fmt or '', ...) 45 | println 'Adobe After Effects 6.0 Keyframe Data' 46 | println '' 47 | println '\tUnits per Second\t23.976' 48 | println '\tSource Width\t%d', meta.res_x 49 | println '\tSource Height\t%d', meta.res_y 50 | println '\tSource Pixel Aspect Ratio\t1' 51 | println '\tComp Pixel Aspect Ratio\t1' 52 | println '' 53 | 54 | println 'Position' 55 | println '\tFrame\tX pixels\tY pixels\tZ pixels' 56 | for i, pos in ipairs positions 57 | println '\t%d\t%f\t%f\t0', i - 1, pos.x, pos.y 58 | 59 | println '' 60 | println 'Scale' 61 | println '\tFrame\tX percent\tY percent\tZ percent' 62 | for i, scale in ipairs scales 63 | println '\t%d\t%f\t%f\t0', i - 1, scale.x, scale.y 64 | 65 | println '' 66 | println 'Rotation' 67 | println '\tFrame\tDegrees' 68 | for i, rotation in ipairs rotations 69 | println '\t%d\t%f', i - 1, -rotation 70 | 71 | result = table.concat data, '\n' 72 | 73 | aegisub.log result 74 | 75 | validate = (subs, sel, _active) -> 76 | -- tag blocks' contents can (and probably will) change, but their presence shouldn't 77 | strip = (line) -> line.text\gsub '{.-}', '{}' 78 | 79 | -- no meaningful derivation if there isn't a selection of multiple lines 80 | return false if #sel < 2 81 | 82 | for i = 2, #sel 83 | i0, i1 = sel[i - 1], sel[i] 84 | line0, line1 = subs[i0], subs[i1] 85 | if strip(line0) != strip(line1) or 86 | line0.end_time != line1.start_time or 87 | line0.layer != line1.layer or 88 | line0.comment != line1.comment 89 | return false 90 | 91 | return true 92 | 93 | aegisub.register_macro 'Aegisub-Motion/Derive', 'Attempt to derive motion tracking data from tracked lines', main, validate 94 | -------------------------------------------------------------------------------- /Aegisub/automation/autoload/ILL.ChangeAlign.moon: -------------------------------------------------------------------------------- 1 | export script_name = "Change Alignment" 2 | export script_description = "Changes the alignment of a text or shape without changing its original position" 3 | export script_version = "1.1.1" 4 | export script_author = "ILLTeam" 5 | export script_namespace = "ILL.ChangeAlign" 6 | 7 | haveDepCtrl, DependencyControl = pcall require, "l0.DependencyControl" 8 | 9 | local depctrl, Aegi, Ass, Line, Path 10 | if haveDepCtrl 11 | depctrl = DependencyControl { 12 | feed: "https://raw.githubusercontent.com/TypesettingTools/ILL-Aegisub-Scripts/main/DependencyControl.json", 13 | { 14 | { 15 | "ILL.ILL" 16 | version: "1.4.4" 17 | url: "https://github.com/TypesettingTools/ILL-Aegisub-Scripts/" 18 | feed: "https://raw.githubusercontent.com/TypesettingTools/ILL-Aegisub-Scripts/main/DependencyControl.json" 19 | } 20 | } 21 | } 22 | {:Aegi, :Ass, :Line, :Path} = depctrl\requireModules! 23 | else 24 | {:Aegi, :Ass, :Line, :Path} = require "ILL.ILL" 25 | 26 | interface = -> 27 | gui = {} 28 | for y = 0, 2 29 | for x = 2, 0, -1 do 30 | z = x + (2 - y) * 3 + 1 31 | table.insert gui, {class: "checkbox", name: z, label: z, :x, :y, value: false} 32 | return gui 33 | 34 | main = (sub, sel, activeLine) -> 35 | button, elements = aegisub.dialog.display interface!, {"Ok", "Cancel"}, {close: "Cancel"} 36 | if button == "Ok" 37 | local aln 38 | for k, v in pairs elements 39 | if v == true 40 | if aln 41 | Aegi.progressCancel "Expected only one selection" 42 | aln = tonumber k 43 | unless aln 44 | Aegi.progressCancel "Expected selection" 45 | ass = Ass sub, sel, activeLine 46 | for l, s, i, n in ass\iterSel! 47 | ass\progressLine s, i, n 48 | Line.extend ass, l 49 | Line.changeAlign l, aln 50 | ass\setLine l, s 51 | 52 | if haveDepCtrl 53 | depctrl\registerMacro main 54 | else 55 | aegisub.register_macro script_name, script_description, main -------------------------------------------------------------------------------- /Aegisub/automation/autoload/ILL.SplitText.moon: -------------------------------------------------------------------------------- 1 | export script_name = "ILL - Split Text" 2 | export script_description = "Splits the text in several ways" 3 | export script_version = "2.1.2" 4 | export script_author = "ILLTeam" 5 | export script_namespace = "ILL.SplitText" 6 | 7 | haveDepCtrl, DependencyControl = pcall require, "l0.DependencyControl" 8 | 9 | local depctrl, ILL 10 | if haveDepCtrl 11 | depctrl = DependencyControl { 12 | feed: "https://raw.githubusercontent.com/TypesettingTools/ILL-Aegisub-Scripts/main/DependencyControl.json", 13 | { 14 | { 15 | "ILL.ILL" 16 | version: "1.6.4" 17 | url: "https://github.com/TypesettingTools/ILL-Aegisub-Scripts/" 18 | feed: "https://raw.githubusercontent.com/TypesettingTools/ILL-Aegisub-Scripts/main/DependencyControl.json" 19 | } 20 | } 21 | } 22 | ILL = depctrl\requireModules! 23 | else 24 | ILL = require "ILL.ILL" 25 | 26 | {:Ass, :Line} = ILL 27 | 28 | main = (mode) -> 29 | (sub, sel, activeLine) -> 30 | ass = Ass sub, sel, activeLine, false 31 | for l, s, i, n in ass\iterSel! 32 | ass\progressLine s, i, n 33 | unless l.isShape 34 | ass\removeLine l, s 35 | Line.extend ass, l, false 36 | for line in *switch mode 37 | when "chars" then Line.chars ass, l, true 38 | when "words" then Line.words ass, l, true 39 | when "breaks" then Line.breaks ass, l, true 40 | when "tags" then Line.tags ass, l, true 41 | fr = line.data.angle != 0 42 | if fr or line.text\existsTagOr "frx", "fry", "frz" 43 | line.tags\insert {{"org", line.data.org}, true} 44 | unless line.tags\existsTag "move" 45 | line.tags\insert {{"pos", Line.reallocate l, line}, true} 46 | else 47 | line.tags\insert {{"move", Line.reallocate l, line, true}, true} 48 | line.text\modifyBlock line.tags 49 | ass\insertLine line, s 50 | else 51 | ass\warning s, "Only divite text not shapes" 52 | return ass\getNewSelection! 53 | 54 | if haveDepCtrl 55 | depctrl\registerMacros { 56 | {"By Chars", "", main "chars"} 57 | {"By Words", "", main "words"} 58 | {"By Tags Blocks", "", main "tags"} 59 | {"By Line Breaks", "", main "breaks"} 60 | } 61 | else 62 | aegisub.register_macro "#{script_name}/By Chars", "", main "chars" 63 | aegisub.register_macro "#{script_name}/By Words", "", main "words" 64 | aegisub.register_macro "#{script_name}/By Tags Blocks", "", main "tags" 65 | aegisub.register_macro "#{script_name}/By Line Breaks", "", main "breaks" -------------------------------------------------------------------------------- /Aegisub/automation/autoload/arch.Line2Fbf.moon: -------------------------------------------------------------------------------- 1 | export script_name = "FBF-ifier" -- thank Light for the name, I needed something that doesn't clash with Zeref's "Line To FBF" 2 | export script_description = "Convert lines into frame-by-frame chunks" 3 | export script_author = "arch1t3cht" 4 | export script_namespace = "arch.Line2Fbf" 5 | export script_version = "0.1.0" 6 | 7 | DependencyControl = require "l0.DependencyControl" 8 | dep = DependencyControl{ 9 | feed: "https://raw.githubusercontent.com/TypesettingTools/arch1t3cht-Aegisub-Scripts/main/DependencyControl.json", 10 | { 11 | {"a-mo.LineCollection", version: "1.3.0", url: "https://github.com/TypesettingTools/Aegisub-Motion", 12 | feed: "https://raw.githubusercontent.com/TypesettingTools/Aegisub-Motion/DepCtrl/DependencyControl.json"}, 13 | {"l0.ASSFoundation", version: "0.5.0", url: "https://github.com/TypesettingTools/ASSFoundation", 14 | feed: "https://raw.githubusercontent.com/TypesettingTools/ASSFoundation/master/DependencyControl.json"}, 15 | {"arch.Util", version: "0.1.0", url: "https://github.com/TypesettingTools/arch1t3cht-Aegisub-Scripts", 16 | feed: "https://raw.githubusercontent.com/TypesettingTools/arch1t3cht-Aegisub-Scripts/main/DependencyControl.json"}, 17 | } 18 | } 19 | LineCollection, ASS, Util = dep\requireModules! 20 | 21 | logger = dep\getLogger! 22 | 23 | fbfify = (subs, sel, active) -> 24 | lines = LineCollection subs, sel, () -> true 25 | 26 | to_delete = {} 27 | lines\runCallback ((lines, line) -> 28 | data = ASS\parse line 29 | 30 | table.insert to_delete, line 31 | 32 | fbf = Util.line2fbf data 33 | for fbfline in *fbf 34 | lines\addLine fbfline 35 | ), true 36 | 37 | lines\insertLines! 38 | lines\deleteLines to_delete 39 | 40 | dep\registerMacro fbfify 41 | 42 | -------------------------------------------------------------------------------- /Aegisub/automation/autoload/lightarrowsexe.tagstripper.moon: -------------------------------------------------------------------------------- 1 | C:/Users/light/Documents/GitHub/Aegisub-Scripts/macros/lightarrowsexe.tagstripper.moon -------------------------------------------------------------------------------- /Aegisub/automation/autoload/lightarrowsexe.weebswap.moon: -------------------------------------------------------------------------------- 1 | C:/Users/light/Documents/GitHub/Aegisub-Scripts/macros/lightarrowsexe.weebswap.moon -------------------------------------------------------------------------------- /Aegisub/automation/autoload/petzku.Autowrapper.moon: -------------------------------------------------------------------------------- 1 | export script_name = "Autowrapper" 2 | export script_description = "Automatically set/unset \\q2 on lines with/without manual linebreaks" 3 | export alt_description = "Automatically unset \\q2 on lines without manual linebreaks" 4 | export script_author = "petzku" 5 | export script_namespace = "petzku.Autowrapper" 6 | export script_version = "0.5.1" 7 | 8 | havedc, DependencyControl, dep = pcall require, "l0.DependencyControl" 9 | if havedc 10 | dep = DependencyControl{ 11 | feed: "https://raw.githubusercontent.com/petzku/Aegisub-Scripts/stable/DependencyControl.json", 12 | {'karaskel'} 13 | } 14 | dep\requireModules! 15 | else 16 | require 'karaskel' 17 | 18 | lines_needed = (meta, line) -> 19 | -- maximum width of line before automatically wrapping 20 | -- eff_margin takes into account in-line margins 21 | wrap_width = meta.res_x - line.eff_margin_l - line.eff_margin_r 22 | line.width / wrap_width 23 | 24 | process = (subs, _sel, add_q2=true, rem_q2=true) -> 25 | meta, styles = karaskel.collect_head subs, false 26 | -- operate on all dialogue lines, not just selection 27 | -- maybe change this? 28 | res_addq2, res_autobreak, res_remq2 = 0,0,0 29 | res_overq2 = 0 30 | res_threelines, res_maybethree = 0, 0 31 | for i, line in ipairs subs 32 | continue unless line.class == 'dialogue' and not line.comment 33 | karaskel.preproc_line subs, meta, styles, line 34 | 35 | if line.text_stripped\find '\\N' 36 | if add_q2 and not line.text\find '\\q2' 37 | line.text = '{\\q2}'..line.text 38 | res_addq2 += 1 39 | else 40 | lines = lines_needed meta, line 41 | if not line.text\find '\\q2' 42 | if lines > 2 43 | -- three-liner 44 | line.effect ..= "## THREE-LINER ##" 45 | res_threelines += 1 46 | elseif lines > 1.9 47 | -- maybe three-liner 48 | line.effect ..= "## POSSIBLE THREE-LINER ##" 49 | res_maybethree += 1 50 | elseif lines > 1 51 | -- warn, do not add \q2 52 | line.effect ..= "## AUTOMATIC LINEBREAK ##" 53 | res_autobreak += 1 54 | else 55 | if lines > 1 56 | -- overwidth but has \q2 57 | line.effect ..= "## OVERWIDTH WITH FORCED WRAP ##" 58 | res_overq2 += 1 59 | elseif rem_q2 60 | line.text = line.text\gsub '\\q2', '' 61 | -- and remove empty tag blocks, if we caused one 62 | line.text = line.text\gsub '{}', '' 63 | res_remq2 += 1 64 | subs[i] = line 65 | aegisub.set_undo_point "automatically set/unset \\q2" 66 | 67 | if res_addq2 > 0 then aegisub.log "Added %d \\q2's on lines with \\N\n", res_addq2 68 | if res_autobreak > 0 then aegisub.log "Found %d automatic linebreaks\n", res_autobreak 69 | if res_threelines + res_maybethree > 0 then aegisub.log "Found %d three-liners and %d likely ones\n", res_threelines, res_maybethree 70 | if res_overq2 > 0 then aegisub.log "Found %d overwidth lines with forced wrapping\n", res_overq2 71 | if res_remq2 > 0 then aegisub.log "Removed %d \\q2's from lines without \\N\n", res_remq2 72 | 73 | main = (subs, sel) -> 74 | process subs, sel 75 | 76 | no_q2 = (subs, sel) -> 77 | process subs, sel, false 78 | 79 | comment = (subs, sel) -> 80 | process subs, sel, false, false 81 | 82 | macros = { 83 | { "Add missing \\q2 tags", script_description, main }, 84 | { "Remove unnecessary \\q2 tags", alt_description, no_q2 }, 85 | { "Only note automatic breaks", "", comment } 86 | } 87 | 88 | if havedc 89 | dep\registerMacros macros 90 | else 91 | for m in *macros 92 | name, desc, fun = unpack m 93 | aegisub.register_macro script_name..'/'..name, desc, fun 94 | -------------------------------------------------------------------------------- /Aegisub/automation/autoload/petzku.ExtrapolateMove.lua: -------------------------------------------------------------------------------- 1 | -- Copyright (c) 2020, petzku 2 | -- 3 | -- Permission to use, copy, modify, and distribute this software for any 4 | -- purpose with or without fee is hereby granted, provided that the above 5 | -- copyright notice and this permission notice appear in all copies. 6 | -- 7 | -- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | -- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | -- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | -- ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | -- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | -- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | -- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | 15 | --[[ README 16 | 17 | Extrapolate a \move over a portion of line's length to full line length. 18 | 19 | More specifically, compute the four-param move tag which will match the 20 | currently existing six-param movement. Should work even if one or more 21 | timestamps are outside the line's duration. Those will just be clipped 22 | to the line's time bounds. 23 | 24 | ]] 25 | 26 | script_name = "Extrapolate Move" 27 | script_description = "Extrapolates a \\move tag to the line's full duration" 28 | script_version = "0.1.5" 29 | script_author = "petzku" 30 | script_namespace = "petzku.ExtrapolateMove" 31 | 32 | local haveDepCtrl, DependencyControl, depctrl = pcall(require, "l0.DependencyControl") 33 | if haveDepCtrl then 34 | depctrl = DependencyControl{ 35 | feed = "https://raw.githubusercontent.com/petzku/Aegisub-Scripts/stable/DependencyControl.json", 36 | {'karaskel'} 37 | } 38 | depctrl:requireModules() 39 | else 40 | require 'karaskel' 41 | end 42 | 43 | --- Extrapolates movement to full line length from given move 44 | -- coordinate order is the same as ASS \move tag 45 | -- all six \move tag params are mandatory 46 | function extrapolate(t_start, t_end, x1, y1, x2, y2, t1, t2) 47 | length = t2 - t1 48 | dx = (x2 - x1) / length 49 | dy = (y2 - y1) / length 50 | 51 | start_x = x1 - dx * (t1 - t_start) 52 | start_y = y1 - dy * (t1 - t_start) 53 | end_x = x2 + dx * (t_end - t2) 54 | end_y = y2 + dy * (t_end - t2) 55 | 56 | return start_x, start_y, end_x, end_y; 57 | end 58 | 59 | function extrapolate_move_to_full_line(subs, sel) 60 | local meta, styles = karaskel.collect_head(subs, false) 61 | for si, li in ipairs(sel) do 62 | local line = subs[li] 63 | karaskel.preproc_line(subs, meta, styles, line) 64 | 65 | -- kinda evil regex matching, can I avoid this? 66 | regex_movtag = "\\move%(%-?[%d.]+,%-?[%d.]+,%-?[%d.]+,%-?[%d.]+,%-?[%d.]+,%-?[%d.]+%)" 67 | movtag = line.text:match(regex_movtag) 68 | if movtag ~= nil then 69 | -- really ugly :/ 70 | t = {} 71 | for num in movtag:gmatch("%-?[%d.]+") do 72 | t[#t+1] = tonumber(num) 73 | end 74 | x1, y1, x2, y2 = extrapolate(0, line.duration, unpack(t)) 75 | newtag = string.format("\\move(%.2f,%.2f,%.2f,%.2f)", x1, y1, x2, y2) 76 | newtext = line.text:gsub(regex_movtag, newtag, 1) 77 | line.text = newtext 78 | subs[li] = line 79 | end 80 | end 81 | end 82 | 83 | if haveDepCtrl then 84 | depctrl:registerMacro(extrapolate_move_to_full_line) 85 | else 86 | aegisub.register_macro(script_name, script_description, extrapolate_move_to_full_line) 87 | end 88 | -------------------------------------------------------------------------------- /Aegisub/automation/autoload/petzku.NewClipShape.moon: -------------------------------------------------------------------------------- 1 | -- Copyright (c) 2021 petzku 2 | 3 | export script_name = "New Clip Shape" 4 | export script_description = "Converts the last point of a vectorial clip into a new origin point" 5 | export script_author = "petzku" 6 | export script_namespace = "petzku.NewClipShape" 7 | export script_version = "0.3.2" 8 | 9 | havedc, DependencyControl, dep = pcall require, "l0.DependencyControl" 10 | if havedc 11 | dep = DependencyControl{feed: "https://raw.githubusercontent.com/petzku/Aegisub-Scripts/stable/DependencyControl.json"} 12 | 13 | make_final_move = (clip) -> 14 | aegisub.log 4, "make_final_move('%s')\n", clip 15 | 16 | clip\gsub " ([-%d.]+ [-%d.]+)%s*$", " m %1" 17 | 18 | rep_clip_tag = (tag) -> 19 | tag\gsub "m [^)]+", make_final_move 20 | 21 | main = (subs, sel) -> 22 | for i in *sel 23 | line = subs[i] 24 | 25 | aegisub.log 5, "looking at line %d: %s\n", i, line.text 26 | continue unless line.text\match "\\i?clip%(m .*%)" 27 | 28 | -- very permissive pattern, because make_final_move only needs one valid pair of coords at the end 29 | line.text = line.text\gsub "\\i?clip%(m .*%)", rep_clip_tag 30 | 31 | aegisub.log 5, "after gsub, line.text: %s\n", line.text 32 | 33 | subs[i] = line 34 | 35 | can_run = (subs, sel) -> 36 | for i in *sel 37 | line = subs[i] 38 | return true if line.text\match "\\i?clip%(m .*%)" 39 | false 40 | 41 | if havedc 42 | dep\registerMacro main, can_run 43 | else 44 | aegisub.register_macro script_name, script_description, main, can_run 45 | -------------------------------------------------------------------------------- /Aegisub/automation/autoload/petzku.Phantom.moon: -------------------------------------------------------------------------------- 1 | -- Copyright (c) 2022, petzku 2 | 3 | export script_name = "Phantom" 4 | export script_description = "Align line content to match others by adding text and abusing transparency" 5 | export script_author = "petzku" 6 | export script_namespace = "petzku.Phantom" 7 | export script_version = "1.1.1" 8 | 9 | -- Currently uses {} as delimiters 10 | -- e.g. "foo{}bar{}baz" -> "barfoobarbaz" 11 | 12 | -- Additionally, if using a version of aegisub exposing cursor position, an extra macro is registered, 13 | -- using the selection (and direction of it) to determine the "desired" output. 14 | 15 | havedc, DependencyControl, dep = pcall require, "l0.DependencyControl" 16 | dep = DependencyControl{feed: "https://raw.githubusercontent.com/petzku/Aegisub-Scripts/stable/DependencyControl.json"} if havedc 17 | 18 | HIDE = "{\\alpha&HFF&}" 19 | SHOW = "{\\alpha}" 20 | 21 | proc_align_start = (beg, mid, den) -> HIDE..mid..SHOW..beg..mid..HIDE..den 22 | proc_align_end = (beg, mid, den) -> HIDE..beg..SHOW..mid..den..HIDE..mid 23 | 24 | pattern_replacer = (rep) -> (part, _offset) -> 25 | -- thanks for the Universal Pattern Hammer, arch1t3ct 26 | part\gsub "^(.-){}(.-){}(.-)$", rep 27 | 28 | cursor_proc = (part, offset) -> 29 | sels, sele = aegisub.gui.get_selection() 30 | cur = aegisub.gui.get_cursor() or sele 31 | -- blame arch1t3ct if this can be something other than a selection endpoint 32 | proc = if sele == cur then proc_align_start else proc_align_end 33 | 34 | sels = sels - offset 35 | sele = sele - offset 36 | 37 | if sels > part\len! or sele < 1 38 | part 39 | else 40 | proc part\sub(1, sels-1), part\sub(sels, sele-1), part\sub(sele) 41 | 42 | 43 | -- only operate on active line; ignore selection 44 | main = (sub, act, proc) -> 45 | line = sub[act] 46 | 47 | -- extract start tags 48 | start, text = line.text\match "^({.-})(.+)$" 49 | unless start 50 | start, text = "", line.text 51 | 52 | procd = {} 53 | idx_offset = #start 54 | 55 | for part in string.gmatch text.."\\N", "(.-)\\N" 56 | part = proc part, idx_offset 57 | table.insert procd, part 58 | -- adjust for processed output + newline 59 | idx_offset += #part + 2 60 | 61 | line.text = start .. table.concat procd, "\\N" 62 | sub[act] = line 63 | 64 | align_start = (sub, _sel, act) -> 65 | main sub, act, pattern_replacer proc_align_start 66 | 67 | align_end = (sub, _sel, act) -> 68 | main sub, act, pattern_replacer proc_align_end 69 | 70 | align_by_cursor = (sub, _sel, act) -> 71 | main sub, act, cursor_proc 72 | 73 | macros = { 74 | {script_name.."/Align start", "Keep start of line aligned", align_start}, 75 | {script_name.."/Align end", "Keep end of line aligned", align_end} 76 | } 77 | if aegisub.gui 78 | table.insert macros, {script_name.."/By cursor", "Determine sections and alignment from selection", align_by_cursor} 79 | 80 | if havedc 81 | dep\registerMacros macros 82 | else 83 | for macro in *macros 84 | aegisub.register_macro unpack macro 85 | -------------------------------------------------------------------------------- /Aegisub/automation/autoload/petzku.SplitTimer.moon: -------------------------------------------------------------------------------- 1 | -- Copyright (c) 2021 petzku 2 | 3 | export script_name = "SplitTimer" 4 | export script_description = "Split lines in selection into shorter segments, preserving any transforms" 5 | export script_author = "petzku" 6 | export script_namespace = "petzku.SplitTimer" 7 | export script_version = "1.2.2" 8 | 9 | havedc, DependencyControl = pcall require, "l0.DependencyControl" 10 | local dep, util, petzku 11 | if havedc 12 | dep = DependencyControl{ 13 | feed: "https://raw.githubusercontent.com/petzku/Aegisub-Scripts/stable/DependencyControl.json", 14 | { 15 | 'aegisub.util', 16 | {'petzku.util', version: '0.4.2', url: "https://github.com/petzku/Aegisub-Scripts", 17 | feed: "https://raw.githubusercontent.com/petzku/Aegisub-Scripts/stable/DependencyControl.json"}, 18 | } 19 | } 20 | util, petzku = dep\requireModules! 21 | else 22 | util = require 'aegisub.util' 23 | petzku = require 'petzku.util' 24 | 25 | 26 | -- Most matroska demuxers look back up to 10 seconds for events on seek 27 | -- Therefore, any events shorter than 10 seconds are guaranteed to be found 28 | MAX_DURATION = 10000 -- milliseconds 29 | 30 | FRAME_GUI = { 31 | help: { 32 | class: 'label', label: "How many frames per segment: ", 33 | x: 0, y: 0 34 | }, 35 | frames: { 36 | class: 'intedit', value: 1, name: 'frames' 37 | x: 1, y: 0 38 | } 39 | } 40 | 41 | 42 | calc_end_frames = (frames) -> (start) -> 43 | temp = aegisub.ms_from_frame frames + aegisub.frame_from_ms start 44 | -- if no vid loaded, assume 23.976 45 | temp or start + frames * 24000/1001 46 | 47 | calc_end_time = (start) -> 48 | temp = aegisub.ms_from_frame aegisub.frame_from_ms start + MAX_DURATION 49 | -- nil if no video loaded 50 | temp or start + MAX_DURATION 51 | 52 | split = (subs, sel, calc) -> 53 | for si = #sel,1,-1 54 | i = sel[si] 55 | line = subs[i] 56 | 57 | -- skip iteration if line is at most one split long 58 | unless line.end_time > calc line.start_time, line.end_time 59 | continue 60 | 61 | k = 1 62 | st = line.start_time 63 | et = math.min line.end_time, calc line.start_time, line.end_time 64 | while st < line.end_time 65 | new = util.copy line 66 | new = petzku.transform.retime new, line.start_time - st 67 | new.start_time = st 68 | new.end_time = et 69 | subs.insert i+k, new 70 | 71 | st = et 72 | et = math.min line.end_time, calc st, line.end_time 73 | k += 1 74 | subs.delete i 75 | 76 | split_time = (subs, sel) -> 77 | split subs, sel, calc_end_time 78 | 79 | split_frames = (subs, sel) -> 80 | btn, res = aegisub.dialog.display FRAME_GUI 81 | if btn 82 | split subs, sel, calc_end_frames res.frames 83 | 84 | split_video = (subs, sel) -> 85 | time = aegisub.ms_from_frame aegisub.project_properties!.video_position 86 | calc = (st, et) -> if st < time then time else et 87 | split subs, sel, calc 88 | 89 | macros = { 90 | {'10 second chunks', "Split line into 10-second-long chunks, preserving transforms", split_time}, 91 | {'On video frame', "Split line on current video frame, preserving transforms", split_video}, 92 | {'N frames...', "Split line into N-frame-long events, preserving transforms (opens GUI)", split_frames} 93 | } 94 | 95 | if havedc 96 | dep\registerMacros macros 97 | else 98 | for macro in *macros 99 | name, desc, fun, cond = unpack macro 100 | aegisub.register_macro script_name..'/'..name, desc, fun, cond 101 | -------------------------------------------------------------------------------- /Aegisub/automation/autoload/petzku.ToggleTemplates.moon: -------------------------------------------------------------------------------- 1 | export script_name = "Toggle Templates" 2 | export script_description = "Toggle disabled state for selected auto4 ktemplate components" 3 | export script_author = "petzku" 4 | export script_version = "0.3.2" 5 | export script_namespace = "petzku.ToggleTemplates" 6 | 7 | is_component = (line) -> 8 | return false unless line.class == "dialogue" and line.comment 9 | cls = line.effect\match "(%l+) " 10 | -- assume anything marked "disabled" is also fair game 11 | return cls == 'disabled' or cls == 'template' or cls == 'code' or cls == 'mixin' or line.effect == 'kara' 12 | 13 | is_disabled = (line) -> 14 | return 'disabled' == line.effect\sub 1, 8 15 | 16 | main = (sub, sel) -> 17 | for i in *sel 18 | line = sub[i] 19 | continue unless is_component line 20 | if is_disabled line 21 | line.effect = line.effect\sub 10 22 | else 23 | line.effect = 'disabled ' .. line.effect 24 | sub[i] = line 25 | 26 | can_run = (sub, sel) -> 27 | for i in *sel 28 | return true if is_component sub[i] 29 | return false 30 | 31 | aegisub.register_macro script_name, script_description, main 32 | -------------------------------------------------------------------------------- /Aegisub/automation/autoload/phos.FitTextInClip.moon: -------------------------------------------------------------------------------- 1 | export script_name = "Fit Text in Clip" 2 | export script_description = "Fit the text inside the rectangular clip" 3 | export script_version = "0.0.4" 4 | export script_author = "PhosCity" 5 | export script_namespace = "phos.FitTextInClip" 6 | 7 | -- Readings 8 | -- https://en.wikipedia.org/wiki/Line_wrap_and_word_wrap 9 | -- https://xxyxyz.org/line-breaking/ 10 | -- https://the-algorithms.com/es/algorithm/text-justification 11 | -- https://leetcode.com/problems/text-justification/solutions/24891/concise-python-solution-10-lines/ 12 | 13 | DependencyControl = require "l0.DependencyControl" 14 | depctrl = DependencyControl{ 15 | feed: "https://raw.githubusercontent.com/PhosCity/Aegisub-Scripts/main/DependencyControl.json", 16 | { 17 | {"a-mo.LineCollection", version: "1.3.0", url: "https: //github.com/TypesettingTools/Aegisub-Motion", 18 | feed: "https: //raw.githubusercontent.com/TypesettingTools/Aegisub-Motion/DepCtrl/DependencyControl.json"}, 19 | {"l0.ASSFoundation", version: "0.5.0", url: "https: //github.com/TypesettingTools/ASSFoundation", 20 | feed: "https: //raw.githubusercontent.com/TypesettingTools/ASSFoundation/master/DependencyControl.json"}, 21 | {"l0.Functional", version: "0.6.0", url: "https://github.com/TypesettingTools/Functional", 22 | feed: "https://raw.githubusercontent.com/TypesettingTools/Functional/master/DependencyControl.json"}, 23 | } 24 | } 25 | LineCollection, ASS, Functional = depctrl\requireModules! 26 | logger = depctrl\getLogger! 27 | { :string } = Functional 28 | 29 | --- Justify the text 30 | ---@param words table list of words to Justify 31 | ---@param maxWidth number width to limit the length of line 32 | ---@param fontObj table font object created by Yutils given a set of values of tags 33 | ---@return string a text seperated by line breakers 34 | textJustification = (words, maxWidth, fontObj) -> 35 | --- Find the width of the text 36 | ---@param text string text whose width must be calculated 37 | ---@return number? width of the text 38 | textWidth = (text) -> 39 | extents = fontObj.text_extents text 40 | tonumber(extents.width) 41 | 42 | result, currentLine, width = {}, {}, 0 43 | spaceWidth = textWidth(" ") 44 | for word in *words 45 | if width + textWidth(word) > maxWidth 46 | for i = 0, math.floor((maxWidth - width)/spaceWidth) - 1 47 | position = i % ( math.max(1, #currentLine - 1) ) 48 | currentLine[position + 1] ..= " " 49 | table.insert result, table.concat(currentLine, " ") 50 | currentLine, width = {}, 0 51 | table.insert currentLine, word 52 | currText = table.concat(currentLine, " ") 53 | width = textWidth(currText) 54 | table.insert result, table.concat(currentLine, " ") 55 | 56 | return table.concat(result, "\\N") 57 | 58 | 59 | --- Main processing function 60 | ---@param sub table subtitle object 61 | ---@param sel table selected lines 62 | main = (sub, sel) -> 63 | lines = LineCollection sub, sel 64 | return if #lines.lines == 0 65 | 66 | lines\runCallback (_, line) -> 67 | aegisub.cancel! if aegisub.progress.is_cancelled! 68 | data = ASS\parse line 69 | 70 | if data\getSectionCount(ASS.Section.Tag) > 1 or data\getSectionCount(ASS.Section.Drawing) > 0 or data\getSectionCount(ASS.Section.Text) == 0 71 | logger\warn "There must be a single text block in the line. Exiting." 72 | return 73 | 74 | clip = data\getTags "clip_rect" 75 | if #clip == 0 76 | logger\warn "Add a rectangular clip in the line fist!" 77 | return 78 | x1, _, x2, _ = clip[1]\getTagParams! 79 | clipWidth = x2 - x1 80 | 81 | effTags = (data\getEffectiveTags -1, true, true, false).tags 82 | if effTags.align\getTagParams! != 7 83 | logger\warn "Please use \\an7 in the line." 84 | return 85 | 86 | data\callback ((section) -> 87 | fontObj = section\getYutilsFont! 88 | text = section\replace("\\N", " ")\replace("%s+", " ")\getString! 89 | words = string.split text, " " 90 | result = textJustification(words, clipWidth, fontObj) 91 | section\set result 92 | ), ASS.Section.Text 93 | data\removeTags "clip_rect" 94 | data\commit! 95 | lines\replaceLines! 96 | 97 | depctrl\registerMacro main 98 | -------------------------------------------------------------------------------- /Aegisub/automation/include/BM/BadMutex.lua: -------------------------------------------------------------------------------- 1 | local ffi = require("ffi") 2 | local requireffi = require("requireffi.requireffi") 3 | ffi.cdef([[void lock( void ); 4 | bool try_lock( void ); 5 | void unlock( void ); 6 | unsigned int version( void ); 7 | ]]) 8 | local BM, loadedLibraryPath = requireffi("BM.BadMutex.BadMutex") 9 | local BMVersion = 0x000100 10 | local libVer = BM.version() 11 | if libVer < BMVersion or math.floor(libVer / 65536 % 256) > math.floor(BMVersion / 65536 % 256) then 12 | error("Library version mismatch. Wanted " .. tostring(BMVersion) .. ", got " .. tostring(libVer) .. ".") 13 | end 14 | local BadMutex 15 | BadMutex = { 16 | lock = function() 17 | return BM.lock() 18 | end, 19 | tryLock = function() 20 | return BM.try_lock() 21 | end, 22 | unlock = function() 23 | return BM.unlock() 24 | end, 25 | version = 0x000103, 26 | __depCtrlInit = function(DependencyControl) 27 | BadMutex.version = DependencyControl({ 28 | name = "BadMutex", 29 | version = BadMutex.version, 30 | description = "A global mutex.", 31 | author = "torque", 32 | url = "https://github.com/TypesettingTools/ffi-experiments", 33 | moduleName = "BM.BadMutex", 34 | feed = "https://raw.githubusercontent.com/TypesettingTools/ffi-experiments/master/DependencyControl.json" 35 | }) 36 | end, 37 | loadedLibraryPath = loadedLibraryPath 38 | } 39 | return BadMutex 40 | -------------------------------------------------------------------------------- /Aegisub/automation/include/BM/BadMutex/BadMutex.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LightArrowsEXE/dotfiles/176453ed77d9f8c59539df8e71b3171ef6e73b3d/Aegisub/automation/include/BM/BadMutex/BadMutex.dll -------------------------------------------------------------------------------- /Aegisub/automation/include/DM/DownloadManager/DownloadManager.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LightArrowsEXE/dotfiles/176453ed77d9f8c59539df8e71b3171ef6e73b3d/Aegisub/automation/include/DM/DownloadManager/DownloadManager.dll -------------------------------------------------------------------------------- /Aegisub/automation/include/ILL/ILL.moon: -------------------------------------------------------------------------------- 1 | module_version = "1.6.5" 2 | 3 | haveDepCtrl, DependencyControl = pcall require, "l0.DependencyControl" 4 | 5 | local depctrl 6 | if haveDepCtrl 7 | depctrl = DependencyControl { 8 | name: "ILL" 9 | version: module_version 10 | description: "Module that eases the creation of macros with a focus on handling shapes." 11 | author: "ILLTeam" 12 | moduleName: "ILL.ILL" 13 | url: "https://github.com/TypesettingTools/ILL-Aegisub-Scripts/" 14 | feed: "https://raw.githubusercontent.com/TypesettingTools/ILL-Aegisub-Scripts/main/DependencyControl.json" 15 | { 16 | {"ffi", "json"} 17 | { 18 | "clipper2.clipper2" 19 | version: "1.4.0" 20 | url: "https://github.com/TypesettingTools/ILL-Aegisub-Scripts/" 21 | feed: "https://raw.githubusercontent.com/TypesettingTools/ILL-Aegisub-Scripts/main/DependencyControl.json" 22 | } 23 | } 24 | } 25 | 26 | import Aegi from require "ILL.ILL.Aegi" 27 | import Config from require "ILL.ILL.Config" 28 | import Math from require "ILL.ILL.Math" 29 | import Table from require "ILL.ILL.Table" 30 | import Util from require "ILL.ILL.Util" 31 | import UTF8 from require "ILL.ILL.UTF8" 32 | import Ass from require "ILL.ILL.Ass.Ass" 33 | import Curve from require "ILL.ILL.Ass.Shape.Curve" 34 | import Path from require "ILL.ILL.Ass.Shape.Path" 35 | import Point from require "ILL.ILL.Ass.Shape.Point" 36 | import Segment from require "ILL.ILL.Ass.Shape.Segment" 37 | import Line from require "ILL.ILL.Ass.Line" 38 | import Tag from require "ILL.ILL.Ass.Text.Tag" 39 | import Tags from require "ILL.ILL.Ass.Text.Tags" 40 | import Text from require "ILL.ILL.Ass.Text.Text" 41 | import Font from require "ILL.ILL.Font.Font" 42 | 43 | modules = { 44 | :Aegi, :Config, :Math, :Table, :Util, :UTF8 45 | :Curve, :Path, :Point, :Segment 46 | :Tag, :Tags, :Text 47 | :Ass, :Line 48 | :Font 49 | version: module_version 50 | } 51 | 52 | if haveDepCtrl 53 | depctrl\register modules 54 | else 55 | modules -------------------------------------------------------------------------------- /Aegisub/automation/include/ILL/ILL/Aegi.moon: -------------------------------------------------------------------------------- 1 | import Table from require "ILL.ILL.Table" 2 | import Config from require "ILL.ILL.Config" 3 | 4 | -- https://aegisub.org/docs/latest/automation/lua/progress_reporting/ 5 | class Aegi 6 | 7 | -- use loaded frame rate data to convert an absolute time given in milliseconds into a frame number 8 | ffm: (ms) -> aegisub.frame_from_ms ms 9 | 10 | -- use loaded frame rate data to convert a frame number of the video into an absolute time in milliseconds 11 | mff: (frame) -> aegisub.ms_from_frame frame 12 | 13 | -- the title that will appear on the progress screen 14 | progressTitle: (title) -> 15 | aegisub.progress.title title 16 | return 17 | 18 | -- the subtitle that will appear on the progress screen 19 | progressTask: (task = "") -> 20 | aegisub.progress.task task 21 | return 22 | 23 | -- the processing bar that ranges from 0 to 100 24 | progressSet: (i, n) -> 25 | aegisub.progress.set 100 * i / n 26 | return 27 | 28 | -- resets all progress 29 | progressReset: -> 30 | aegisub.progress.set 0 31 | aegisub.progress.task "" 32 | return 33 | 34 | -- checks if processing has been canceled and cancels 35 | progressCancelled: -> 36 | if aegisub.progress.is_cancelled! 37 | aegisub.cancel! 38 | return 39 | 40 | -- cancels current processing 41 | progressCancel: (msg) -> 42 | if msg 43 | aegisub.log msg 44 | aegisub.cancel! 45 | return 46 | 47 | -- debugging support 48 | debug: (lvl = 0, msg) -> 49 | aegisub.debug.out lvl, msg 50 | return 51 | 52 | -- interface display 53 | display: (interface, ...) -> 54 | args = {...} 55 | config = Config interface 56 | if extra = args[3] 57 | if script_namespace 58 | config\setJsonPath script_namespace .. extra 59 | else 60 | error "Expected script_namespace" 61 | button, elements = aegisub.dialog.display config\getInterface!, ... 62 | if not args[4] and button != "Cancel" 63 | config\save elements 64 | return button, elements, config 65 | 66 | -- prints any value in the Aegisub log 67 | log: (value) -> 68 | if type(value) == "string" or type(value) == "number" 69 | aegisub.log tostring(value) .. "\n" 70 | else 71 | aegisub.log Table.view value 72 | return 73 | 74 | {:Aegi} -------------------------------------------------------------------------------- /Aegisub/automation/include/ILL/ILL/Ass/Shape/Segment.moon: -------------------------------------------------------------------------------- 1 | import Math from require "ILL.ILL.Math" 2 | import Point from require "ILL.ILL.Ass.Shape.Point" 3 | 4 | class Segment 5 | 6 | -- create a new Segment object 7 | new: (@a = Point!, @b = Point!) => 8 | 9 | -- gets the value of X given a time on a segment 10 | getXatTime: (t) => (1 - t) * @a.x + t * @b.x 11 | 12 | -- gets the value of Y given a time on a segment 13 | getYatTime: (t) => (1 - t) * @a.y + t * @b.y 14 | 15 | -- gets the value of Point given a time on a segment 16 | getPTatTime: (t) => 17 | x = @getXatTime t 18 | y = @getYatTime t 19 | return Point x, y 20 | 21 | -- flattens the segment 22 | flatten: (len = @getLength!, reduce = 1) => 23 | len = math.floor len / reduce + 0.5 24 | points = {Point @a.x, @a.y} 25 | for i = 1, len - 1 26 | table.insert points, @getPTatTime i / len 27 | table.insert points, Point @b.x, @b.y 28 | return points 29 | 30 | -- splits the segment in two 31 | split: (t = 0.5) => 32 | {:a, :b} = @ 33 | c = a\lerp b, t 34 | return { 35 | Segment a, c 36 | Segment c, b 37 | } 38 | 39 | -- gets the normalized tangent given a time on a segment 40 | getNormalized: (t, inverse) => 41 | t = Math.clamp t, 0, 1 42 | p = @getPTatTime t 43 | d = Point! 44 | d.x = @b.x - p.x 45 | d.y = @b.y - p.y 46 | with d 47 | if inverse 48 | .x, .y = .y, -.x 49 | else 50 | .x, .y = -.y, .x 51 | mag = d\vecMagnitude! 52 | tan = Point d.x / mag, d.y / mag 53 | return tan, p, t 54 | 55 | -- gets the real length of the segment through time 56 | getLength: (t = 1) => t * @a\distance @b 57 | 58 | -- converts a segment to a bezier curve 59 | lineToBezier: => 60 | a = @a\clone! 61 | b = Point (2 * @a.x + @b.x) / 3, (2 * @a.y + @b.y) / 3 62 | c = Point (@a.x + 2 * @b.x) / 3, (@a.y + 2 * @b.y) / 3 63 | d = @b\clone! 64 | a.id, b.id, c.id, d.id = "l", "b", "b", "b" 65 | return a, b, c, d 66 | 67 | reverse: => 68 | a2, b2 = @a\clone!, @b\clone! 69 | @a, @b = b2, a2 70 | 71 | {:Segment} -------------------------------------------------------------------------------- /Aegisub/automation/include/ILL/ILL/Config.moon: -------------------------------------------------------------------------------- 1 | import Util from require "ILL.ILL.Util" 2 | 3 | json = require "json" 4 | 5 | class Config 6 | 7 | getPath: (dir) -> Util.fixPath aegisub.decode_path("?user") .. dir 8 | 9 | getMacroPath: (dir, namespace = script_namespace) -> 10 | if namespace 11 | return "#{Config.getPath dir}#{namespace}" 12 | else 13 | error "Expected script_namespace" 14 | 15 | getElements: (gui) -> 16 | elements = {} 17 | for {:name, :value} in *gui 18 | elements[name] = value if name 19 | return elements 20 | 21 | getElement: (gui, name) -> 22 | if element = Config.getElements[name] 23 | return element 24 | else 25 | error "element not found" 26 | 27 | new: (@interface, @dir = "/config/") => 28 | @setPath! 29 | @setJsonPath! 30 | 31 | setPath: (dir) => @path = Config.getPath dir or @dir 32 | 33 | setJsonPath: (namespace) => @jsonPath = Config.getMacroPath(@dir, namespace) .. ".json" 34 | 35 | reset: => 36 | if Util.fileExist @jsonPath 37 | if jit.os == "Windows" 38 | os.execute "del #{@jsonPath}" 39 | else 40 | os.execute "rm -f #{@jsonPath}" 41 | return true 42 | return false 43 | 44 | save: (elements) => 45 | unless script_version 46 | error "Expected script_version" 47 | elements.__VERSION__ = script_version 48 | unless Util.fileExist @path, true 49 | os.execute "mkdir #{@path}" 50 | success, code = pcall json.encode, elements 51 | if success 52 | file = io.open @jsonPath, "w" 53 | file\write code 54 | file\close! 55 | else 56 | error "could not save the config", 2 57 | return code 58 | 59 | getInterface: => 60 | {:interface} = @ 61 | if file = io.open @jsonPath, "r" 62 | if data = file\read "*a" 63 | success, obj = pcall json.decode, data 64 | if success 65 | file\close! 66 | unless script_version 67 | error "Expected script_version" 68 | if obj.__VERSION__ == script_version 69 | for objName, objValue in pairs obj 70 | for i = 1, #interface 71 | cfg = interface[i] 72 | if cfg.name == objName 73 | cfg.value = objValue 74 | return interface 75 | else 76 | error "could not get the config", 2 77 | else 78 | error "could not get file data", 2 79 | @save Config.getElements interface 80 | @getInterface interface 81 | 82 | {:Config} -------------------------------------------------------------------------------- /Aegisub/automation/include/ILL/ILL/Font/Font.moon: -------------------------------------------------------------------------------- 1 | -- Copyright (c) 2014, Christoph "Youka" Spanknebel 2 | 3 | -- Permission is hereby granted, free of charge, to any person obtaining a copy 4 | -- of this software and associated documentation files (the "Software"), to deal 5 | -- in the Software without restriction, including without limitation the rights 6 | -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | -- copies of the Software, and to permit persons to whom the Software is 8 | -- furnished to do so, subject to the following conditions: 9 | 10 | -- The above copyright notice and this permission notice shall be included in 11 | -- all copies or substantial portions of the Software. 12 | 13 | -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | -- THE SOFTWARE. 20 | 21 | -- Font scale values for increased size & later downscaling to produce floating point coordinates 22 | export FONT_LF_FACESIZE = 32 23 | export FONT_UPSCALE = 64 24 | export FONT_DOWNSCALE = 1 / FONT_UPSCALE 25 | export IS_UNIX = jit.os != "Windows" 26 | 27 | unless IS_UNIX 28 | -- if the operating system is windows 29 | import WindowsGDI from require "ILL.ILL.Font.Win" 30 | return {Font: WindowsGDI} 31 | 32 | -- if the operating system is unix 33 | import FreeType from require "ILL.ILL.Font.Unx" 34 | return {Font: FreeType} -------------------------------------------------------------------------------- /Aegisub/automation/include/ILL/ILL/Font/Init.moon: -------------------------------------------------------------------------------- 1 | class Init 2 | 3 | new: (data) => 4 | { 5 | fontname: @family 6 | bold: @bold 7 | italic: @italic 8 | underline: @underline 9 | strikeout: @strikeout 10 | fontsize: @size 11 | scale_x: @xscale 12 | scale_y: @yscale 13 | spacing: @hspace 14 | } = data 15 | 16 | -- limits the font size to 250 17 | if @size > 250 18 | factor = (@size - 100) / 100 19 | @xscale += @xscale * factor 20 | @yscale += @yscale * factor 21 | @size = 100 22 | 23 | -- Reescale x and y 24 | @xscale /= 100 25 | @yscale /= 100 26 | 27 | @init! 28 | 29 | {:Init} -------------------------------------------------------------------------------- /Aegisub/automation/include/ILL/ILL/Table.moon: -------------------------------------------------------------------------------- 1 | {:insert, :remove} = table 2 | 3 | class Table 4 | 5 | -- checks if the table is empty 6 | isEmpty: (tb) -> next(tb) == nil 7 | 8 | -- makes a shallow copy of the table 9 | shallowcopy: (tb) -> 10 | shallowcopy = (t) -> 11 | copy = {} 12 | if type(t) == "table" 13 | for k, v in pairs t 14 | copy[k] = v 15 | else 16 | copy = t 17 | return copy 18 | return shallowcopy tb 19 | 20 | -- makes a deep copy of the table 21 | deepcopy: (tb) -> 22 | deepcopy = (t, copies = {}) -> 23 | copy = {} 24 | if type(t) == "table" 25 | if copies[t] 26 | copy = copies[t] 27 | else 28 | copies[t] = copy 29 | for k, v in next, t, nil 30 | copy[deepcopy k, copies] = deepcopy v, copies 31 | setmetatable copy, deepcopy getmetatable(t), copies 32 | else 33 | copy = t 34 | return copy 35 | return deepcopy tb 36 | 37 | -- makes a copy of the table 38 | copy: (tb, deepcopy = true) -> deepcopy and Table.deepcopy(tb) or Table.shallowcopy(tb) 39 | 40 | -- inserts one or more values at the end of an array 41 | push: (tb, ...) -> 42 | arguments = {...} 43 | for i = 1, #arguments 44 | insert tb, arguments[i] 45 | return #arguments 46 | 47 | -- removes the last value from the array 48 | pop: (tb) -> remove tb 49 | 50 | -- reverses the array values 51 | reverse: (tb) -> [tb[#tb + 1 - i] for i = 1, #tb] 52 | 53 | -- removes the first value from the array 54 | shift: (tb) -> remove tb, 1 55 | 56 | -- inserts one or more values at the beginning of an array 57 | unshift: (tb, ...) -> 58 | arguments = {...} 59 | for i = #arguments, 1, -1 60 | insert tb, 1, arguments[i] 61 | return #tb 62 | 63 | -- slices the array according to the given arguments 64 | slice: (tb, f, l, s) -> [tb[i] for i = f or 1, l or #tb, s or 1] 65 | 66 | -- changes the contents of a array, adding new elements while removing old ones 67 | splice: (tb, start, delete, ...) -> 68 | arguments, removes, t_len = {...}, {}, #tb 69 | n_args, i_args = #arguments, 1 70 | start = start < 1 and 1 or start 71 | delete = delete < 0 and 0 or delete 72 | if start > t_len 73 | start = t_len + 1 74 | delete = 0 75 | delete = start + delete - 1 > t_len and t_len - start + 1 or delete 76 | for pos = start, start + math.min(delete, n_args) - 1 77 | insert removes, tb[pos] 78 | tb[pos] = arguments[i_args] 79 | i_args += 1 80 | i_args -= 1 81 | for i = 1, delete - n_args 82 | insert removes, remove tb, start + i_args 83 | for i = n_args - delete, 1, -1 84 | insert tb, start + delete, arguments[i_args + i] 85 | return removes 86 | 87 | -- returns the contents of a table to a string 88 | view: (tb, table_name = "table_unnamed", indent = "") -> 89 | cart, autoref = "", "" 90 | basicSerialize = (o) -> 91 | so = tostring o 92 | if type(o) == "function" 93 | info = debug.getinfo o, "S" 94 | return string.format "%q", so .. ", C function" if info.what == "C" 95 | string.format "%q, defined in (lines: %s - %s), ubication %s", so, info.linedefined, info.lastlinedefined, info.source 96 | elseif (type(o) == "number") or (type(o) == "boolean") 97 | return so 98 | string.format "%q", so 99 | addtocart = (value, table_name, indent, saved = {}, field = table_name) -> 100 | cart ..= indent .. field 101 | if type(value) != "table" 102 | cart ..= " = " .. basicSerialize(value) .. ";\n" 103 | else 104 | if saved[value] 105 | cart ..= " = {}; -- #{saved[value]}(self reference)\n" 106 | autoref ..= "#{table_name} = #{saved[value]};\n" 107 | else 108 | saved[value] = table_name 109 | if Table.isEmpty value 110 | cart ..= " = {};\n" 111 | else 112 | cart ..= " = {\n" 113 | for k, v in pairs value 114 | k = basicSerialize k 115 | fname = "#{table_name}[ #{k} ]" 116 | field = "[ #{k} ]" 117 | addtocart v, fname, indent .. " ", saved, field 118 | cart = "#{cart}#{indent}};\n" 119 | return "#{table_name} = #{basicSerialize tb}" if type(tb) != "table" 120 | addtocart tb, table_name, indent 121 | return cart .. autoref 122 | 123 | {:Table} -------------------------------------------------------------------------------- /Aegisub/automation/include/ILL/ILL/UTF8.moon: -------------------------------------------------------------------------------- 1 | -- code taken from the Yutils lib 2 | -- https://github.com/TypesettingTools/Yutils/blob/91a4ac771b08ecffdcc8c084592286961d99c5f2/src/Yutils.lua#L587 3 | 4 | class UTF8 5 | 6 | new: (@s) => 7 | 8 | charrange: (c, i) -> 9 | byte = c\byte i 10 | return not byte and 0 or byte < 192 and 1 or byte < 224 and 2 or byte < 240 and 3 or byte < 248 and 4 or byte < 252 and 5 or 6 11 | 12 | charcodepoint: (c) -> 13 | -- Basic case, ASCII 14 | b = c\byte 1 15 | return b if b < 128 16 | -- Use a naive decoding algorithm, and assume input is valid 17 | local res, w 18 | if b < 224 then 19 | -- prefix byte is 110xxxxx 20 | res = b - 192 21 | w = 2 22 | elseif b < 240 then 23 | -- prefix byte is 11100000 24 | res = b - 224 25 | w = 3 26 | else 27 | res = b - 240 28 | w = 4 29 | for i = 2, w 30 | res = res * 64 + c\byte(i) - 128 31 | return res 32 | 33 | chars: => 34 | {:s} = @ 35 | ci, sp, len = 0, 1, #s 36 | -> 37 | if sp <= len 38 | cp = sp 39 | sp += UTF8.charrange s, sp 40 | if sp - 1 <= len 41 | ci += 1 42 | return ci, s\sub cp, sp - 1 43 | 44 | len: => 45 | n = 0 46 | for ci in @chars! 47 | n += 1 48 | return n 49 | 50 | {:UTF8} -------------------------------------------------------------------------------- /Aegisub/automation/include/ILL/IMG/bitmap/bitmap.moon: -------------------------------------------------------------------------------- 1 | ffi = require "ffi" 2 | require "ILL.IMG.buffer.buffer" 3 | 4 | bmp_header = { 5 | offset: 0 6 | pixel_offset: 10 7 | width: 18 8 | height: 22 9 | bpp: 28 10 | compression: 30 11 | } 12 | 13 | -- https://github.com/max1220/lua-bitmap 14 | class LIBBMP 15 | 16 | new: (@filename = filename) => 17 | file = io.open @filename, "rb" 18 | 19 | unless file 20 | error "Can't open input file for reading: #{@filename}" 21 | 22 | raw = file\read "*a" 23 | assert raw and raw != "", "Can't read input file: #{@filename}" 24 | 25 | file\close! 26 | 27 | @raw = {} 28 | for i = 1, #raw 29 | @raw[i - 1] = raw\sub(i, i)\byte! 30 | 31 | -- reading 8/16/32-bit little-endian integer values from a string 32 | -- read uint8 33 | read: (offset) => 34 | offset = tonumber offset 35 | assert offset 36 | value = @raw[math.floor(offset)] 37 | assert value 38 | return value 39 | 40 | -- read uint16 41 | read_word: (offset) => @read(offset + 1) * 0x100 + @read offset 42 | 43 | -- read uint32 44 | read_dword: (offset) => @read(offset + 3) * 0x1000000 + @read(offset + 2) * 0x10000 + @read(offset + 1) * 0x100 + @read offset 45 | 46 | -- read int32 47 | read_long: (offset) => 48 | value = @read_dword offset 49 | if value >= 0x8000000 50 | value = -(value - 0x80000000) 51 | return value 52 | 53 | decode: => 54 | -- check the bitmap header 55 | unless @read_word(bmp_header.offset) == 0x4D42 56 | error "Bitmap magic header not found" 57 | 58 | compression = @read_dword bmp_header.compression 59 | if compression != 0 60 | error "Only uncompressed bitmaps supported. Is: #{compression}" 61 | 62 | -- get bits per pixel from the bitmap header 63 | -- this library only supports 24bpp and 32bpp pixel formats! 64 | @bit_depth = @read_word bmp_header.bpp 65 | unless @bit_depth == 24 or @bit_depth == 32 66 | error "Only 24bpp/32bpp bitmaps supported. Is: #{@bit_depth}" 67 | 68 | -- get other required info from the bitmap header 69 | @pxOffset = @read_dword bmp_header.pixel_offset 70 | @width = @read_long bmp_header.width 71 | @height = @read_long bmp_header.height 72 | 73 | -- if height is < 0, the image data is in topdown format 74 | @topdown = true 75 | if @height < 0 76 | @topdown, @height = false, -@height 77 | 78 | @getPixel = (x, y) => 79 | if (x < 0) or (x >= @width) or (y < 0) or (y >= @height) 80 | error "Out of bounds" 81 | 82 | -- calculate byte offset in data 83 | bpp = @bit_depth / 8 84 | lineW = math.ceil(@width / 4) * 4 85 | index = @pxOffset + y * lineW * bpp + x * bpp 86 | if @topdown 87 | index = @pxOffset + (@height - y - 1) * bpp * lineW + x * bpp 88 | 89 | b = @read index 90 | g = @read index + 1 91 | r = @read index + 2 92 | a = bpp < 4 and 255 or @read index + 3 93 | return r, g, b, a 94 | 95 | @getData = => 96 | @data = ffi.new "color_RGBA[?]", @width * @height 97 | 98 | for y = 0, @height - 1 99 | for x = 0, @width - 1 100 | r, g, b, a = @getPixel x, y 101 | with @data[y * @width + x] 102 | .r = r 103 | .g = g 104 | .b = b 105 | .a = a 106 | 107 | return @data 108 | 109 | return @ 110 | 111 | {:LIBBMP} -------------------------------------------------------------------------------- /Aegisub/automation/include/ILL/IMG/giflib/giflib.moon: -------------------------------------------------------------------------------- 1 | ffi = require "ffi" 2 | requireffi = require "requireffi.requireffi" 3 | 4 | has_loaded, GIF = pcall requireffi, "ILL.IMG.giflib.giflib.giflib" 5 | 6 | ffi.cdef [[ 7 | typedef unsigned char GifByteType; 8 | typedef int GifWord; 9 | typedef struct GifColorType { 10 | GifByteType Red, Green, Blue; 11 | } GifColorType; 12 | typedef struct ColorMapObject { 13 | int ColorCount; 14 | int BitsPerPixel; 15 | _Bool SortFlag; 16 | GifColorType *Colors; 17 | } ColorMapObject; 18 | typedef struct GifImageDesc { 19 | GifWord Left, Top, Width, Height; 20 | _Bool Interlace; 21 | ColorMapObject *ColorMap; 22 | } GifImageDesc; 23 | typedef struct ExtensionBlock { 24 | int ByteCount; 25 | GifByteType *Bytes; 26 | int Function; 27 | } ExtensionBlock; 28 | typedef struct SavedImage { 29 | GifImageDesc ImageDesc; 30 | GifByteType *RasterBits; 31 | int ExtensionBlockCount; 32 | ExtensionBlock *ExtensionBlocks; 33 | } SavedImage; 34 | typedef struct GifFileType { 35 | GifWord SWidth, SHeight; 36 | GifWord SColorResolution; 37 | GifWord SBackGroundColor; 38 | GifByteType AspectByte; 39 | ColorMapObject *SColorMap; 40 | int ImageCount; 41 | GifImageDesc Image; 42 | SavedImage *SavedImages; 43 | int ExtensionBlockCount; 44 | ExtensionBlock *ExtensionBlocks; 45 | int Error; 46 | void *UserData; 47 | void *Private; 48 | } GifFileType; 49 | typedef int (*GifInputFunc) (GifFileType *, GifByteType *, int); 50 | typedef int (*GifOutputFunc) (GifFileType *, const GifByteType *, int); 51 | typedef struct GraphicsControlBlock { 52 | int DisposalMode; 53 | _Bool UserInputFlag; 54 | int DelayTime; 55 | int TransparentColor; 56 | } GraphicsControlBlock; 57 | GifFileType *DGifOpenFileName(const char *GifFileName, int *Error); 58 | int DGifSlurp(GifFileType * GifFile); 59 | GifFileType *DGifOpen(void *userPtr, GifInputFunc readFunc, int *Error); 60 | int DGifCloseFile(GifFileType * GifFile); 61 | char *GifErrorString(int ErrorCode); 62 | int DGifSavedExtensionToGCB(GifFileType *GifFile, int ImageIndex, GraphicsControlBlock *GCB); 63 | ]] 64 | 65 | -- https://luapower.com/giflib 66 | class LIBGIF 67 | 68 | new: (@filename = filename) => 69 | 70 | read: => 71 | open = (err) -> GIF.DGifOpenFileName @filename, err 72 | 73 | err = ffi.new "int[1]" 74 | @file = open(err) or nil 75 | 76 | unless @file 77 | error ffi.string GIF.GifErrorString err[0] 78 | 79 | return @ 80 | 81 | close: => ffi.C.free(@file) if GIF.DGifCloseFile(@file) == 0 82 | 83 | decode: (transparent = true) => 84 | @read! 85 | 86 | check = -> 87 | res = GIF.DGifSlurp @file 88 | if res != 0 89 | return 90 | error ffi.string GIF.GifErrorString @file.Error 91 | 92 | check! 93 | @frames = {} 94 | @width = @file.SWidth 95 | @height = @file.SHeight 96 | 97 | gcb = ffi.new "GraphicsControlBlock" 98 | for i = 0, @file.ImageCount - 1 99 | si = @file.SavedImages[i] 100 | 101 | local delayMs, tColorK 102 | if GIF.DGifSavedExtensionToGCB(@file, i, gcb) == 1 103 | delayMs = gcb.DelayTime * 10 104 | tColorK = gcb.TransparentColor 105 | 106 | width, height = si.ImageDesc.Width, si.ImageDesc.Height 107 | colorMap = si.ImageDesc.ColorMap != nil and si.ImageDesc.ColorMap or @file.SColorMap 108 | 109 | length = width * height 110 | data = ffi.new "color_RGBA[?]", length 111 | for j = 0, length - 1 112 | k = si.RasterBits[j] 113 | assert k < colorMap.ColorCount 114 | 115 | with data[j] 116 | if k == tColorK and transparent 117 | .b = 0 118 | .g = 0 119 | .r = 0 120 | .a = 0 121 | else 122 | .b = colorMap.Colors[k].Blue 123 | .g = colorMap.Colors[k].Green 124 | .r = colorMap.Colors[k].Red 125 | .a = 0xff 126 | 127 | table.insert @frames, {:data, :width, :height, :delayMs, x: si.ImageDesc.Left, y: si.ImageDesc.Top, getData: => data} 128 | 129 | @close! 130 | 131 | return @ 132 | 133 | {:LIBGIF} -------------------------------------------------------------------------------- /Aegisub/automation/include/ILL/IMG/giflib/giflib/giflib.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LightArrowsEXE/dotfiles/176453ed77d9f8c59539df8e71b3171ef6e73b3d/Aegisub/automation/include/ILL/IMG/giflib/giflib/giflib.dll -------------------------------------------------------------------------------- /Aegisub/automation/include/ILL/IMG/lodepng/lodepng.moon: -------------------------------------------------------------------------------- 1 | ffi = require "ffi" 2 | requireffi = require "requireffi.requireffi" 3 | bff = require "ILL.IMG.buffer.buffer" 4 | 5 | has_loaded, PNG = pcall requireffi, "ILL.IMG.lodepng.lodepng.lodepng" 6 | 7 | ffi.cdef [[ 8 | typedef enum { 9 | LCT_GREY = 0, 10 | LCT_RGB = 2, 11 | LCT_PALETTE = 3, 12 | LCT_GREY_ALPHA = 4, 13 | LCT_RGBA = 6, 14 | } LodePNGColorType; 15 | const char *LODEPNG_VERSION_STRING; 16 | const char *lodepng_error_text(unsigned int); 17 | unsigned int lodepng_decode32_file(unsigned char **, unsigned int *, unsigned int *, const char *); 18 | ]] 19 | 20 | -- https://github.com/koreader/koreader-base/tree/master/ffi 21 | class LIBPNG 22 | 23 | new: (@filename = filename) => 24 | 25 | setArguments: => 26 | @rawData = ffi.new "unsigned char*[1]" 27 | @width = ffi.new "int[1]" 28 | @height = ffi.new "int[1]" 29 | 30 | decode: => 31 | @setArguments! 32 | 33 | err = PNG.lodepng_decode32_file @rawData, @width, @height, @filename 34 | assert err == 0, ffi.string PNG.lodepng_error_text err 35 | 36 | buffer = bff.BUFFER @width[0], @height[0], 5, @rawData[0] 37 | buffer\set_allocated 1 38 | 39 | @rawData = buffer 40 | @width = buffer\get_width! 41 | @height = buffer\get_height! 42 | @bit_depth = buffer\get_bpp! 43 | 44 | @getPixel = (x, y) => buffer\get_pixel x, y 45 | 46 | @getData = => 47 | @data = ffi.new "color_RGBA[?]", @width * @height 48 | 49 | for y = 0, @height - 1 50 | for x = 0, @width - 1 51 | i = y * @width + x 52 | with @getPixel(x, y)\get_color_32! 53 | @data[i].r = .r 54 | @data[i].g = .g 55 | @data[i].b = .b 56 | @data[i].a = .alpha 57 | 58 | return @data 59 | 60 | return @ 61 | 62 | {:LIBPNG} -------------------------------------------------------------------------------- /Aegisub/automation/include/ILL/IMG/lodepng/lodepng/lodepng.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LightArrowsEXE/dotfiles/176453ed77d9f8c59539df8e71b3171ef6e73b3d/Aegisub/automation/include/ILL/IMG/lodepng/lodepng/lodepng.dll -------------------------------------------------------------------------------- /Aegisub/automation/include/ILL/IMG/turbojpeg/turbojpeg.moon: -------------------------------------------------------------------------------- 1 | ffi = require "ffi" 2 | requireffi = require "requireffi.requireffi" 3 | bff = require "ILL.IMG.buffer.buffer" 4 | 5 | has_loaded, JPG = pcall requireffi, "ILL.IMG.turbojpeg.turbojpeg.turbojpeg" 6 | 7 | ffi.cdef [[ 8 | typedef void *tjhandle; 9 | typedef enum { 10 | TJPF_RGB = 0, 11 | TJPF_BGR = 1, 12 | TJPF_RGBX = 2, 13 | TJPF_BGRX = 3, 14 | TJPF_XBGR = 4, 15 | TJPF_XRGB = 5, 16 | TJPF_GRAY = 6, 17 | TJPF_RGBA = 7, 18 | TJPF_BGRA = 8, 19 | TJPF_ABGR = 9, 20 | TJPF_ARGB = 10, 21 | TJPF_CMYK = 11, 22 | TJPF_UNKNOWN = -1, 23 | } TJPF; 24 | typedef enum { 25 | TJSAMP_444 = 0, 26 | TJSAMP_422, 27 | TJSAMP_420, 28 | TJSAMP_GRAY, 29 | TJSAMP_440, 30 | TJSAMP_411 31 | } TJPF; 32 | int tjDestroy(tjhandle handle); 33 | tjhandle tjInitDecompress(void); 34 | int tjDecompressHeader3(tjhandle handle, const unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height, int *jpegSubsamp, int *jpegColorspace); 35 | int tjDecompress2(tjhandle handle, const unsigned char *jpegBuf, unsigned long jpegSize, unsigned char *dstBuf, int width, int pitch, int height, int pixelFormat, int flags); 36 | ]] 37 | 38 | -- https://github.com/koreader/koreader-base/tree/master/ffi 39 | class LIBJPG 40 | 41 | new: (@filename = filename) => 42 | 43 | read: => 44 | file = io.open @filename, "rb" 45 | assert file, "Couldn't open JPEG file" 46 | 47 | @rawData = file\read "*a" 48 | file\close! 49 | 50 | setArguments: => 51 | @width = ffi.new "int[1]" 52 | @height = ffi.new "int[1]" 53 | @jpegSubsamp = ffi.new "int[1]" 54 | @colorSpace = ffi.new "int[1]" 55 | 56 | decode: (gray) => 57 | @read! 58 | 59 | handle = JPG.tjInitDecompress! 60 | assert handle, "no TurboJPEG API decompressor handle" 61 | 62 | @setArguments! 63 | 64 | JPG.tjDecompressHeader3 handle, ffi.cast("const unsigned char*", @rawData), #@rawData, @width, @height, @jpegSubsamp, @colorSpace 65 | assert @width[0] > 0 and @height[0] > 0, "Image dimensions" 66 | 67 | buffer = gray and bff.BUFFER(@width[0], @height[0], 1) or bff.BUFFER @width[0], @height[0], 4 68 | format = gray and JPG.TJPF_GRAY or JPG.TJPF_RGB 69 | 70 | err = JPG.tjDecompress2(handle, ffi.cast("unsigned char*", @rawData), #@rawData, ffi.cast("unsigned char*", buffer.data), @width[0], buffer.pitch, @height[0], format, 0) == -1 71 | assert not err, "Decoding error" 72 | 73 | JPG.tjDestroy handle 74 | 75 | @rawData = buffer 76 | @width = buffer\get_width! 77 | @height = buffer\get_height! 78 | @bit_depth = buffer\get_bpp! 79 | 80 | @getPixel = (x, y) => buffer\get_pixel x, y 81 | 82 | @getData = => 83 | @data = ffi.new "color_RGBA[?]", @width * @height 84 | 85 | for y = 0, @height - 1 86 | for x = 0, @width - 1 87 | i = y * @width + x 88 | with @getPixel(x, y)\get_color_32! 89 | @data[i].r = .r 90 | @data[i].g = .g 91 | @data[i].b = .b 92 | @data[i].a = .alpha 93 | 94 | return @data 95 | 96 | return @ 97 | 98 | {:LIBJPG} -------------------------------------------------------------------------------- /Aegisub/automation/include/ILL/IMG/turbojpeg/turbojpeg/turbojpeg.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LightArrowsEXE/dotfiles/176453ed77d9f8c59539df8e71b3171ef6e73b3d/Aegisub/automation/include/ILL/IMG/turbojpeg/turbojpeg/turbojpeg.dll -------------------------------------------------------------------------------- /Aegisub/automation/include/PT/PreciseTimer.lua: -------------------------------------------------------------------------------- 1 | local ffi = require("ffi") 2 | local requireffi = require("requireffi.requireffi") 3 | ffi.cdef([[struct CPT; 4 | typedef struct CPT CPT; 5 | CPT* startTimer( void ); 6 | double getDuration( CPT *pt ); 7 | unsigned int version( void ); 8 | void freeTimer( CPT *pt ); 9 | int usleep(unsigned int); 10 | void Sleep(unsigned long); 11 | ]]) 12 | local PTVersion = 0x000100 13 | local PT, loadedLibraryPath = requireffi("PT.PreciseTimer.PreciseTimer") 14 | local libVer = PT.version() 15 | if libVer < PTVersion or math.floor(libVer / 65536 % 256) > math.floor(PTVersion / 65536 % 256) then 16 | error("Library version mismatch. Wanted " .. tostring(PTVersion) .. ", got " .. tostring(libVer) .. ".") 17 | end 18 | local PreciseTimer 19 | do 20 | local _class_0 21 | local freeTimer 22 | local _base_0 = { 23 | loadedLibraryPath = loadedLibraryPath, 24 | timeElapsed = function(self) 25 | return PT.getDuration(self.timer) 26 | end, 27 | sleep = ffi.os == "Windows" and (function(ms) 28 | if ms == nil then 29 | ms = 100 30 | end 31 | return ffi.C.Sleep(ms) 32 | end) or (function(ms) 33 | if ms == nil then 34 | ms = 100 35 | end 36 | return ffi.C.usleep(ms * 1000) 37 | end) 38 | } 39 | _base_0.__index = _base_0 40 | _class_0 = setmetatable({ 41 | __init = function(self) 42 | self.timer = ffi.gc(PT.startTimer(), freeTimer) 43 | end, 44 | __base = _base_0, 45 | __name = "PreciseTimer" 46 | }, { 47 | __index = _base_0, 48 | __call = function(cls, ...) 49 | local _self_0 = setmetatable({}, _base_0) 50 | cls.__init(_self_0, ...) 51 | return _self_0 52 | end 53 | }) 54 | _base_0.__class = _class_0 55 | local self = _class_0 56 | self.version = 0x000106 57 | self.version_string = "0.1.6" 58 | self.__depCtrlInit = function(DependencyControl) 59 | self.version = DependencyControl({ 60 | name = tostring(self.__name), 61 | version = self.version_string, 62 | description = "Measure times down to the nanosecond. Except not really.", 63 | author = "torque", 64 | url = "https://github.com/TypesettingTools/ffi-experiments", 65 | moduleName = "PT." .. tostring(self.__name), 66 | feed = "https://raw.githubusercontent.com/TypesettingTools/ffi-experiments/master/DependencyControl.json" 67 | }) 68 | end 69 | freeTimer = function(timer) 70 | return PT.freeTimer(timer) 71 | end 72 | PreciseTimer = _class_0 73 | return _class_0 74 | end 75 | -------------------------------------------------------------------------------- /Aegisub/automation/include/PT/PreciseTimer/PreciseTimer.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LightArrowsEXE/dotfiles/176453ed77d9f8c59539df8e71b3171ef6e73b3d/Aegisub/automation/include/PT/PreciseTimer/PreciseTimer.dll -------------------------------------------------------------------------------- /Aegisub/automation/include/SubInspector/Inspector/SubInspector.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LightArrowsEXE/dotfiles/176453ed77d9f8c59539df8e71b3171ef6e73b3d/Aegisub/automation/include/SubInspector/Inspector/SubInspector.dll -------------------------------------------------------------------------------- /Aegisub/automation/include/a-mo/DataWrapper.moon: -------------------------------------------------------------------------------- 1 | local log, DataHandler, ShakeShapeHandler 2 | version = '1.0.2' 3 | 4 | haveDepCtrl, DependencyControl = pcall require, 'l0.DependencyControl' 5 | 6 | if haveDepCtrl 7 | version = DependencyControl { 8 | name: 'DataWrapper', 9 | :version, 10 | description: 'A class for wrapping motion data.', 11 | author: 'torque', 12 | url: 'https://github.com/TypesettingTools/Aegisub-Motion' 13 | moduleName: 'a-mo.DataWrapper' 14 | feed: 'https://raw.githubusercontent.com/TypesettingTools/Aegisub-Motion/DepCtrl/DependencyControl.json' 15 | { 16 | { 'a-mo.Log', version: '1.0.0' } 17 | { 'a-mo.DataHandler', version: '1.0.5' } 18 | { 'a-mo.ShakeShapeHandler', version: '1.0.2' } 19 | } 20 | } 21 | log, DataHandler, ShakeShapeHandler = version\requireModules! 22 | else 23 | log = require 'a-mo.Log' 24 | DataHandler = require 'a-mo.DataHandler' 25 | ShakeShapeHandler = require 'a-mo.ShakeShapeHandler' 26 | 27 | class DataWrapper 28 | @version: version 29 | new: => 30 | 31 | tryDataHandler = ( input ) => 32 | @dataObject = DataHandler input, @scriptResX, @scriptResY 33 | if @dataObject.length 34 | @type = "TSR" 35 | return true 36 | 37 | return false 38 | 39 | tryShakeShape = ( input ) => 40 | @dataObject = ShakeShapeHandler input, @scriptResY 41 | if @dataObject.length 42 | @type = "SRS" 43 | return true 44 | 45 | return false 46 | 47 | bestEffortParsingAttempt: ( input, scriptResX, scriptResY ) => 48 | if "string" != type( input ) 49 | return false 50 | 51 | @scriptResX, @scriptResY = tonumber( scriptResX ), tonumber( scriptResY ) 52 | if input\match '^Adobe After Effects 6.0 Keyframe Data' 53 | if tryDataHandler @, input 54 | return true 55 | 56 | elseif input\match '^shake_shape_data 4.0' 57 | if tryShakeShape @, input 58 | return true 59 | 60 | else 61 | if tryDataHandler @, input 62 | return true 63 | 64 | if tryShakeShape @, input 65 | return true 66 | 67 | return false 68 | 69 | if haveDepCtrl 70 | return version\register DataWrapper 71 | else 72 | return DataWrapper 73 | -------------------------------------------------------------------------------- /Aegisub/automation/include/a-mo/Log.moon: -------------------------------------------------------------------------------- 1 | return { 2 | version: "1.0.0" 3 | 4 | debug: (...) -> 5 | aegisub.log 4, ... 6 | aegisub.log 4, '\n' 7 | 8 | warn: (...) -> 9 | aegisub.log 2, ... 10 | aegisub.log 2, '\n' 11 | 12 | -- I am not sure this is the logical place for this function. 13 | checkCancellation: -> 14 | if aegisub.progress.is_cancelled! 15 | aegisub.cancel! 16 | 17 | dump: ( item, ignore ) -> 18 | level = 2 19 | if "table" != type item 20 | aegisub.log level, tostring item 21 | aegisub.log level, "\n" 22 | return 23 | 24 | count = 1 25 | tablecount = 1 26 | 27 | result = { "{ @#{tablecount}" } 28 | seen = { [item]: tablecount } 29 | recurse = ( item, space ) -> 30 | for key, value in pairs item 31 | unless key == ignore 32 | if "number" == type key 33 | key = "##{key}" 34 | if "table" == type value 35 | unless seen[value] 36 | tablecount += 1 37 | seen[value] = tablecount 38 | count += 1 39 | result[count] = space .. "#{key}: { @#{tablecount}" 40 | recurse value, space .. " " 41 | count += 1 42 | result[count] = space .. "}" 43 | else 44 | count += 1 45 | result[count] = space .. "#{key}: @#{seen[value]}" 46 | 47 | else 48 | if "string" == type value 49 | value = ("%q")\format value 50 | 51 | count += 1 52 | result[count] = space .. "#{key}: #{value}" 53 | 54 | recurse item, " " 55 | 56 | count += 1 57 | result[count] = "}\n" 58 | aegisub.log level, table.concat result, "\n" 59 | 60 | windowError: ( errorMessage ) -> 61 | aegisub.dialog.display { { class: "label", label: errorMessage } }, { "&Close" }, { cancel: "&Close" } 62 | aegisub.cancel! 63 | } 64 | -------------------------------------------------------------------------------- /Aegisub/automation/include/a-mo/Math.moon: -------------------------------------------------------------------------------- 1 | return { 2 | version: "1.0.0" 3 | 4 | round: ( num, idp ) -> 5 | mult = 10^(idp or 0) 6 | math.floor( num * mult + 0.5 ) / mult 7 | 8 | dCos: (a) -> 9 | math.cos math.rad a 10 | 11 | dSin: (a) -> 12 | math.sin math.rad a 13 | 14 | dAtan: (y, x) -> 15 | math.deg math.atan2 y, x 16 | 17 | uuid: -> 18 | ('xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx')\gsub "[xy]", ( char ) -> 19 | ('%x')\format char=="x" and math.random( 0, 15 ) or math.random 8, 11 20 | } 21 | -------------------------------------------------------------------------------- /Aegisub/automation/include/aka/StackTracePlus/init.lua: -------------------------------------------------------------------------------- 1 | -- aka.StackTracePlus 2 | -- Copyright (c) 2010 Ignacio Burgueño 3 | -- 4 | -- Permission is hereby granted, free of charge, to any person obtaining a copy 5 | -- of this software and associated documentation files (the "Software"), to deal 6 | -- in the Software without restriction, including without limitation the rights 7 | -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | -- copies of the Software, and to permit persons to whom the Software is 9 | -- furnished to do so, subject to the following conditions: 10 | -- 11 | -- The above copyright notice and this permission notice shall be included in 12 | -- all copies or substantial portions of the Software. 13 | -- 14 | -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | -- THE SOFTWARE. 21 | 22 | local versioning = {} 23 | 24 | versioning.name = "StackTracePlus" 25 | versioning.description = "Module StackTracePlus" 26 | versioning.version = "1.0.6" 27 | versioning.author = "Ignacio Burgueño" 28 | versioning.namespace = "aka.StackTracePlus" 29 | 30 | local version = require("l0.DependencyControl")({ 31 | name = versioning.name, 32 | description = versioning.description, 33 | version = versioning.version, 34 | author = versioning.author, 35 | moduleName = versioning.namespace, 36 | url = "https://github.com/Akatmks/Akatsumekusa-Aegisub-Scripts", 37 | feed = "https://raw.githubusercontent.com/Akatmks/Akatsumekusa-Aegisub-Scripts/master/DependencyControl.json" 38 | }) 39 | 40 | local functions = require("aka.StackTracePlus.StackTracePlus") 41 | 42 | setmetatable(functions, { __call = function() debug.traceback = functions.stacktrace end }) 43 | 44 | functions.version = version 45 | functions.versioning = versioning 46 | 47 | return version:register(functions) 48 | -------------------------------------------------------------------------------- /Aegisub/automation/include/aka/config/init.lua: -------------------------------------------------------------------------------- 1 | -- aka.config 2 | -- Copyright (c) Akatsumekusa and contributors 3 | 4 | ------------------------------------------------------------------------------ 5 | -- Permission is hereby granted, free of charge, to any person obtaining a 6 | -- copy of this software and associated documentation files (the "Software"), 7 | -- to deal in the Software without restriction, including without limitation 8 | -- the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 | -- and/or sell copies of the Software, and to permit persons to whom the 10 | -- Software is furnished to do so, subject to the following conditions: 11 | 12 | -- The above copyright notice and this permission notice shall be included in 13 | -- all copies or substantial portions of the Software. 14 | 15 | -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 | -- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 | -- DEALINGS IN THE SOFTWARE. 22 | ------------------------------------------------------------------------------ 23 | 24 | ------------------------------------------------------------------------------ 25 | -- Although this module is called aka.config, you can serialise anything you 26 | -- want using this module, not only configs. 27 | -- This module, compared to other serialisation modules like DepCtrl's 28 | -- ConfigHandler, generates beautified JSON. Additionally, it also provides a 29 | -- basic GUI so that the user may edit the JSON in Aegisub. The JSON editor 30 | -- supports templates or presets. 31 | -- 32 | -- If you for whatever reason are interested in using this module, tutorials 33 | -- are available at „docs/Using aka.config.md“. 34 | ------------------------------------------------------------------------------ 35 | 36 | local versioning = {} 37 | 38 | -- ‎aka.config 39 | versioning.name = "aka.config" 40 | versioning.description = "Module aka.config" 41 | versioning.version = "1.0.14" 42 | versioning.author = "Akatsumekusa and contributors" 43 | versioning.namespace = "aka.config" 44 | 45 | versioning.requiredModules = "[{ \"moduleName\": \"aka.config2\" }, { \"moduleName\": \"aka.outcome\" }, { \"moduleName\": \"aka.unicode\" }, { \"moduleName\": \"aegisub.re\" }]" 46 | 47 | local version = require("l0.DependencyControl")({ 48 | name = versioning.name, 49 | description = versioning.description, 50 | version = versioning.version, 51 | author = versioning.author, 52 | moduleName = versioning.namespace, 53 | url = "https://github.com/Akatmks/Akatsumekusa-Aegisub-Scripts", 54 | feed = "https://raw.githubusercontent.com/Akatmks/Akatsumekusa-Aegisub-Scripts/master/DependencyControl.json", 55 | { 56 | { "aka.config2", version = "1.0.0" }, 57 | { "aka.outcome", version = "1.0.0" }, 58 | { "aka.unicode", version = "1.0.0" }, 59 | { "aegisub.re" } 60 | } 61 | }) 62 | version:requireModules() 63 | 64 | local config = require("aka.config.config") 65 | 66 | config.version = version 67 | config.versioning = versioning 68 | 69 | return version:register(config) 70 | -------------------------------------------------------------------------------- /Aegisub/automation/include/aka/config2/init.lua: -------------------------------------------------------------------------------- 1 | -- aka.config2 2 | -- Copyright (c) Akatsumekusa and contributors 3 | 4 | ------------------------------------------------------------------------------ 5 | -- Permission is hereby granted, free of charge, to any person obtaining a 6 | -- copy of this software and associated documentation files (the "Software"), 7 | -- to deal in the Software without restriction, including without limitation 8 | -- the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 | -- and/or sell copies of the Software, and to permit persons to whom the 10 | -- Software is furnished to do so, subject to the following conditions: 11 | 12 | -- The above copyright notice and this permission notice shall be included in 13 | -- all copies or substantial portions of the Software. 14 | 15 | -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 | -- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 | -- DEALINGS IN THE SOFTWARE. 22 | ------------------------------------------------------------------------------ 23 | 24 | ------------------------------------------------------------------------------ 25 | -- Tutorials are available at „docs/Using aka.config.md“. 26 | ------------------------------------------------------------------------------ 27 | 28 | local versioning = {} 29 | 30 | versioning.name = "aka.config2" 31 | versioning.description = "Module aka.config2" 32 | versioning.version = "1.0.11" 33 | versioning.author = "Akatsumekusa and contributors" 34 | versioning.namespace = "aka.config2" 35 | 36 | versioning.requiredModules = "[{ \"moduleName\": \"aka.outcome\" }, { \"moduleName\": \"aegisub.re\" }, { \"moduleName\": \"aegisub.unicode\" }, { \"moduleName\": \"lfs\" }]" 37 | 38 | local version = require("l0.DependencyControl")({ 39 | name = versioning.name, 40 | description = versioning.description, 41 | version = versioning.version, 42 | author = versioning.author, 43 | moduleName = versioning.namespace, 44 | url = "https://github.com/Akatmks/Akatsumekusa-Aegisub-Scripts", 45 | feed = "https://raw.githubusercontent.com/Akatmks/Akatsumekusa-Aegisub-Scripts/master/DependencyControl.json", 46 | { 47 | { "aka.outcome", version = "1.0.0" }, 48 | { "aegisub.re" }, 49 | { "aegisub.unicode" }, 50 | { "lfs" } 51 | } 52 | }) 53 | version:requireModules() 54 | 55 | local config2 = require("aka.config2.config2") 56 | 57 | config2.version = version 58 | config2.versioning = versioning 59 | 60 | return version:register(config2) 61 | -------------------------------------------------------------------------------- /Aegisub/automation/include/aka/uikit/init.lua: -------------------------------------------------------------------------------- 1 | -- aka.uikit 2 | -- Copyright (c) Akatsumekusa and contributors 3 | 4 | ------------------------------------------------------------------------------ 5 | -- Permission is hereby granted, free of charge, to any person obtaining a 6 | -- copy of this software and associated documentation files (the "Software"), 7 | -- to deal in the Software without restriction, including without limitation 8 | -- the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 | -- and/or sell copies of the Software, and to permit persons to whom the 10 | -- Software is furnished to do so, subject to the following conditions: 11 | 12 | -- The above copyright notice and this permission notice shall be included in 13 | -- all copies or substantial portions of the Software. 14 | 15 | -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 | -- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 | -- DEALINGS IN THE SOFTWARE. 22 | ------------------------------------------------------------------------------ 23 | 24 | local versioning = {} 25 | 26 | versioning.name = "aka.uikit" 27 | versioning.description = "Module aka.uikit" 28 | versioning.version = "1.0.14" 29 | versioning.author = "Akatsumekusa and contributors" 30 | versioning.namespace = "aka.uikit" 31 | 32 | versioning.requiredModules = "[{ \"moduleName\": \"aka.outcome\" }, { \"moduleName\": \"aegisub.re\" }, { \"moduleName\": \"ILL.ILL\" }, { \"moduleName\": \"aka.config2\" }]" 33 | 34 | local version = require("l0.DependencyControl")({ 35 | name = versioning.name, 36 | description = versioning.description, 37 | version = versioning.version, 38 | author = versioning.author, 39 | moduleName = versioning.namespace, 40 | url = "https://github.com/Akatmks/Akatsumekusa-Aegisub-Scripts", 41 | feed = "https://raw.githubusercontent.com/Akatmks/Akatsumekusa-Aegisub-Scripts/master/DependencyControl.json", 42 | { 43 | { "aka.outcome", version = "1.0.0" }, 44 | { "aegisub.re" }, 45 | { "ILL.ILL", version = "1.0.0" }, 46 | { "aka.config2", version = "1.0.0" } 47 | } 48 | }) 49 | 50 | local functions = {} 51 | 52 | functions.dialog = require("aka.uikit.dialog").dialog 53 | functions.buttons = require("aka.uikit.buttons").buttons 54 | functions.display = require("aka.uikit.display").display 55 | 56 | functions.error = function(str) error(str) end 57 | 58 | functions.version = version 59 | functions.versioning = versioning 60 | 61 | return version:register(functions) 62 | -------------------------------------------------------------------------------- /Aegisub/automation/include/aka/unicode/init.lua: -------------------------------------------------------------------------------- 1 | -- aka.unicode 2 | -- Copyright (c) Akatsumekusa and contributors 3 | 4 | ------------------------------------------------------------------------------ 5 | -- Permission is hereby granted, free of charge, to any person obtaining a 6 | -- copy of this software and associated documentation files (the "Software"), 7 | -- to deal in the Software without restriction, including without limitation 8 | -- the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 | -- and/or sell copies of the Software, and to permit persons to whom the 10 | -- Software is furnished to do so, subject to the following conditions: 11 | 12 | -- The above copyright notice and this permission notice shall be included in 13 | -- all copies or substantial portions of the Software. 14 | 15 | -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 | -- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 | -- DEALINGS IN THE SOFTWARE. 22 | ------------------------------------------------------------------------------ 23 | 24 | local versioning = {} 25 | 26 | versioning.name = "aka.unicode" 27 | versioning.description = "Module aka.unicode" 28 | versioning.version = "1.0.10" 29 | versioning.author = "Akatsumekusa and contributors" 30 | versioning.namespace = "aka.unicode" 31 | 32 | versioning.requiredModules = "[{ \"moduleName\": \"aegisub.unicode\" }, { \"moduleName\": \"bit\" }]" 33 | 34 | local version = require("l0.DependencyControl")({ 35 | name = versioning.name, 36 | description = versioning.description, 37 | version = versioning.version, 38 | author = versioning.author, 39 | moduleName = versioning.namespace, 40 | url = "https://github.com/Akatmks/Akatsumekusa-Aegisub-Scripts", 41 | feed = "https://raw.githubusercontent.com/Akatmks/Akatsumekusa-Aegisub-Scripts/master/DependencyControl.json", 42 | { 43 | { "aegisub.unicode" }, 44 | { "bit" } 45 | } 46 | }) 47 | local unicode, bit = version:requireModules() 48 | 49 | unicode.char = function(codepoint) 50 | local byte1 51 | local byte2 52 | local byte3 53 | local byte4 54 | 55 | if codepoint < 0 then 56 | error("[aka.unicode] Invalid UTF-8 codepoint") 57 | elseif codepoint <= 0x7F then 58 | return string.char(codepoint) 59 | elseif codepoint <= 0x7FF then 60 | byte1 = 0xC0 + bit.rshift(codepoint, 6) 61 | byte2 = 0x80 + bit.band(codepoint, 0x3F) 62 | return string.char(byte1, byte2) 63 | elseif codepoint <= 0xFFFF then 64 | byte1 = 0xE0 + bit.rshift(codepoint, 12) 65 | byte2 = 0x80 + bit.band(bit.rshift(codepoint, 6), 0x3F) 66 | byte3 = 0x80 + bit.band(codepoint, 0x3F) 67 | return string.char(byte1, byte2, byte3) 68 | elseif codepoint <= 0x10FFFF then 69 | byte1 = 0xF0 + bit.rshift(codepoint, 18) 70 | byte2 = 0x80 + bit.band(bit.rshift(codepoint, 12), 0x3F) 71 | byte3 = 0x80 + bit.band(bit.rshift(codepoint, 6), 0x3F) 72 | byte4 = 0x80 + bit.band(codepoint, 0x3F) 73 | return string.char(byte1, byte2, byte3, byte4) 74 | else 75 | error("[aka.unicode] Invalid UTF-8 codepoint") 76 | end end 77 | 78 | unicode.version = version 79 | unicode.versioning = versioning 80 | 81 | return version:register(unicode) 82 | -------------------------------------------------------------------------------- /Aegisub/automation/include/aka/unsemantic/init.lua: -------------------------------------------------------------------------------- 1 | -- aka.unsemantic 2 | -- Copyright (c) Akatsumekusa and contributors 3 | 4 | ------------------------------------------------------------------------------ 5 | -- Permission is hereby granted, free of charge, to any person obtaining a 6 | -- copy of this software and associated documentation files (the "Software"), 7 | -- to deal in the Software without restriction, including without limitation 8 | -- the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 | -- and/or sell copies of the Software, and to permit persons to whom the 10 | -- Software is furnished to do so, subject to the following conditions: 11 | 12 | -- The above copyright notice and this permission notice shall be included in 13 | -- all copies or substantial portions of the Software. 14 | 15 | -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 | -- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 | -- DEALINGS IN THE SOFTWARE. 22 | ------------------------------------------------------------------------------ 23 | 24 | local versioning = {} 25 | 26 | versioning.name = "aka.unsemantic" 27 | versioning.description = "Module aka.unsemantic" 28 | versioning.version = "1.1.2" 29 | versioning.author = "Akatsumekusa and contributors" 30 | versioning.namespace = "aka.unsemantic" 31 | 32 | versioning.requiredModules = "[{ \"moduleName\": \"lpeg\" }]" 33 | 34 | local version = require("l0.DependencyControl")({ 35 | name = versioning.name, 36 | description = versioning.description, 37 | version = versioning.version, 38 | author = versioning.author, 39 | moduleName = versioning.namespace, 40 | url = "https://github.com/Akatmks/Akatsumekusa-Aegisub-Scripts", 41 | feed = "https://raw.githubusercontent.com/Akatmks/Akatsumekusa-Aegisub-Scripts/master/DependencyControl.json", 42 | { 43 | { "lpeg" } 44 | } 45 | }) 46 | local lpeg = version:requireModules() 47 | local C, P, R = lpeg.C, lpeg.P, lpeg.R 48 | 49 | local number = C(R"09"^1)/tonumber 50 | local dot = P"." 51 | local version_match = number*dot*number*dot*number 52 | local two_number_version_match = number*dot*number 53 | 54 | local mt 55 | local V 56 | mt = { 57 | __index = mt, 58 | __eq = function(lhs, rhs) 59 | return lhs.major == rhs.major and 60 | lhs.minor == rhs.minor and 61 | lhs.patch == rhs.patch 62 | end, 63 | __lt = function(lhs, rhs) 64 | return lhs.major < rhs.major or 65 | (lhs.major == rhs.major and lhs.minor < rhs.minor) or 66 | (lhs.major == rhs.major and lhs.minor == rhs.minor and lhs.patch < rhs.patch) 67 | end, 68 | __le = function(lhs, rhs) 69 | return lhs.major < rhs.major or 70 | (lhs.major == rhs.major and lhs.minor < rhs.minor) or 71 | (lhs.major == rhs.major and lhs.minor == rhs.minor and lhs.patch <= rhs.patch) 72 | end 73 | } 74 | V = function(version_str) 75 | local t 76 | 77 | t = {} 78 | t.major, t.minor, t.patch = version_match:match(version_str) 79 | if not t.major then 80 | t.major, t.minor = two_number_version_match:match(version_str) 81 | t.patch = -1 82 | 83 | if not t.major then 84 | error("[aka.unsemantic] Invalid version format.") 85 | end end 86 | 87 | setmetatable(t, mt) 88 | 89 | return t 90 | end 91 | 92 | local unsemantic = {} 93 | 94 | unsemantic.V = V 95 | 96 | unsemantic.version = version 97 | unsemantic.versioning = versioning 98 | 99 | return version:register(unsemantic) 100 | -------------------------------------------------------------------------------- /Aegisub/automation/include/clipper2/clipper2/clipper2.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LightArrowsEXE/dotfiles/176453ed77d9f8c59539df8e71b3171ef6e73b3d/Aegisub/automation/include/clipper2/clipper2/clipper2.dll -------------------------------------------------------------------------------- /Aegisub/automation/include/json.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | Licensed according to the included 'LICENSE' document 3 | Author: Thomas Harning Jr 4 | ]] 5 | local decode = require("json.decode") 6 | local encode = require("json.encode") 7 | local util = require("json.util") 8 | 9 | local _G = _G 10 | 11 | local _ENV = nil 12 | 13 | local json = { 14 | _VERSION = "1.3.5", 15 | _DESCRIPTION = "LuaJSON : customizable JSON decoder/encoder", 16 | _COPYRIGHT = "Copyright (c) 2007-2017 Thomas Harning Jr. ", 17 | decode = decode, 18 | encode = encode, 19 | util = util 20 | } 21 | 22 | _G.json = json 23 | 24 | return json 25 | -------------------------------------------------------------------------------- /Aegisub/automation/include/json/decode/number.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | Licensed according to the included 'LICENSE' document 3 | Author: Thomas Harning Jr 4 | ]] 5 | local lpeg = require("lpeg") 6 | local tonumber = tonumber 7 | local jsonutil = require("json.util") 8 | local merge = jsonutil.merge 9 | local util = require("json.decode.util") 10 | 11 | local _ENV = nil 12 | 13 | local digit = lpeg.R("09") 14 | local digits = digit^1 15 | 16 | -- Illegal octal declaration 17 | local illegal_octal_detect = #(lpeg.P('0') * digits) * util.denied("Octal numbers") 18 | 19 | local int = (lpeg.P('-') + 0) * (lpeg.R("19") * digits + illegal_octal_detect + digit) 20 | 21 | local frac = lpeg.P('.') * digits 22 | 23 | local exp = lpeg.S("Ee") * (lpeg.S("-+") + 0) * digits 24 | 25 | local nan = lpeg.S("Nn") * lpeg.S("Aa") * lpeg.S("Nn") 26 | local inf = lpeg.S("Ii") * lpeg.P("nfinity") 27 | local ninf = lpeg.P('-') * lpeg.S("Ii") * lpeg.P("nfinity") 28 | local hex = (lpeg.P("0x") + lpeg.P("0X")) * lpeg.R("09","AF","af")^1 29 | 30 | local defaultOptions = { 31 | nan = true, 32 | inf = true, 33 | frac = true, 34 | exp = true, 35 | hex = false 36 | } 37 | 38 | local modeOptions = {} 39 | 40 | modeOptions.strict = { 41 | nan = false, 42 | inf = false 43 | } 44 | 45 | local nan_value = 0/0 46 | local inf_value = 1/0 47 | local ninf_value = -1/0 48 | 49 | --[[ 50 | Options: configuration options for number rules 51 | nan: match NaN 52 | inf: match Infinity 53 | frac: match fraction portion (.0) 54 | exp: match exponent portion (e1) 55 | DEFAULT: nan, inf, frac, exp 56 | ]] 57 | local function mergeOptions(options, mode) 58 | jsonutil.doOptionMerge(options, false, 'number', defaultOptions, mode and modeOptions[mode]) 59 | end 60 | 61 | local function generateLexer(options) 62 | options = options.number 63 | local ret = int 64 | if options.frac then 65 | ret = ret * (frac + 0) 66 | else 67 | ret = ret * (#frac * util.denied("Fractions", "number.frac") + 0) 68 | end 69 | if options.exp then 70 | ret = ret * (exp + 0) 71 | else 72 | ret = ret * (#exp * util.denied("Exponents", "number.exp") + 0) 73 | end 74 | if options.hex then 75 | ret = hex + ret 76 | else 77 | ret = #hex * util.denied("Hexadecimal", "number.hex") + ret 78 | end 79 | -- Capture number now 80 | ret = ret / tonumber 81 | if options.nan then 82 | ret = ret + nan / function() return nan_value end 83 | else 84 | ret = ret + #nan * util.denied("NaN", "number.nan") 85 | end 86 | if options.inf then 87 | ret = ret + ninf / function() return ninf_value end + inf / function() return inf_value end 88 | else 89 | ret = ret + (#ninf + #inf) * util.denied("+/-Inf", "number.inf") 90 | end 91 | return ret 92 | end 93 | 94 | local number = { 95 | int = int, 96 | mergeOptions = mergeOptions, 97 | generateLexer = generateLexer 98 | } 99 | 100 | return number 101 | -------------------------------------------------------------------------------- /Aegisub/automation/include/json/decode/others.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | Licensed according to the included 'LICENSE' document 3 | Author: Thomas Harning Jr 4 | ]] 5 | local lpeg = require("lpeg") 6 | local jsonutil = require("json.util") 7 | local merge = jsonutil.merge 8 | local util = require("json.decode.util") 9 | 10 | -- Container module for other JavaScript types (bool, null, undefined) 11 | 12 | local _ENV = nil 13 | 14 | -- For null and undefined, use the util.null value to preserve null-ness 15 | local booleanCapture = 16 | lpeg.P("true") * lpeg.Cc(true) 17 | + lpeg.P("false") * lpeg.Cc(false) 18 | 19 | local nullCapture = lpeg.P("null") 20 | local undefinedCapture = lpeg.P("undefined") 21 | 22 | local defaultOptions = { 23 | allowUndefined = true, 24 | null = jsonutil.null, 25 | undefined = jsonutil.undefined 26 | } 27 | 28 | local modeOptions = {} 29 | 30 | modeOptions.simple = { 31 | null = false, -- Mapped to nil 32 | undefined = false -- Mapped to nil 33 | } 34 | modeOptions.strict = { 35 | allowUndefined = false 36 | } 37 | 38 | local function mergeOptions(options, mode) 39 | jsonutil.doOptionMerge(options, false, 'others', defaultOptions, mode and modeOptions[mode]) 40 | end 41 | 42 | local function generateLexer(options) 43 | -- The 'or nil' clause allows false to map to a nil value since 'nil' cannot be merged 44 | options = options.others 45 | local valueCapture = ( 46 | booleanCapture 47 | + nullCapture * lpeg.Cc(options.null or nil) 48 | ) 49 | if options.allowUndefined then 50 | valueCapture = valueCapture + undefinedCapture * lpeg.Cc(options.undefined or nil) 51 | else 52 | valueCapture = valueCapture + #undefinedCapture * util.denied("undefined", "others.allowUndefined") 53 | end 54 | return valueCapture 55 | end 56 | 57 | local others = { 58 | mergeOptions = mergeOptions, 59 | generateLexer = generateLexer 60 | } 61 | 62 | return others 63 | -------------------------------------------------------------------------------- /Aegisub/automation/include/json/decode/util.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | Licensed according to the included 'LICENSE' document 3 | Author: Thomas Harning Jr 4 | ]] 5 | local lpeg = require("lpeg") 6 | local select = select 7 | local pairs, ipairs = pairs, ipairs 8 | local tonumber = tonumber 9 | local string_char = require("string").char 10 | local rawset = rawset 11 | local jsonutil = require("json.util") 12 | 13 | local error = error 14 | local setmetatable = setmetatable 15 | 16 | local table_concat = require("table").concat 17 | 18 | local merge = require("json.util").merge 19 | 20 | local type = type 21 | 22 | local _ENV = nil 23 | 24 | local function get_invalid_character_info(input, index) 25 | local parsed = input:sub(1, index) 26 | local bad_character = input:sub(index, index) 27 | local _, line_number = parsed:gsub('\n',{}) 28 | local last_line = parsed:match("\n([^\n]+.)$") or parsed 29 | return line_number, #last_line, bad_character, last_line 30 | end 31 | 32 | local function build_report(msg) 33 | local fmt = msg:gsub("%%", "%%%%") .. " @ character: %i %i:%i [%s] line:\n%s" 34 | return lpeg.P(function(data, pos) 35 | local line, line_index, bad_char, last_line = get_invalid_character_info(data, pos) 36 | local text = fmt:format(pos, line, line_index, bad_char, last_line) 37 | error(text) 38 | end) * 1 39 | end 40 | local function unexpected() 41 | local msg = "unexpected character" 42 | return build_report(msg) 43 | end 44 | local function denied(item, option) 45 | local msg 46 | if option then 47 | msg = ("'%s' denied by option set '%s'"):format(item, option) 48 | else 49 | msg = ("'%s' denied"):format(item) 50 | end 51 | return build_report(msg) 52 | end 53 | 54 | -- 09, 0A, 0B, 0C, 0D, 20 55 | local ascii_space = lpeg.S("\t\n\v\f\r ") 56 | local unicode_space 57 | do 58 | local chr = string_char 59 | local u_space = ascii_space 60 | -- \u0085 \u00A0 61 | u_space = u_space + lpeg.P(chr(0xC2)) * lpeg.S(chr(0x85) .. chr(0xA0)) 62 | -- \u1680 \u180E 63 | u_space = u_space + lpeg.P(chr(0xE1)) * (lpeg.P(chr(0x9A, 0x80)) + chr(0xA0, 0x8E)) 64 | -- \u2000 - \u200A, also 200B 65 | local spacing_end = "" 66 | for i = 0x80,0x8b do 67 | spacing_end = spacing_end .. chr(i) 68 | end 69 | -- \u2028 \u2029 \u202F 70 | spacing_end = spacing_end .. chr(0xA8) .. chr(0xA9) .. chr(0xAF) 71 | u_space = u_space + lpeg.P(chr(0xE2, 0x80)) * lpeg.S(spacing_end) 72 | -- \u205F 73 | u_space = u_space + lpeg.P(chr(0xE2, 0x81, 0x9F)) 74 | -- \u3000 75 | u_space = u_space + lpeg.P(chr(0xE3, 0x80, 0x80)) 76 | -- BOM \uFEFF 77 | u_space = u_space + lpeg.P(chr(0xEF, 0xBB, 0xBF)) 78 | unicode_space = u_space 79 | end 80 | 81 | local identifier = lpeg.R("AZ","az","__") * lpeg.R("AZ","az", "__", "09") ^0 82 | 83 | local hex = lpeg.R("09","AF","af") 84 | local hexpair = hex * hex 85 | 86 | local comments = { 87 | cpp = lpeg.P("//") * (1 - lpeg.P("\n"))^0 * lpeg.P("\n"), 88 | c = lpeg.P("/*") * (1 - lpeg.P("*/"))^0 * lpeg.P("*/") 89 | } 90 | 91 | local comment = comments.cpp + comments.c 92 | 93 | local ascii_ignored = (ascii_space + comment)^0 94 | 95 | local unicode_ignored = (unicode_space + comment)^0 96 | 97 | -- Parse the lpeg version skipping patch-values 98 | -- LPEG <= 0.7 have no version value... so 0.7 is value 99 | -- LPEG >= 1.1 uses a string for the version instead of function 100 | local DecimalLpegVersion = lpeg.version 101 | and tonumber( 102 | (type(lpeg.version) == "string" and lpeg.version or lpeg.version()):match("(%d+%.%d+)") 103 | ) 104 | or 0.7 105 | 106 | local function setObjectKeyForceNumber(t, key, value) 107 | key = tonumber(key) or key 108 | return rawset(t, key, value) 109 | end 110 | 111 | local util = { 112 | unexpected = unexpected, 113 | denied = denied, 114 | ascii_space = ascii_space, 115 | unicode_space = unicode_space, 116 | identifier = identifier, 117 | hex = hex, 118 | hexpair = hexpair, 119 | comments = comments, 120 | comment = comment, 121 | ascii_ignored = ascii_ignored, 122 | unicode_ignored = unicode_ignored, 123 | DecimalLpegVersion = DecimalLpegVersion, 124 | get_invalid_character_info = get_invalid_character_info, 125 | setObjectKeyForceNumber = setObjectKeyForceNumber 126 | } 127 | 128 | return util 129 | -------------------------------------------------------------------------------- /Aegisub/automation/include/json/encode/array.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | Licensed according to the included 'LICENSE' document 3 | Author: Thomas Harning Jr 4 | ]] 5 | local jsonutil = require("json.util") 6 | 7 | local type = type 8 | local pairs = pairs 9 | local assert = assert 10 | 11 | local table = require("table") 12 | local math = require("math") 13 | local table_concat = table.concat 14 | local math_floor, math_modf = math.floor, math.modf 15 | 16 | local jsonutil = require("json.util") 17 | local util_IsArray = jsonutil.IsArray 18 | 19 | local _ENV = nil 20 | 21 | local defaultOptions = { 22 | isArray = util_IsArray 23 | } 24 | 25 | local modeOptions = {} 26 | 27 | local function mergeOptions(options, mode) 28 | jsonutil.doOptionMerge(options, false, 'array', defaultOptions, mode and modeOptions[mode]) 29 | end 30 | 31 | --[[ 32 | Utility function to determine whether a table is an array or not. 33 | Criteria for it being an array: 34 | * ExternalIsArray returns true (or false directly reports not-array) 35 | * If the table has an 'n' value that is an integer >= 1 then it 36 | is an array... may result in false positives (should check some values 37 | before it) 38 | * It is a contiguous list of values with zero string-based keys 39 | ]] 40 | local function isArray(val, options) 41 | local externalIsArray = options and options.isArray 42 | 43 | if externalIsArray then 44 | local ret = externalIsArray(val) 45 | if ret == true or ret == false then 46 | return ret 47 | end 48 | end 49 | -- Use the 'n' element if it's a number 50 | if type(val.n) == 'number' and math_floor(val.n) == val.n and val.n >= 1 then 51 | return true 52 | end 53 | local len = #val 54 | for k,v in pairs(val) do 55 | if type(k) ~= 'number' then 56 | return false 57 | end 58 | local _, decim = math_modf(k) 59 | if not (decim == 0 and 1<=k) then 60 | return false 61 | end 62 | if k > len then -- Use Lua's length as absolute determiner 63 | return false 64 | end 65 | end 66 | 67 | return true 68 | end 69 | 70 | --[[ 71 | Cleanup function to unmark a value as in the encoding process and return 72 | trailing results 73 | ]] 74 | local function unmarkAfterEncode(tab, state, ...) 75 | state.already_encoded[tab] = nil 76 | return ... 77 | end 78 | local function getEncoder(options) 79 | options = options and jsonutil.merge({}, defaultOptions, options) or defaultOptions 80 | local function encodeArray(tab, state) 81 | if not isArray(tab, options) then 82 | return false 83 | end 84 | -- Make sure this value hasn't been encoded yet 85 | state.check_unique(tab) 86 | local encode = state.encode 87 | local compositeEncoder = state.outputEncoder.composite 88 | local valueEncoder = [[ 89 | for i = 1, (composite.n or #composite) do 90 | local val = composite[i] 91 | PUTINNER(i ~= 1) 92 | val = encode(val, state) 93 | val = val or '' 94 | if val then 95 | PUTVALUE(val) 96 | end 97 | end 98 | ]] 99 | return unmarkAfterEncode(tab, state, compositeEncoder(valueEncoder, '[', ']', ',', tab, encode, state)) 100 | end 101 | return { table = encodeArray } 102 | end 103 | 104 | local array = { 105 | mergeOptions = mergeOptions, 106 | isArray = isArray, 107 | getEncoder = getEncoder 108 | } 109 | 110 | return array 111 | -------------------------------------------------------------------------------- /Aegisub/automation/include/json/encode/calls.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | Licensed according to the included 'LICENSE' document 3 | Author: Thomas Harning Jr 4 | ]] 5 | local table = require("table") 6 | local table_concat = table.concat 7 | 8 | local select = select 9 | local getmetatable, setmetatable = getmetatable, setmetatable 10 | local assert = assert 11 | 12 | local jsonutil = require("json.util") 13 | 14 | local isCall, decodeCall = jsonutil.isCall, jsonutil.decodeCall 15 | 16 | local _ENV = nil 17 | 18 | local defaultOptions = { 19 | } 20 | 21 | -- No real default-option handling needed... 22 | local modeOptions = {} 23 | 24 | local function mergeOptions(options, mode) 25 | jsonutil.doOptionMerge(options, false, 'calls', defaultOptions, mode and modeOptions[mode]) 26 | end 27 | 28 | 29 | --[[ 30 | Encodes 'value' as a function call 31 | Must have parameters in the 'callData' field of the metatable 32 | name == name of the function call 33 | parameters == array of parameters to encode 34 | ]] 35 | local function getEncoder(options) 36 | options = options and jsonutil.merge({}, defaultOptions, options) or defaultOptions 37 | local function encodeCall(value, state) 38 | if not isCall(value) then 39 | return false 40 | end 41 | local encode = state.encode 42 | local name, params = decodeCall(value) 43 | local compositeEncoder = state.outputEncoder.composite 44 | local valueEncoder = [[ 45 | for i = 1, (composite.n or #composite) do 46 | local val = composite[i] 47 | PUTINNER(i ~= 1) 48 | val = encode(val, state) 49 | val = val or '' 50 | if val then 51 | PUTVALUE(val) 52 | end 53 | end 54 | ]] 55 | return compositeEncoder(valueEncoder, name .. '(', ')', ',', params, encode, state) 56 | end 57 | return { 58 | table = encodeCall, 59 | ['function'] = encodeCall 60 | } 61 | end 62 | 63 | local calls = { 64 | mergeOptions = mergeOptions, 65 | getEncoder = getEncoder 66 | } 67 | 68 | return calls 69 | -------------------------------------------------------------------------------- /Aegisub/automation/include/json/encode/number.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | Licensed according to the included 'LICENSE' document 3 | Author: Thomas Harning Jr 4 | ]] 5 | local tostring = tostring 6 | local assert = assert 7 | local jsonutil = require("json.util") 8 | local huge = require("math").huge 9 | 10 | local _ENV = nil 11 | 12 | local defaultOptions = { 13 | nan = true, 14 | inf = true 15 | } 16 | 17 | local modeOptions = {} 18 | modeOptions.strict = { 19 | nan = false, 20 | inf = false 21 | } 22 | 23 | local function mergeOptions(options, mode) 24 | jsonutil.doOptionMerge(options, false, 'number', defaultOptions, mode and modeOptions[mode]) 25 | end 26 | 27 | 28 | local function encodeNumber(number, options) 29 | if number ~= number then 30 | assert(options.nan, "Invalid number: NaN not enabled") 31 | return "NaN" 32 | end 33 | if number == huge then 34 | assert(options.inf, "Invalid number: Infinity not enabled") 35 | return "Infinity" 36 | end 37 | if number == -huge then 38 | assert(options.inf, "Invalid number: Infinity not enabled") 39 | return "-Infinity" 40 | end 41 | return tostring(number) 42 | end 43 | 44 | local function getEncoder(options) 45 | options = options and jsonutil.merge({}, defaultOptions, options) or defaultOptions 46 | return { 47 | number = function(number, state) 48 | return encodeNumber(number, options) 49 | end 50 | } 51 | end 52 | 53 | local number = { 54 | mergeOptions = mergeOptions, 55 | getEncoder = getEncoder 56 | } 57 | 58 | return number 59 | -------------------------------------------------------------------------------- /Aegisub/automation/include/json/encode/object.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | Licensed according to the included 'LICENSE' document 3 | Author: Thomas Harning Jr 4 | ]] 5 | local pairs = pairs 6 | local assert = assert 7 | 8 | local type = type 9 | local tostring = tostring 10 | 11 | local table_concat = require("table").concat 12 | local jsonutil = require("json.util") 13 | 14 | local _ENV = nil 15 | 16 | local defaultOptions = { 17 | } 18 | 19 | local modeOptions = {} 20 | 21 | local function mergeOptions(options, mode) 22 | jsonutil.doOptionMerge(options, false, 'object', defaultOptions, mode and modeOptions[mode]) 23 | end 24 | 25 | --[[ 26 | Cleanup function to unmark a value as in the encoding process and return 27 | trailing results 28 | ]] 29 | local function unmarkAfterEncode(tab, state, ...) 30 | state.already_encoded[tab] = nil 31 | return ... 32 | end 33 | --[[ 34 | Encode a table as a JSON Object ( keys = strings, values = anything else ) 35 | ]] 36 | local function encodeTable(tab, options, state) 37 | -- Make sure this value hasn't been encoded yet 38 | state.check_unique(tab) 39 | local encode = state.encode 40 | local compositeEncoder = state.outputEncoder.composite 41 | local valueEncoder = [[ 42 | local first = true 43 | for k, v in pairs(composite) do 44 | local ti = type(k) 45 | assert(ti == 'string' or ti == 'number' or ti == 'boolean', "Invalid object index type: " .. ti) 46 | local name = encode(tostring(k), state, true) 47 | if first then 48 | first = false 49 | else 50 | name = ',' .. name 51 | end 52 | PUTVALUE(name .. ':') 53 | local val = encode(v, state) 54 | val = val or '' 55 | if val then 56 | PUTVALUE(val) 57 | end 58 | end 59 | ]] 60 | return unmarkAfterEncode(tab, state, compositeEncoder(valueEncoder, '{', '}', nil, tab, encode, state)) 61 | end 62 | 63 | local function getEncoder(options) 64 | options = options and jsonutil.merge({}, defaultOptions, options) or defaultOptions 65 | return { 66 | table = function(tab, state) 67 | return encodeTable(tab, options, state) 68 | end 69 | } 70 | end 71 | 72 | local object = { 73 | mergeOptions = mergeOptions, 74 | getEncoder = getEncoder 75 | } 76 | 77 | return object 78 | -------------------------------------------------------------------------------- /Aegisub/automation/include/json/encode/others.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | Licensed according to the included 'LICENSE' document 3 | Author: Thomas Harning Jr 4 | ]] 5 | local tostring = tostring 6 | 7 | local assert = assert 8 | local jsonutil = require("json.util") 9 | local type = type 10 | 11 | local _ENV = nil 12 | 13 | -- Shortcut that works 14 | local encodeBoolean = tostring 15 | 16 | local defaultOptions = { 17 | allowUndefined = true, 18 | null = jsonutil.null, 19 | undefined = jsonutil.undefined 20 | } 21 | 22 | local modeOptions = {} 23 | 24 | modeOptions.strict = { 25 | allowUndefined = false 26 | } 27 | 28 | local function mergeOptions(options, mode) 29 | jsonutil.doOptionMerge(options, false, 'others', defaultOptions, mode and modeOptions[mode]) 30 | end 31 | local function getEncoder(options) 32 | options = options and jsonutil.merge({}, defaultOptions, options) or defaultOptions 33 | local function encodeOthers(value, state) 34 | if value == options.null then 35 | return 'null' 36 | elseif value == options.undefined then 37 | assert(options.allowUndefined, "Invalid value: Unsupported 'Undefined' parameter") 38 | return 'undefined' 39 | else 40 | return false 41 | end 42 | end 43 | local function encodeBoolean(value, state) 44 | return value and 'true' or 'false' 45 | end 46 | local nullType = type(options.null) 47 | local undefinedType = options.undefined and type(options.undefined) 48 | -- Make sure that all of the types handled here are handled 49 | local ret = { 50 | boolean = encodeBoolean, 51 | ['nil'] = function() return 'null' end, 52 | [nullType] = encodeOthers 53 | } 54 | if undefinedType then 55 | ret[undefinedType] = encodeOthers 56 | end 57 | return ret 58 | end 59 | 60 | local others = { 61 | encodeBoolean = encodeBoolean, 62 | mergeOptions = mergeOptions, 63 | getEncoder = getEncoder 64 | } 65 | 66 | return others 67 | -------------------------------------------------------------------------------- /Aegisub/automation/include/json/encode/output.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | Licensed according to the included 'LICENSE' document 3 | Author: Thomas Harning Jr 4 | ]] 5 | local type = type 6 | local assert, error = assert, error 7 | local table_concat = require("table").concat 8 | local loadstring = loadstring or load 9 | 10 | local io = require("io") 11 | 12 | local setmetatable = setmetatable 13 | 14 | local output_utility = require("json.encode.output_utility") 15 | 16 | local _ENV = nil 17 | 18 | local tableCompositeCache = setmetatable({}, {__mode = 'v'}) 19 | 20 | local TABLE_VALUE_WRITER = [[ 21 | ret[#ret + 1] = %VALUE% 22 | ]] 23 | 24 | local TABLE_INNER_WRITER = "" 25 | 26 | --[[ 27 | nextValues can output a max of two values to throw into the data stream 28 | expected to be called until nil is first return value 29 | value separator should either be attached to v1 or in innerValue 30 | ]] 31 | local function defaultTableCompositeWriter(nextValues, beginValue, closeValue, innerValue, composite, encode, state) 32 | if type(nextValues) == 'string' then 33 | local fun = output_utility.prepareEncoder(defaultTableCompositeWriter, nextValues, innerValue, TABLE_VALUE_WRITER, TABLE_INNER_WRITER) 34 | local ret = {} 35 | fun(composite, ret, encode, state) 36 | return beginValue .. table_concat(ret, innerValue) .. closeValue 37 | end 38 | end 39 | 40 | -- no 'simple' as default action is just to return the value 41 | local function getDefault() 42 | return { composite = defaultTableCompositeWriter } 43 | end 44 | 45 | -- BEGIN IO-WRITER OUTPUT 46 | local IO_INNER_WRITER = [[ 47 | if %WRITE_INNER% then 48 | state.__outputFile:write(%INNER_VALUE%) 49 | end 50 | ]] 51 | local IO_VALUE_WRITER = [[ 52 | state.__outputFile:write(%VALUE%) 53 | ]] 54 | 55 | local function buildIoWriter(output) 56 | if not output then -- Default to stdout 57 | output = io.output() 58 | end 59 | local function ioWriter(nextValues, beginValue, closeValue, innerValue, composite, encode, state) 60 | -- HOOK OUTPUT STATE 61 | state.__outputFile = output 62 | if type(nextValues) == 'string' then 63 | local fun = output_utility.prepareEncoder(ioWriter, nextValues, innerValue, IO_VALUE_WRITER, IO_INNER_WRITER) 64 | local ret = {} 65 | output:write(beginValue) 66 | fun(composite, ret, encode, state) 67 | output:write(closeValue) 68 | return nil 69 | end 70 | end 71 | 72 | local function ioSimpleWriter(encoded) 73 | if encoded then 74 | output:write(encoded) 75 | end 76 | return nil 77 | end 78 | return { composite = ioWriter, simple = ioSimpleWriter } 79 | end 80 | local function getIoWriter(output) 81 | return function() 82 | return buildIoWriter(output) 83 | end 84 | end 85 | 86 | local output = { 87 | getDefault = getDefault, 88 | getIoWriter = getIoWriter 89 | } 90 | 91 | return output 92 | -------------------------------------------------------------------------------- /Aegisub/automation/include/json/encode/output_utility.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | Licensed according to the included 'LICENSE' document 3 | Author: Thomas Harning Jr 4 | ]] 5 | local setmetatable = setmetatable 6 | local assert, loadstring = assert, loadstring or load 7 | 8 | local _ENV = nil 9 | 10 | -- Key == weak, if main key goes away, then cache cleared 11 | local outputCache = setmetatable({}, {__mode = 'k'}) 12 | -- TODO: inner tables weak? 13 | 14 | local function buildFunction(nextValues, innerValue, valueWriter, innerWriter) 15 | local putInner = "" 16 | if innerValue and innerWriter then 17 | -- Prepare the lua-string representation of the separator to put in between values 18 | local formattedInnerValue = ("%q"):format(innerValue) 19 | -- Fill in the condition %WRITE_INNER% and the %INNER_VALUE% to actually write 20 | putInner = innerWriter:gsub("%%WRITE_INNER%%", "%%1"):gsub("%%INNER_VALUE%%", formattedInnerValue) 21 | end 22 | -- Template-in the value writer (if present) and its conditional argument 23 | local functionCode = nextValues:gsub("PUTINNER(%b())", putInner) 24 | -- %VALUE% is to be filled in by the value-to-write 25 | valueWriter = valueWriter:gsub("%%VALUE%%", "%%1") 26 | -- Template-in the value writer with its argument 27 | functionCode = functionCode:gsub("PUTVALUE(%b())", valueWriter) 28 | functionCode = [[ 29 | return function(composite, ret, encode, state) 30 | ]] .. functionCode .. [[ 31 | end 32 | ]] 33 | return assert(loadstring(functionCode))() 34 | end 35 | 36 | local function prepareEncoder(cacheKey, nextValues, innerValue, valueWriter, innerWriter) 37 | local cache = outputCache[cacheKey] 38 | if not cache then 39 | cache = {} 40 | outputCache[cacheKey] = cache 41 | end 42 | local fun = cache[nextValues] 43 | if not fun then 44 | fun = buildFunction(nextValues, innerValue, valueWriter, innerWriter) 45 | cache[nextValues] = fun 46 | end 47 | return fun 48 | end 49 | 50 | local output_utility = { 51 | prepareEncoder = prepareEncoder 52 | } 53 | 54 | return output_utility 55 | -------------------------------------------------------------------------------- /Aegisub/automation/include/json/encode/strings.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | Licensed according to the included 'LICENSE' document 3 | Author: Thomas Harning Jr 4 | ]] 5 | local string_char = require("string").char 6 | local pairs = pairs 7 | 8 | local jsonutil = require("json.util") 9 | local util_merge = jsonutil.merge 10 | 11 | local _ENV = nil 12 | 13 | local normalEncodingMap = { 14 | ['"'] = '\\"', 15 | ['\\'] = '\\\\', 16 | ['/'] = '\\/', 17 | ['\b'] = '\\b', 18 | ['\f'] = '\\f', 19 | ['\n'] = '\\n', 20 | ['\r'] = '\\r', 21 | ['\t'] = '\\t', 22 | ['\v'] = '\\v' -- not in official spec, on report, removing 23 | } 24 | 25 | local xEncodingMap = {} 26 | for char, encoded in pairs(normalEncodingMap) do 27 | xEncodingMap[char] = encoded 28 | end 29 | 30 | -- Pre-encode the control characters to speed up encoding... 31 | -- NOTE: UTF-8 may not work out right w/ JavaScript 32 | -- JavaScript uses 2 bytes after a \u... yet UTF-8 is a 33 | -- byte-stream encoding, not pairs of bytes (it does encode 34 | -- some letters > 1 byte, but base case is 1) 35 | for i = 0, 255 do 36 | local c = string_char(i) 37 | if c:match('[%z\1-\031\128-\255]') and not normalEncodingMap[c] then 38 | -- WARN: UTF8 specializes values >= 0x80 as parts of sequences... 39 | -- without \x encoding, do not allow encoding > 7F 40 | normalEncodingMap[c] = ('\\u%.4X'):format(i) 41 | xEncodingMap[c] = ('\\x%.2X'):format(i) 42 | end 43 | end 44 | 45 | local defaultOptions = { 46 | xEncode = false, -- Encode single-bytes as \xXX 47 | processor = nil, -- Simple processor for the string prior to quoting 48 | -- / is not required to be quoted but it helps with certain decoding 49 | -- Required encoded characters, " \, and 00-1F (0 - 31) 50 | encodeSet = '\\"/%z\1-\031', 51 | encodeSetAppend = nil -- Chars to append to the default set 52 | } 53 | 54 | local modeOptions = {} 55 | 56 | local function mergeOptions(options, mode) 57 | jsonutil.doOptionMerge(options, false, 'strings', defaultOptions, mode and modeOptions[mode]) 58 | end 59 | 60 | local function getEncoder(options) 61 | options = options and util_merge({}, defaultOptions, options) or defaultOptions 62 | local encodeSet = options.encodeSet 63 | if options.encodeSetAppend then 64 | encodeSet = encodeSet .. options.encodeSetAppend 65 | end 66 | local encodingMap = options.xEncode and xEncodingMap or normalEncodingMap 67 | local encodeString 68 | if options.processor then 69 | local processor = options.processor 70 | encodeString = function(s, state) 71 | return '"' .. processor(s:gsub('[' .. encodeSet .. ']', encodingMap)) .. '"' 72 | end 73 | else 74 | encodeString = function(s, state) 75 | return '"' .. s:gsub('[' .. encodeSet .. ']', encodingMap) .. '"' 76 | end 77 | end 78 | return { 79 | string = encodeString 80 | } 81 | end 82 | 83 | local strings = { 84 | mergeOptions = mergeOptions, 85 | getEncoder = getEncoder 86 | } 87 | 88 | return strings 89 | -------------------------------------------------------------------------------- /Aegisub/automation/include/json/util.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | Licensed according to the included 'LICENSE' document 3 | Author: Thomas Harning Jr 4 | ]] 5 | local type = type 6 | local print = print 7 | local tostring = tostring 8 | local pairs = pairs 9 | local getmetatable, setmetatable = getmetatable, setmetatable 10 | local select = select 11 | 12 | local _ENV = nil 13 | 14 | local function foreach(tab, func) 15 | for k, v in pairs(tab) do 16 | func(k,v) 17 | end 18 | end 19 | local function printValue(tab, name) 20 | local parsed = {} 21 | local function doPrint(key, value, space) 22 | space = space or '' 23 | if type(value) == 'table' then 24 | if parsed[value] then 25 | print(space .. key .. '= <' .. parsed[value] .. '>') 26 | else 27 | parsed[value] = key 28 | print(space .. key .. '= {') 29 | space = space .. ' ' 30 | foreach(value, function(key, value) doPrint(key, value, space) end) 31 | end 32 | else 33 | if type(value) == 'string' then 34 | value = '[[' .. tostring(value) .. ']]' 35 | end 36 | print(space .. key .. '=' .. tostring(value)) 37 | end 38 | end 39 | doPrint(name, tab) 40 | end 41 | 42 | local function clone(t) 43 | local ret = {} 44 | for k,v in pairs(t) do 45 | ret[k] = v 46 | end 47 | return ret 48 | end 49 | 50 | local function inner_merge(t, remaining, from, ...) 51 | if remaining == 0 then 52 | return t 53 | end 54 | if from then 55 | for k,v in pairs(from) do 56 | t[k] = v 57 | end 58 | end 59 | return inner_merge(t, remaining - 1, ...) 60 | end 61 | 62 | --[[* 63 | Shallow-merges tables in order onto the first table. 64 | 65 | @param t table to merge entries onto 66 | @param ... sequence of 0 or more tables to merge onto 't' 67 | 68 | @returns table 't' from input 69 | ]] 70 | local function merge(t, ...) 71 | return inner_merge(t, select('#', ...), ...) 72 | end 73 | 74 | -- Function to insert nulls into the JSON stream 75 | local function null() 76 | return null 77 | end 78 | 79 | -- Marker for 'undefined' values 80 | local function undefined() 81 | return undefined 82 | end 83 | 84 | local ArrayMT = {} 85 | 86 | --[[ 87 | Return's true if the metatable marks it as an array.. 88 | Or false if it has no array component at all 89 | Otherwise nil to get the normal detection component working 90 | ]] 91 | local function IsArray(value) 92 | if type(value) ~= 'table' then return false end 93 | local meta = getmetatable(value) 94 | local ret = meta == ArrayMT or (meta ~= nil and meta.__is_luajson_array) 95 | if not ret then 96 | if #value == 0 then return false end 97 | else 98 | return ret 99 | end 100 | end 101 | local function InitArray(array) 102 | setmetatable(array, ArrayMT) 103 | return array 104 | end 105 | 106 | local CallMT = {} 107 | 108 | local function isCall(value) 109 | return CallMT == getmetatable(value) 110 | end 111 | 112 | local function buildCall(name, ...) 113 | local callData = { 114 | name = name, 115 | parameters = {n = select('#', ...), ...} 116 | } 117 | return setmetatable(callData, CallMT) 118 | end 119 | 120 | local function decodeCall(callData) 121 | if not isCall(callData) then return nil end 122 | return callData.name, callData.parameters 123 | end 124 | 125 | local function doOptionMerge(options, nested, name, defaultOptions, modeOptions) 126 | if nested then 127 | modeOptions = modeOptions and modeOptions[name] 128 | defaultOptions = defaultOptions and defaultOptions[name] 129 | end 130 | options[name] = merge( 131 | {}, 132 | defaultOptions, 133 | modeOptions, 134 | options[name] 135 | ) 136 | end 137 | 138 | local json_util = { 139 | printValue = printValue, 140 | clone = clone, 141 | merge = merge, 142 | null = null, 143 | undefined = undefined, 144 | IsArray = IsArray, 145 | InitArray = InitArray, 146 | isCall = isCall, 147 | buildCall = buildCall, 148 | decodeCall = decodeCall, 149 | doOptionMerge = doOptionMerge 150 | } 151 | 152 | return json_util 153 | -------------------------------------------------------------------------------- /Aegisub/automation/include/l0/ASSFoundation/ClassFactory.lua: -------------------------------------------------------------------------------- 1 | local util = require("aegisub.util") 2 | local Functional = require("l0.Functional"); 3 | 4 | return function (typeName, baseClasses, order, types, tagProps, compatibleClasses, customIndex) 5 | if not baseClasses or type(baseClasses)=="table" and baseClasses.instanceOf then 6 | baseClasses = {baseClasses} 7 | end 8 | local cls, compatibleClasses = {}, compatibleClasses or {} 9 | 10 | -- write base classes set and import class members 11 | cls.baseClasses = {} 12 | for i=1,#baseClasses do 13 | for k, v in pairs(baseClasses[i]) do 14 | cls[k] = v 15 | end 16 | cls.baseClasses[baseClasses[i]] = true 17 | end 18 | 19 | -- object constructor 20 | setmetatable(cls, { 21 | __call = function(cls, ...) 22 | local self = setmetatable({__tag = util.copy(cls.__defProps)}, cls) 23 | self:new(...) 24 | return self 25 | end}) 26 | 27 | cls.__index = customIndex and customIndex or cls 28 | cls.instanceOf, cls.typeName, cls.class = {[cls] = true}, typeName, cls 29 | cls.__meta__ = {order = order, types = types} 30 | cls.__defProps = Functional.table.union(tagProps or {}, cls.__defProps or {}) 31 | 32 | -- compatible classes 33 | cls.compatible = Functional.list.makeSet(compatibleClasses) 34 | -- set mutual compatibility in reference classes 35 | for i=1,#compatibleClasses do 36 | compatibleClasses[i].compatible[cls] = true 37 | end 38 | cls.compatible[cls] = true 39 | 40 | cls.getRawArgCnt = function(self) 41 | local cnt, meta = 0, self.__meta__ 42 | if not meta.types then return 0 end 43 | for i=1,#meta.types do 44 | cnt = cnt + (type(meta.types[i])=="table" and meta.types[i].class and meta.types[i]:getRawArgCnt() or 1) 45 | end 46 | return cnt 47 | end 48 | cls.__meta__.rawArgCnt = cls:getRawArgCnt() 49 | 50 | return cls 51 | end 52 | -------------------------------------------------------------------------------- /Aegisub/automation/include/l0/ASSFoundation/Draw/Bezier.moon: -------------------------------------------------------------------------------- 1 | return (ASS, ASSFInst, yutilsMissingMsg, createASSClass, Functional, LineCollection, Line, logger, SubInspector, Yutils) -> 2 | {:list, :math, :string, :table, :unicode, :util, :re } = Functional 3 | round = math.round 4 | defProps, ptsDefProps = {name: "b", ords: 6, precision: 3}, {precision: 3, scale: 1} 5 | 6 | DrawBezier = createASSClass "Draw.Bezier", ASS.Draw.CommandBase, {"p1","p2","p3"}, 7 | {ASS.Point, ASS.Point, ASS.Point}, defProps 8 | Point = ASS.Point 9 | 10 | DrawBezier.new = (args) => 11 | -- this whole constructor is an optimization of the generic CommandBase constructor 12 | -- creating beziers works without this constructor, albeit slower 13 | args = @getArgs args, nil, true unless args.__raw 14 | args[1] or= 0 15 | 16 | @p1 = Point args[1], args[2] or args[1] 17 | @p2 = Point args[3] or @p1.x, args[4] or @p1.y 18 | @p3 = Point args[5] or @p2.x, args[6] or @p2.y 19 | 20 | return @ 21 | 22 | -- optimized superfast constructor for internal use 23 | DrawBezier.__defNew = (args) -> 24 | p1 = setmetatable {__tag: ptsDefProps, x: args[1], y: args[2] or args[1]}, Point 25 | p2 = setmetatable {__tag: ptsDefProps, x: args[3] or p1.x, y: args[4] or p1.y}, Point 26 | p3 = setmetatable {__tag: ptsDefProps, x: args[5] or p2.x, y: args[6] or p2.y}, Point 27 | 28 | bezier = setmetatable {__tag: defProps, :p1, :p2, :p3}, DrawBezier 29 | return bezier 30 | 31 | 32 | DrawBezier.commonOp = (method, callback, default, ...) => 33 | args, j = {...}, 1 34 | if #args <= 2 -- special case to allow common operation on all x an y values of a vector drawing 35 | args[3], args[4], args[5], args[6] = args[1], args[2], args[1], args[2] 36 | if type(default)=="table" and #default <= 2 37 | default = {default[1], default[2], default[1], default[2]} 38 | 39 | args = @getArgs args, default, false 40 | 41 | for valName in *@__meta__.order 42 | subCnt = #@[valName].__meta__.order 43 | @[valName][method] @[valName], unpack args, j, j+subCnt-1 44 | j += subCnt 45 | 46 | return @ 47 | 48 | DrawBezier.getTagParams = (precision = @__tag.precision) => 49 | x1, y1, x2, y2, x3, y3 = @p1.x, @p1.y, @p2.x, @p2.y, @p3.x, @p3.y 50 | x1, x2, x3, y1, y2, y3 %= @__tag.mod if @__tag.mod 51 | 52 | return round(x1, precision), round(y1, precision), round(x2, precision), round(y2, precision), round(x3, precision), round(y3, precision) 53 | 54 | DrawBezier.getFlattened = (noUpdate) => 55 | assert Yutils, yutilsMissingMsg 56 | unless noUpdate and @flattened 57 | @parent\getLength! unless noUpdate and @cursor 58 | 59 | -- TODO: check 60 | shapeSection = ASS.Draw.DrawingBase{ASS.Draw.Move(@cursor.x, @cursor.y), @} 61 | @flattened = ASS.Draw.DrawingBase{str: Yutils.shape.flatten shapeSection\getTagParams!} 62 | 63 | return @flattened 64 | 65 | 66 | DrawBezier.getPoints = => 67 | return {@p1, @p2, @p3} 68 | 69 | return DrawBezier 70 | -------------------------------------------------------------------------------- /Aegisub/automation/include/l0/ASSFoundation/Draw/Close.moon: -------------------------------------------------------------------------------- 1 | return (ASS, ASSFInst, yutilsMissingMsg, createASSClass, Functional, LineCollection, Line, logger, SubInspector, Yutils) -> 2 | {:list, :math, :string, :table, :unicode, :util, :re } = Functional 3 | defProps = {name: "c", ords: 0} 4 | 5 | DrawClose = createASSClass "Draw.Close", ASS.Draw.CommandBase, {}, {}, defProps 6 | 7 | DrawClose.getPoints = => 8 | return {} 9 | 10 | -- optimized superfast constructor for internal use 11 | DrawClose.__defNew = -> 12 | close = setmetatable {__tag: defProps}, DrawClose 13 | return close 14 | 15 | return DrawClose 16 | -------------------------------------------------------------------------------- /Aegisub/automation/include/l0/ASSFoundation/Draw/CommandBase.moon: -------------------------------------------------------------------------------- 1 | return (ASS, ASSFInst, yutilsMissingMsg, createASSClass, Functional, LineCollection, Line, logger, SubInspector, Yutils) -> 2 | {:list, :math, :string, :table, :unicode, :util, :re } = Functional 3 | round = math.round 4 | 5 | CommandBase = createASSClass "Draw.CommandBase", ASS.Tag.Base, {}, {}, {precision: 3} 6 | CommandBase.new = (args, y) => 7 | -- most drawing commands (l, m, n) represent a single point 8 | if @compatible[ASS.Point] 9 | argType = type args 10 | @x, @y = if argType == "number" 11 | args, y or 0 12 | elseif argType == "table" and args.__raw 13 | args[1] or 0, args[2] or args[1] or 0 14 | else 15 | args = y == nil and args or {args, y} 16 | @readProps args 17 | @getArgs args, 0, true 18 | else 19 | -- any other drawing command either consist of multiple (b, s) or no (c) points 20 | -- do note that this constructor is fairly slow in the context of drawings 21 | -- which is why faster overrides are specified for common drawing commands 22 | for i = 1, #args, 2 23 | j = (i+1)/2 24 | @[@__meta__.order[j]] = @__meta__.types[j]{args[i], args[i+1] or args[i]} 25 | 26 | return @ 27 | 28 | CommandBase.getTagParams = (precision = @__tag.precision) => 29 | return round(@x, precision), round(@y, precision) if @compatible[ASS.Point] 30 | 31 | params, parts = @__meta__.order, {} 32 | i, j = 1, 1 33 | while i <= @__meta__.rawArgCnt 34 | parts[i], parts[i+1] = @[params[j]]\getTagParams! 35 | i += @[params[j]].__meta__.rawArgCnt 36 | j += 1 37 | 38 | return unpack parts 39 | 40 | 41 | CommandBase.getLength = (prevCmd) => 42 | assert Yutils, yutilsMissingMsg 43 | -- get end coordinates (cursor) of previous command 44 | x0, y0 = if prevCmd 45 | if prevCmd.class == ASS.Draw.Bezier 46 | prevCmd.p3.x, prevCmd.p3.y 47 | elseif prevCmd.compatible[ASS.Point] 48 | prevCmd.x, prevCmd.y 49 | else prevCmd\get! 50 | else 0, 0 51 | 52 | -- save cursor for further processing 53 | @cursor = ASS.Point x0, y0 54 | 55 | name = @__tag.name 56 | 57 | len = switch name 58 | when "b" 59 | -- TODO: make less grievously slow, drop Yutils 60 | shapeSection = ASS.Draw.DrawingBase{ASS.Draw.Move(@cursor.x, @cursor.y), @} 61 | --save flattened shape for further processing 62 | @flattened = ASS.Draw.DrawingBase{str: Yutils.shape.flatten shapeSection\getTagParams!} 63 | @flattened\getLength! 64 | when "l" 65 | x, y = @get! 66 | math.vector2.distance x0, y0, x, y 67 | else 0 -- m, n 68 | 69 | -- save length for further processing 70 | @length = len 71 | return len 72 | 73 | 74 | CommandBase.getPositionAtLength = (len, useCachedLengths, useCurveTime) => 75 | assert Yutils, yutilsMissingMsg 76 | @parent\getLength! unless @length and @cursor and useCachedLengths 77 | 78 | pos = switch @__tag.name 79 | when useCurveTime and "b" 80 | px, py = Yutils.math.bezier math.min(len/@length, 1), {{@cursor.x, @cursor.y}, {@p1.x, @p1.y}, 81 | {@p2.x, @p2.y}, {@p3.x, @p3.y}} 82 | ASS.Point px, py 83 | when "b" 84 | -- we already know this data is up-to-date because @parent\getLength! was run 85 | @getFlattened(true)\getPositionAtLength len, true 86 | when "l" 87 | ASS.Point @copy!\scaleToLength len, true 88 | when "m" 89 | ASS.Point @ 90 | 91 | pos.__tag.name = "position" 92 | return pos 93 | 94 | 95 | CommandBase.getPoints = (allowCompatible) => 96 | return allowCompatible and {@} or {ASS.Point{@}} 97 | 98 | return CommandBase 99 | -------------------------------------------------------------------------------- /Aegisub/automation/include/l0/ASSFoundation/Draw/Line.moon: -------------------------------------------------------------------------------- 1 | return (ASS, ASSFInst, yutilsMissingMsg, createASSClass, Functional, LineCollection, Line, logger, SubInspector, Yutils) -> 2 | {:list, :math, :string, :table, :unicode, :util, :re } = Functional 3 | defProps = {name: "l", ords: 2, precision: 3, scale: 1} 4 | 5 | DrawLine = createASSClass "Draw.Line", {ASS.Draw.CommandBase, ASS.Point}, {"x", "y"}, {"number", "number"}, 6 | defProps, {ASS.Point, ASS.Draw.Move, ASS.Draw.MoveNc} 7 | 8 | -- optimized superfast constructor for internal use 9 | DrawLine.__defNew = (args) -> 10 | line = setmetatable {x: args[1], y: args[2], __tag: defProps}, DrawLine 11 | return line 12 | 13 | DrawLine.scaleToLength = (len, useCachedLengths) => 14 | @parent\getLength! unless @length and @cursor and useCachedLengths 15 | @sub @cursor 16 | @set @cursor\copy!\add math.vector2.normalize @x, @y, len 17 | return @ 18 | 19 | 20 | DrawLine.getAngle = (ref, vectAngle, useCachedLengths) => 21 | unless ref and @cursor and useCachedLengths 22 | @parent\getLength! 23 | ref = @cursor 24 | 25 | return ASS.Point.getAngle @, ref, vectAngle 26 | 27 | return DrawLine 28 | -------------------------------------------------------------------------------- /Aegisub/automation/include/l0/ASSFoundation/Draw/Move.moon: -------------------------------------------------------------------------------- 1 | return (ASS, ASSFInst, yutilsMissingMsg, createASSClass, Functional, LineCollection, Line, logger, SubInspector, Yutils) -> 2 | {:list, :math, :string, :table, :unicode, :util, :re } = Functional 3 | defProps = {name: "m", ords: 2, precision: 3, scale: 1} 4 | 5 | DrawMove = createASSClass "Draw.Move", {ASS.Draw.CommandBase, ASS.Point}, {"x", "y"}, {"number", "number"}, 6 | defProps, {ASS.Point} 7 | 8 | -- optimized superfast constructor for internal use 9 | DrawMove.__defNew = (args) -> 10 | move = setmetatable {x: args[1], y: args[2], __tag: defProps}, DrawMove 11 | return move 12 | 13 | return DrawMove 14 | -------------------------------------------------------------------------------- /Aegisub/automation/include/l0/ASSFoundation/Draw/MoveNc.moon: -------------------------------------------------------------------------------- 1 | return (ASS, ASSFInst, yutilsMissingMsg, createASSClass, Functional, LineCollection, Line, logger, SubInspector, Yutils) -> 2 | {:list, :math, :string, :table, :unicode, :util, :re } = Functional 3 | defProps = {name: "n", ords: 2, precision: 3, scale: 1} 4 | 5 | DrawMoveNc = createASSClass "Draw.MoveNc", {ASS.Draw.Move}, {"x", "y"}, {"number", "number"}, 6 | defProps, {ASS.Draw.Move, ASS.Point} 7 | 8 | -- optimized superfast constructor for internal use 9 | DrawMoveNc.__defNew = (args) -> 10 | moveNc = setmetatable {x: args[1], y: args[2], __tag: defProps}, DrawMoveNc 11 | return moveNc 12 | 13 | return DrawMoveNc 14 | -------------------------------------------------------------------------------- /Aegisub/automation/include/l0/ASSFoundation/LineBounds.moon: -------------------------------------------------------------------------------- 1 | return (ASS, ASSFInst, yutilsMissingMsg, createASSClass, Functional, LineCollection, Line, logger, SubInspector, Yutils) -> 2 | min, max = math.min, math.max 3 | {:list, :math, :string, :table, :unicode, :util, :re } = Functional 4 | 5 | LineBounds = createASSClass "LineBounds", ASS.Base, {1, 2, "w", "h", "fbf", "animated", "rawText"}, 6 | {ASS.Point, ASS.Point, "number", "number", "table", "boolean", "string"} 7 | 8 | LineBounds.new = (line, bounds, frames, first, last, offset, keepRawText) => 9 | first, last, offset = first or 1, last or #bounds, offset or 0 10 | @animated = line.si_exhaustive 11 | 12 | if bounds[first] != false or @animated 13 | x2Max, y2Max, x1Min, y1Min = 0, 0 14 | 15 | @fbf = {off: frames[first]+offset, n: last - first + 1} 16 | for i = first, last 17 | bound = bounds[i] 18 | if bound 19 | x1, y1, w, h = bound.x, bound.y, bound.w, bound.h 20 | x2, y2 = x1+w, y1+h 21 | @fbf[frames[i]+offset] = {ASS.Point(x1,y1), ASS.Point(x2,y2), :w, :h, hash: bound.hash, solid: bound.solid} 22 | x1Min, y1Min = min(x1, x1Min or x1), min(y1, y1Min or y1) 23 | x2Max, y2Max = max(x2, x2Max), max(y2, y2Max) 24 | else @fbf[frames[i]+offset] = {w: 0, h: 0, hash: false} 25 | 26 | if x1Min 27 | @[1], @[2], @w, @h = ASS.Point(x1Min, y1Min), ASS.Point(x2Max, y2Max), x2Max-x1Min, y2Max-y1Min 28 | @firstHash = @fbf[@fbf.off].hash 29 | @firstFrameIsSolid = @fbf[@fbf.off].solid 30 | else @w, @h = 0, 0 31 | 32 | else @w, @h, @fbf = 0, 0, {n: 0} 33 | 34 | @rawText = line.text if keepRawText 35 | return @ 36 | 37 | LineBounds.equal = (other) => 38 | if other.class != LineBounds 39 | -- TODO: replace w/ logger.error 40 | error string.format "argument #1 must be an object of type %s, got a %s.", 41 | LineBounds.typeName, ASS\instanceOf(other) or type(other) 42 | 43 | return true if @w == other.w == 0 44 | if @w != other.w or @h != other.h or @animated != other.animated or @fbf.n != other.fbf.n or @fbf.off != other.fbf.off 45 | return false 46 | 47 | for i = 0, @fbf.n-1 48 | return false if @fbf[@fbf.off+i].hash != other.fbf[other.fbf.off+i].hash 49 | 50 | return true 51 | 52 | return LineBounds 53 | -------------------------------------------------------------------------------- /Aegisub/automation/include/l0/ASSFoundation/LineBoundsBatch.moon: -------------------------------------------------------------------------------- 1 | return (ASS, ASSFInst, yutilsMissingMsg, createASSClass, Functional, LineCollection, Line, logger, SubInspector, Yutils) -> 2 | {:list, :math, :string, :table, :unicode, :util, :re } = Functional 3 | time, frame = aegisub.ms_from_frame, aegisub.frame_from_ms 4 | 5 | msgs = { 6 | add: { 7 | badLineContents: "argument #1 (lineContents) must be an object of type %s, got a %s." 8 | } 9 | run: { 10 | inspectorError: "SubInspector Error: %s." 11 | inspectorRefreshingHeaders: "Sending headers to SubInspector for new subtitle object %s..." 12 | inspectorNoSub: "Can't initialize SubInspector because the Line isn't linked to a subtitle object." 13 | } 14 | } 15 | 16 | LineBoundsBatch = createASSClass "LineBoundsBatch", ASS.Base, {"lines", "lineCount", "virtualStartFrame", "bounds"}, 17 | {"table", "number", "number", "table"} 18 | 19 | 20 | LineBoundsBatch.new = => 21 | @lines = {} 22 | @lineCount = 0 23 | @virtualStartFrame = 1 24 | return @ 25 | 26 | LineBoundsBatch.add = (cnts, custText, foreignKey = cnts, isAnimated = cnts\isAnimated!) => 27 | if cnts.class != ASS.LineContents 28 | logger\error msgs.add.badLineContents, ASS.LineContents.typeName, ASS\instanceOf(cnts) or type cnts 29 | 30 | line = cnts.line 31 | @sub or= line.sub 32 | @lineCount += 1 33 | 34 | startFrame, endFrame = frame(line.start_time), frame line.end_time 35 | line = Line line, nil, { 36 | text: custText == true and line.text or custText or cnts\getString! 37 | start_time: time @virtualStartFrame 38 | end_time: time @virtualStartFrame + endFrame - startFrame 39 | extra: false 40 | } 41 | 42 | line.si_exhaustive = isAnimated 43 | @lines[foreignKey] = {id: @lineCount, :line, :foreignKey, startFrame: @virtualStartFrame, 44 | offset: startFrame - @virtualStartFrame } 45 | @virtualStartFrame += 1 + endFrame - startFrame 46 | 47 | LineBoundsBatch.run = (purgeLines, outBounds = {}) => 48 | return {} if @lineCount == 0 49 | 50 | subInspector = ASSFInst.cache.SubInspector 51 | if not subInspector 52 | logger\assert @sub, msgs.run.inspectorNoSub 53 | subInspector, msg = SubInspector @sub 54 | logger\error msgs.run.inspectorError, tostring msg unless subInspector 55 | ASSFInst.cache.SubInspector = subInspector 56 | ASSFInst.cache.lastInspectorSub = @sub 57 | 58 | elseif @sub and @sub != ASSFInst.cache.lastInspectorSub 59 | logger\trace msgs.run.inspectorRefreshingHeaders, @sub 60 | subInspector\updateHeader @sub 61 | ASSFInst.cache.lastInspectorSub = @sub 62 | 63 | linesById = {line.id, line for _, line in pairs @lines} 64 | bounds, times = subInspector\getBounds [line.line for line in *linesById] 65 | frames = times.frames 66 | 67 | fStart, lineId, line = 1, 1, linesById[1] 68 | for f, frame in ipairs frames 69 | if frame == line.startFrame 70 | outBounds[line.foreignKey] = ASS.LineBounds line.line, bounds, frames, fStart, f, line.offset 71 | if purgeLines 72 | @lines[line.foreignKey] = nil 73 | lineId += 1 74 | line = linesById[lineId] 75 | fStart = f + 1 76 | break unless line 77 | 78 | if purgeLines 79 | @lines, @lineCount, @virtualStartFrame = {}, 0, 1 80 | 81 | return outBounds 82 | return LineBoundsBatch 83 | -------------------------------------------------------------------------------- /Aegisub/automation/include/l0/ASSFoundation/Parser/LineText.moon: -------------------------------------------------------------------------------- 1 | return (ASS, ASSFInst, yutilsMissingMsg, createASSClass, Functional, LineCollection, Line, logger, SubInspector, Yutils) -> 2 | {:list, :math, :string, :table, :unicode, :util, :re } = Functional 3 | 4 | class LineText 5 | insertContentSections = (str, sections, sectCnt, drawingState) -> 6 | if drawingState.value == 0 7 | sections[sectCnt+1], sectCnt = ASS.Section.Text(str), sectCnt + 1 8 | else 9 | sections[sectCnt+1] = ASS.Section.Drawing{:str, scale: drawingState} 10 | if sections[sectCnt+1].junk 11 | sections[sectCnt+2], sectCnt = sections[sectCnt+1].junk, sectCnt + 2 12 | else sectCnt = sectCnt + 1 13 | return sectCnt 14 | 15 | @getSections = (line) => 16 | sections = {} 17 | i, sectCnt, drawingState, ovrStart, ovrEnd = 1, 0, ASS\createTag "drawing", 0 18 | while i <= #line.text 19 | ovrStart, ovrEnd = line.text\find "{.-}", i 20 | if ovrStart 21 | if ovrStart > i 22 | substr = line.text\sub i, ovrStart-1 23 | sectCnt = insertContentSections substr, sections, sectCnt, drawingState 24 | 25 | tagSection = ASS.Parser.Sections\getTagOrCommentSection line.text\sub ovrStart+1, ovrEnd-1 26 | -- remove drawing tags from tag sections so we don't have to keep state in sync with ASSSection.Drawing 27 | if tagSection.class == ASS.Section.Tag 28 | drawingTags, drawingTagCnt = tagSection\removeTags "drawing" 29 | if #tagSection.tags == 0 and drawingTagCnt > 0 30 | tagSection = nil 31 | 32 | drawingState = drawingTags[drawingTagCnt] or drawingState 33 | 34 | if tagSection 35 | sections[sectCnt+1], sectCnt = tagSection, sectCnt + 1 36 | 37 | i = ovrEnd +1 38 | else 39 | insertContentSections line.text\sub(i), sections, sectCnt, drawingState 40 | break 41 | 42 | return sections 43 | 44 | @getLineContents = (line) => ASS.LineContents line, @getSections(line), false 45 | -------------------------------------------------------------------------------- /Aegisub/automation/include/l0/ASSFoundation/Parser/Sections.moon: -------------------------------------------------------------------------------- 1 | return (ASS, ASSFInst, yutilsMissingMsg, createASSClass, Functional, LineCollection, Line, logger, SubInspector, Yutils) -> 2 | {:list, :math, :string, :table, :unicode, :util, :re } = Functional 3 | 4 | class Sections 5 | tagMatchPattern = re.compile "\\\\[^\\\\\\(]+(?:\\([^\\)]+\\)?[^\\\\]*)?" 6 | 7 | @getTagOrCommentSection = (rawTags) => 8 | tags = @parseTags rawTags 9 | return ASS.Section.Comment rawTags if #tags == 0 and #rawTags > 0 10 | 11 | tagSection = ASS.Section.Tag tags 12 | return tagSection 13 | 14 | @parseTags = (rawTags) => 15 | tags, t = {}, 1 16 | return tags if #rawTags == 0 17 | 18 | for match in tagMatchPattern\gfind rawTags 19 | tag, _, last = ASS\getTagFromString match 20 | tags[t] = tag 21 | t += 1 22 | 23 | -- comments inside tag sections are read into ASS.Tag.Unknowns 24 | if last < #match 25 | afterStr = match\sub last + 1 26 | tags[t] = ASS\createTag afterStr\sub(1,1)=="\\" and "unknown" or "junk", afterStr 27 | t += 1 28 | 29 | return tags 30 | -------------------------------------------------------------------------------- /Aegisub/automation/include/l0/ASSFoundation/Primitive/Number.moon: -------------------------------------------------------------------------------- 1 | return (ASS, ASSFInst, yutilsMissingMsg, createASSClass, Functional, LineCollection, Line, logger, SubInspector, Yutils) -> 2 | {:list, :math, :string, :table, :unicode, :util, :re } = Functional 3 | 4 | msgs = { 5 | checkValue: { 6 | mustBePositive: "%s must be a positive number, got %d." 7 | mustBeInteger: "%s must be an integer, got %s." 8 | mustBeInRange: "%s must be in range %d - %d, got %s." 9 | } 10 | cmp: { 11 | badOperand: "operand #%d must be a number or an object of (or based on) the %s class, got a %s." 12 | } 13 | } 14 | 15 | Number = createASSClass "Number", ASS.Tag.Base, {"value"}, {"number"}, {base: 10, precision: 3, scale: 1} 16 | 17 | Number.new = (args) => 18 | if type(args) == "number" 19 | @value = args 20 | else 21 | @value = @getArgs(args, 0, true)[1] 22 | @readProps args 23 | @checkValue! 24 | @value %= @__tag.mod if @__tag.mod 25 | @value *= @__tag.scale if @__tag.scale != 1 26 | 27 | return @ 28 | 29 | Number.checkValue = => 30 | @typeCheck{@value} 31 | tag = @__tag 32 | 33 | if tag.range and (@value < tag.range[1] or @value > tag.range[2]) 34 | logger\error msgs.checkValue.mustBeInRange, @typeName, tag.range[1], tag.range[2], @value 35 | logger\error msgs.checkValue.mustBePositive, @typeName, @value if tag.positive and @value < 0 36 | logger\error msgs.checkValue.mustBeInteger, @typeName, @value if tag.integer and not math.isInt @value 37 | 38 | Number.getTagParams = (_, precision = @__tag.precision) => 39 | val = @value 40 | @checkValue! 41 | 42 | val %= @__tag.mod if @__tag.mod 43 | val /= @__tag.scale if @__tag.scale != 1 44 | 45 | return math.round val, precision 46 | 47 | Number.cmp = (a, mode, b) -> 48 | aType, bType = type(a), type b 49 | 50 | if aType == "table" and (a.compatible[Number] or a.baseClasses[Number]) 51 | a = a.value 52 | elseif aType !="number" 53 | logger\error msgs.cmp.badOperand, 1, Number.typeName, ASS\instanceOf(a) and a.typeName or type a 54 | 55 | if bType == "table" and (b.compatible[Number] or b.baseClasses[Number]) 56 | b = b.value 57 | elseif bType !="number" 58 | logger\error msgs.cmp.badOperand, 2, Number.typeName, ASS\instanceOf(b) and b.typeName or type b 59 | 60 | return switch mode 61 | when "<" then a < b 62 | when ">" then a > b 63 | when "<=" then a <= b 64 | when ">=" then a >= b 65 | 66 | Number.lerp = (a, b, t) -> 67 | c = a\copy! 68 | c.value = a.value + (b.value - a.value) * t 69 | return c 70 | 71 | Number.modEq = (val, div) => (@%div)\equal val 72 | 73 | Number.__lt = (a, b) -> Number.cmp a, "<", b 74 | Number.__le = (a, b) -> Number.cmp a, "<=", b 75 | Number.__add = (a, b) -> type(a) == "table" and a\copy!\add(b) or b\copy!\add a 76 | Number.__sub = (a, b) -> type(a) == "table" and a\copy!\sub(b) or Number(a)\sub b 77 | Number.__mul = (a, b) -> type(a) == "table" and a\copy!\mul(b) or b\copy!\mul a 78 | Number.__div = (a, b) -> type(a) == "table" and a\copy!\div(b) or Number(a)\div b 79 | Number.__mod = (a, b) -> type(a) == "table" and a\copy!\mod(b) or Number(a)\mod b 80 | Number.__pow = (a, b) -> type(a) == "table" and a\copy!\pow(b) or Number(a)\pow b 81 | 82 | return Number 83 | -------------------------------------------------------------------------------- /Aegisub/automation/include/l0/ASSFoundation/Primitive/Point.moon: -------------------------------------------------------------------------------- 1 | return (ASS, ASSFInst, yutilsMissingMsg, createASSClass, Functional, LineCollection, Line, logger, SubInspector, Yutils) -> 2 | {:list, :math, :string, :table, :unicode, :util, :re } = Functional 3 | round = math.round 4 | msgs = { 5 | getAngle: { 6 | badRef: "Argument #1 (ref) must be a Drawing Command, a %s (or compatible) or a coordinate table, got a %s." 7 | badTuple: "Table with reference coordinates must be of format {x, y}, got {%s, %s}." 8 | } 9 | } 10 | 11 | Point = createASSClass "Point", ASS.Tag.Base, {"x","y"}, {"number", "number"}, {precision: 3, scale: 1} 12 | 13 | Point.new = (x, y) => 14 | xType = type x 15 | @x, @y = if xType == "number" 16 | x, y or 0 17 | elseif xType == "table" and x.__raw 18 | x[1] or 0, x[2] or x[1] or 0 19 | else 20 | args = y == nil and x or {x, y} 21 | @readProps args 22 | unpack @getArgs args, 0, true 23 | 24 | return @ 25 | 26 | Point.getTagParams = (precision = @__tag.precision) => 27 | x, y = @x, @y 28 | x, y %= @__tag.mod if @__tag.mod 29 | 30 | return round(x, precision), round(y, precision) 31 | 32 | Point.getAngle = (ref, vectAngle) => 33 | if "table" != type ref 34 | logger\error msgs.getAngle.badRef, Point.typeName, type ref 35 | 36 | rx, ry = if ref.class == ASS.Draw.Bezier 37 | ref.p3.x, ref.p3.y 38 | elseif not ref.class 39 | logger\assert type(ref[1]) == "number" and type(ref[2]) == "number", msgs.getAngle.badTuple, 40 | tostring(ref[1]), tostring ref[2] 41 | ref[1], ref[2] 42 | elseif ref.compatible[Point] 43 | ref.x, ref.y 44 | else logger\error msgs.getAngle.badRef, Point.typeName, type ref 45 | 46 | 47 | sx, sy, cw = @x, @y 48 | deg = if vectAngle 49 | cw = (sx*ry - sy*rx) < 0 50 | a = (sx*rx + sy*ry) / math.sqrt(sx^2 + sy^2) / math.sqrt(rx^2 + ry^2) 51 | 52 | if a >= 1 or a <= -1 or a != a 53 | 0 -- math.acos(x) only defined for -1 61 | c = a\copy! 62 | c.x = a.x + (b.x - a.x) * t 63 | c.y = a.y + (b.y - a.y) * t 64 | return c 65 | 66 | return Point 67 | -------------------------------------------------------------------------------- /Aegisub/automation/include/l0/ASSFoundation/Primitive/String.moon: -------------------------------------------------------------------------------- 1 | return (ASS, ASSFInst, yutilsMissingMsg, createASSClass, Functional, LineCollection, Line, logger, SubInspector, Yutils) -> 2 | {:list, :math, :string, :table, :unicode, :util, :re } = Functional 3 | 4 | String = createASSClass "String", ASS.Tag.Base, {"value"}, {"string"} 5 | 6 | String.new = (args) => 7 | @value = @getArgs(args, "", true)[1] 8 | @readProps args 9 | return @ 10 | 11 | String.append = (str, sep) => 12 | if type(str) == "table" 13 | return @ if #str == 0 14 | str = table.concat str, sep 15 | 16 | sep = #@value > 0 and sep or "" 17 | return @commonOp "append", ((val, str) -> val .. sep ..str), "", str 18 | 19 | String.prepend = (str) => 20 | return @commonOp "prepend", ((val,str) -> str .. val), "", str 21 | 22 | String.replace = (pattern, rep, plainMatch, useRegex) => 23 | if plainMatch 24 | useRegex, pattern = false, string.escLuaExp pattern 25 | 26 | @value = useRegex and re.sub(@value, pattern, rep) or @value\gsub pattern, rep 27 | return @ 28 | 29 | String.reverse = => 30 | @value = unicode.reverse @value 31 | return @ 32 | 33 | return String 34 | -------------------------------------------------------------------------------- /Aegisub/automation/include/l0/ASSFoundation/Primitive/Time.moon: -------------------------------------------------------------------------------- 1 | return (ASS, ASSFInst, yutilsMissingMsg, createASSClass, Functional, LineCollection, Line, logger, SubInspector, Yutils) -> 2 | {:list, :math, :string, :table, :unicode, :util, :re } = Functional 3 | 4 | msgs = { 5 | getTagParams: 6 | { 7 | noFloatMs: "%s doesn't support floating point precision." 8 | } 9 | } 10 | 11 | Time = createASSClass "Time", ASS.Number, {"value"}, {"number"}, {precision: 0} 12 | -- TODO: implement adding by framecount 13 | 14 | Time.getTagParams = (precision = 0) => 15 | val = @value 16 | if precision > 0 17 | logger\error msgs.getTagParams.noFloatMs @typeName 18 | 19 | @checkPositive @value if @__tag.positive 20 | val /= @.__tag.scale 21 | return math.round val, precision 22 | 23 | return Time 24 | -------------------------------------------------------------------------------- /Aegisub/automation/include/l0/ASSFoundation/Section/Comment.moon: -------------------------------------------------------------------------------- 1 | return (ASS, ASSFInst, yutilsMissingMsg, createASSClass, Functional, LineCollection, Line, logger, SubInspector, Yutils) -> 2 | CommentSection = createASSClass "Section.Comment", ASS.Section.Text, {"value"}, {"string"} 3 | 4 | CommentSection.new = (value) => 5 | ASS.Section.Text.new @, value 6 | -- there's no way to escape a } in an ASS tag/comment section so just go ahead and nuke it 7 | @value = @value\gsub("}", "")\gsub "\\{", "{" 8 | return @ 9 | 10 | CommentSection.getString = => 11 | @typeCheck {@value} 12 | -- there's no way to escape a } in an ASS tag/comment section so just go ahead and nuke it 13 | return @value\gsub("}", "")\gsub "{", "\\{" 14 | return CommentSection 15 | -------------------------------------------------------------------------------- /Aegisub/automation/include/l0/ASSFoundation/Section/Drawing.moon: -------------------------------------------------------------------------------- 1 | return (ASS, ASSFInst, yutilsMissingMsg, createASSClass, Functional, LineCollection, Line, logger, SubInspector, Yutils) -> 2 | DrawingSection = createASSClass "Section.Drawing", ASS.Draw.DrawingBase, {"contours","scale"}, 3 | {"table", ASS.Number}, {}, {ASS.Draw.DrawingBase, ASS.Tag.ClipVect} 4 | 5 | DrawingSection.getStyleTable = ASS.Section.Text.getStyleTable 6 | DrawingSection.getEffectiveTags = ASS.Section.Text.getEffectiveTags 7 | DrawingSection.getTagString = nil 8 | 9 | getTagParams = DrawingSection.getTagParams 10 | DrawingSection.getTagParams = () => 11 | scale, commands = getTagParams @ 12 | return commands or scale 13 | DrawingSection.getString = DrawingSection.getTagParams -- TODO: remove in favor of toString 14 | DrawingSection.toString = DrawingSection.getTagParams 15 | 16 | DrawingSection.alignToOrigin = (mode) => 17 | mode = ASS.Tag.Align {mode or 7} 18 | ex = @getExtremePoints true 19 | cmdOff = ASS.Point ex.left.x, ex.top.y 20 | posOff = mode\getPositionOffset(ex.w, ex.h)\add cmdOff 21 | @sub cmdOff 22 | return posOff, ex 23 | 24 | DrawingSection.getClip = (inverse) => 25 | -- TODO: scale support 26 | effTags, ex = @parent\getEffectiveTags(-1, true, true, false).tags, @getExtremePoints! 27 | clip = ASS\createTag ASS.tagNames[ASS.Tag.ClipVect][inverse and 2 or 1], self 28 | anOff = effTags.align\getPositionOffset ex.w, ex.h 29 | return clip\add(effTags.position)\sub anOff 30 | 31 | return DrawingSection 32 | -------------------------------------------------------------------------------- /Aegisub/automation/include/l0/ASSFoundation/Tag/Align.moon: -------------------------------------------------------------------------------- 1 | return (ASS, ASSFInst, yutilsMissingMsg, createASSClass, Functional, LineCollection, Line, logger, SubInspector, Yutils) -> 2 | Align = createASSClass "Tag.Align", ASS.Tag.Indexed, {"value"}, {"number"}, {range: {1,9}, default: 5} 3 | 4 | Align.up = => @value < 7 and @add(3) or false 5 | Align.down = => @value > 3 and @sub(3) or false 6 | Align.left = => @value %3 != 1 and @sub(1) or false 7 | Align.right = => @value %3 != 0 and @add(1) or false 8 | 9 | Align.centerV = => 10 | if @value <= 3 then @up! 11 | elseif @value >= 7 then @down! 12 | 13 | Align.centerH = => 14 | if @value%3 == 1 then @right! 15 | elseif @value%3 == 0 then @left! 16 | 17 | Align.getSet = (pos) => 18 | val = @value 19 | set = { 20 | top: val >=7 21 | centerV: val > 3 and val < 7 22 | bottom: val <= 3 23 | left: val%3 == 1 24 | centerH: val%3 == 2 25 | right: val%3 == 0 26 | } 27 | return pos == nil and set or set[pos] 28 | 29 | Align.isTop = => @getSet "top" 30 | Align.isCenterV = => @getSet "centerV" 31 | Align.isBottom = => @getSet "bottom" 32 | Align.isLeft = => @getSet "left" 33 | Align.isCenterH = => @getSet "centerH" 34 | Align.isRight = => @getSet "right" 35 | 36 | Align.getPositionOffset = (w, h, refAlign = Align{7}) => 37 | if ASS\instanceOf w, ASS.Point, nil, true 38 | w, h = w\get! 39 | 40 | x, y = {w, 0, w/2}, {h, h/2, 0} 41 | off = ASS.Point{x[@value%3 + 1], y[math.ceil @value/3]} 42 | off\sub x[refAlign.value%3 + 1], y[math.ceil refAlign.value/3] 43 | 44 | return off 45 | 46 | Align.lerp = nil 47 | 48 | return Align 49 | -------------------------------------------------------------------------------- /Aegisub/automation/include/l0/ASSFoundation/Tag/Base.moon: -------------------------------------------------------------------------------- 1 | return (ASS, ASSFInst, yutilsMissingMsg, createASSClass, Functional, LineCollection, Line, logger, SubInspector, Yutils) -> 2 | {:list, :math, :string, :table, :unicode, :util, :re } = Functional 3 | 4 | msgs = { 5 | toString: { 6 | failedFormat: "Failed to convert tag '%s' to string using params (%s) and format '%s': %s" 7 | } 8 | } 9 | 10 | TagBase = createASSClass "TagBase", ASS.Base 11 | 12 | TagBase.commonOp = (method, callback, default, ...) => 13 | args = @getArgs {...}, default, false 14 | a = 1 15 | 16 | for valName in *@__meta__.order 17 | val = @[valName] 18 | if type(val) == "table" and val.class 19 | subArgCount = val.__meta__.rawArgCnt 20 | val[method] val, unpack args, a, a+subArgCount-1 21 | a += subArgCount 22 | else 23 | @[valName] = callback val, args[a] 24 | a += 1 25 | 26 | return @ 27 | 28 | TagBase.add = (...) => 29 | @commonOp "add", ((a,b) -> a + b), 0, ... 30 | 31 | TagBase.sub = (...) => 32 | @commonOp "sub", ((a,b) -> a - b), 0, ... 33 | 34 | TagBase.mul = (...) => 35 | @commonOp "mul", ((a,b) -> a * b), 1, ... 36 | 37 | TagBase.div = (...) => 38 | @commonOp "div", ((a,b) -> a / b), 1, ... 39 | 40 | TagBase.pow = (...) => 41 | @commonOp "pow", ((a,b) -> a ^ b), 1, ... 42 | 43 | TagBase.mod = (...) => 44 | @commonOp "mod", ((a,b) -> a % b), 1, ... 45 | 46 | TagBase.set = (...) => 47 | @commonOp "set", ((_,b) -> b), nil, ... 48 | 49 | TagBase.round = (...) => 50 | @commonOp "round", ((a,b) -> math.round(a,b)), nil, ... 51 | 52 | TagBase.ceil = => 53 | @commonOp "ceil", ((a) -> math.ceil a), nil 54 | 55 | TagBase.floor = => 56 | @commonOp "floor", ((a) -> math.floor a), nil 57 | 58 | TagBase.modify = (callback, ...) => 59 | @set callback @get ... 60 | 61 | TagBase.readProps = (args) => 62 | if args.tagProps 63 | @__tag[k] = v for k, v in pairs args.tagProps 64 | 65 | elseif type(args[1]) == "table" and args[1].instanceOf and args[1].instanceOf[@class] 66 | @__tag[k] = v for k, v in pairs args[1].__tag 67 | 68 | TagBase.getSignature = => 69 | return @__tag.signature or "default" 70 | 71 | TagBase.toString = () => 72 | format = ASS.tagMap[@__tag.name].signatures[@getSignature!].format 73 | tagString, errMsg = string.formatEx format, @getTagParams! 74 | unless tagString 75 | logger\error msgs.toString.failedFormat, 76 | @__tag.name, table.concat({@getTagParams!}, ', '), format, errMsg 77 | return tagString 78 | 79 | TagBase.__tostring = TagBase.toString 80 | 81 | -- legacy TODO: move the disable magic out and replace w/ toString 82 | TagBase.getTagString = (caller) => 83 | -- disabled tags or tags marked for deletion are not emitted 84 | return "" if @disabled or caller and caller.toRemove and caller.toRemove[@] 85 | return @toString! 86 | 87 | -- checks equality only of the relevant properties 88 | TagBase.equal = (a, b, acceptCompatible, ignoreTagNames) -> 89 | bVals = if type(b) != "table" 90 | {b} 91 | elseif not b.instanceOf 92 | b 93 | elseif acceptCompatible and a.compatible[b.class] 94 | {b\get!} 95 | elseif b.class == a.class and (a.__tag.name == b.__tag.name or ignoreTagNames) 96 | {b\get!} 97 | else return false 98 | 99 | aVals = {a\get!} 100 | return false if #aVals != #bVals 101 | 102 | for i, aVal in ipairs aVals 103 | if type(aVal) == "table" 104 | return false unless util.equals aVal, bVals[i], "table" 105 | else return false if aVal != bVals[i] 106 | 107 | return true 108 | 109 | return TagBase 110 | -------------------------------------------------------------------------------- /Aegisub/automation/include/l0/ASSFoundation/Tag/ClipRect.moon: -------------------------------------------------------------------------------- 1 | return (ASS, ASSFInst, yutilsMissingMsg, createASSClass, Functional, LineCollection, Line, logger, SubInspector, Yutils) -> 2 | ClipRect = createASSClass "Tag.ClipRect", ASS.Tag.Base, {"topLeft", "bottomRight"}, {ASS.Point, ASS.Point} 3 | 4 | ClipRect.new = (args) => 5 | left, top, right, bottom = unpack @getArgs args, 0, true 6 | @readProps args 7 | 8 | @topLeft = ASS.Point{left, top} 9 | @bottomRight = ASS.Point{right, bottom} 10 | @setInverse @__tag.inverse or false 11 | 12 | ClipRect.getTagParams = => 13 | @setInverse @__tag.inverse or false 14 | xTopLeft, yTopLeft = @topLeft\getTagParams! 15 | xBottomRight, yBottomRight = @bottomRight\getTagParams! 16 | return xTopLeft, yTopLeft, xBottomRight, yBottomRight 17 | 18 | ClipRect.getVect = => 19 | vect = ASSFInst\createTag ASS.tagNames[ASS.Tag.ClipVect][@__tag.inverse and 2 or 1] 20 | return vect\drawRect @topLeft, @bottomRight 21 | 22 | ClipRect.getDrawing = (trimDrawing, pos, an) => 23 | if ASS\instanceOf pos, ASS.TagList 24 | pos, an = pos.tags.position, pos.tags.align 25 | 26 | unless pos and an 27 | if @parent and @parent.parent 28 | effTags = @parent.parent\getEffectiveTags(-1, true, true, false).tags 29 | pos, an = pos or effTags.position, an or effTags.align 30 | 31 | return @getVect!\getDrawing trimDrawing, pos, an 32 | 33 | ClipRect.lerp = (a, b, t) -> 34 | c = a\copy! 35 | c.topLeft = a.topLeft\lerp b.topLeft, t 36 | c.bottomRight = a.bottomRight\lerp b.bottomRight, t 37 | 38 | ClipRect.setInverse = (state = true) => 39 | @__tag.inverse = state 40 | @__tag.name = state and "iclip_rect" or "clip_rect" 41 | return state 42 | 43 | ClipRect.toggleInverse = => @setInverse not self.__tag.inverse -- TODO: rename to invert() 44 | 45 | return ClipRect 46 | -------------------------------------------------------------------------------- /Aegisub/automation/include/l0/ASSFoundation/Tag/ClipVect.moon: -------------------------------------------------------------------------------- 1 | return (ASS, ASSFInst, yutilsMissingMsg, createASSClass, Functional, LineCollection, Line, logger, SubInspector, Yutils) -> 2 | ClipVect = createASSClass "Tag.ClipVect", ASS.Draw.DrawingBase, {"commands", "scale"}, 3 | {"table", ASS.Number}, {}, {ASS.Draw.DrawingBase} 4 | 5 | msgs = { 6 | getDrawing: { 7 | badPosition: "argument position must be an %d or a compatible object, got a %s." 8 | badAlign: "argument align must be an %d or a compatible object, got a %s." 9 | } 10 | } 11 | 12 | ClipVect.toString = ASS.Tag.Base.toString 13 | ClipVect.__toString = ASS.Tag.Base.toString 14 | 15 | ClipVect.setInverse = (state = true) => 16 | @__tag.inverse = state 17 | @__tag.name = state and "iclip_vect" or "clip_vect" 18 | return state 19 | 20 | ClipVect.toggleInverse = => @setInverse not @__tag.inverse 21 | 22 | ClipVect.getSignature = => 23 | @__tag.signature = if @scale\equal 1 -- TODO: remove legacy property 24 | "default" 25 | else "scale" 26 | return @__tag.signature 27 | 28 | ClipVect.getDrawing = (trimDrawing, pos, an) => 29 | if ASS\instanceOf pos, ASS.TagList 30 | pos, an = pos.tags.position, pos.tags.align 31 | 32 | unless pos and an 33 | if @parent and @parent.parent 34 | effTags = @parent.parent\getEffectiveTags(-1, true, true, false).tags 35 | pos, an = pos or effTags.position, an or effTags.align 36 | elseif not an 37 | an = ASS.Tag.Align{7} 38 | 39 | posType = type pos 40 | logger\assert not pos or ASS\instanceOf(pos, ASS.Point, nil, true), msgs.getDrawing.badPosition, 41 | ASS.Point.typeName, posType == "table" and pos.typeName or posType 42 | logger\assert ASS\instanceOf(an, ASS.Tag.Align), msgs.getDrawing.badAlign, 43 | ASS.Tag.Align.typeName, posType =="table" and an.typeName or type an 44 | 45 | drawing = ASS.Section.Drawing{@} 46 | extremePoints = @getExtremePoints! 47 | -- width and height of a drawing are always determined by the extreme points 48 | -- in the drawing, not the actual bounding box 49 | anOffset = an\getPositionOffset extremePoints.w, extremePoints.h 50 | 51 | if trimDrawing or not pos 52 | topLeft = ASS\createTag "position", @getBounds![1] 53 | drawing\sub topLeft 54 | return drawing, topLeft\add anOffset 55 | else return drawing\add(anOffset)\sub pos 56 | 57 | return ClipVect 58 | -------------------------------------------------------------------------------- /Aegisub/automation/include/l0/ASSFoundation/Tag/Color.moon: -------------------------------------------------------------------------------- 1 | return (ASS, ASSFInst, yutilsMissingMsg, createASSClass, Functional, LineCollection, Line, logger, SubInspector, Yutils) -> 2 | {:list, :math, :string, :table, :unicode, :util, :re } = Functional 3 | Color = createASSClass "Tag.Color", ASS.Tag.Base, {"r","g","b"}, {ASS.Hex, ASS.Hex, ASS.Hex} 4 | 5 | Color.new = (args) => 6 | b, g, r = unpack @getArgs args, nil, true 7 | @readProps args 8 | @r, @g, @b = ASS.Hex(r), ASS.Hex(g), ASS.Hex(b) 9 | 10 | Color.addHSV = (h, s, v) => 11 | ho, so, vo = @getHSV! 12 | return @set util.HSV_to_RGB ho+h, util.clamp(so+s, 0, 1), util.clamp vo+v, 0, 1 13 | 14 | Color.applyHSV = (filter) => 15 | ho, so, vo = @getHSV! 16 | h, s, v = filter ho, so, vo, @ 17 | return @set util.HSV_to_RGB h, util.clamp(s, 0, 1), util.clamp v, 0, 1 18 | 19 | Color.fromHSV = (h, s, v) -> 20 | color = Color! 21 | color\addHSV h, s, v 22 | return color 23 | 24 | Color.getHSV = => util.RGB_to_HSV @r\get!, @g\get!, @b\get! 25 | 26 | Color.getTagParams = => @b\getTagParams!, @g\getTagParams!, @r\getTagParams! 27 | 28 | Color.lerp = (a, b, t) -> 29 | c = a\copy! 30 | return c\applyHSV (ha, sa, va) -> 31 | hb, sb, vb = b\getHSV! 32 | return ha + (hb - ha)*t, sa + (sb - sa)*t, va + (vb - va)*t 33 | 34 | return Color 35 | -------------------------------------------------------------------------------- /Aegisub/automation/include/l0/ASSFoundation/Tag/Fade.moon: -------------------------------------------------------------------------------- 1 | return (ASS, ASSFInst, yutilsMissingMsg, createASSClass, Functional, LineCollection, Line, logger, SubInspector, Yutils) -> 2 | {:list, :math, :string, :table, :unicode, :util, :re} = Functional 3 | 4 | Fade = createASSClass "Tag.Fade", ASS.Tag.Base, 5 | {"inDuration", "outDuration", "inStartTime", "outStartTime", "inAlpha", "midAlpha", "outAlpha"}, 6 | {ASS.Duration, ASS.Duration, ASS.Time, ASS.Time, ASS.Hex, ASS.Hex, ASS.Hex} 7 | 8 | Fade.new = (args) => 9 | @readProps args 10 | if args.raw and @__tag.name == "fade" -- \fade(,,,,,,) 11 | a, r, num = {}, args.raw, tonumber 12 | a[1], a[2], a[3], a[4] = num(r[5])-num(r[4]), num(r[7])-num(r[6]), r[4], r[6] 13 | -- avoid having alpha values automatically parsed as hex strings 14 | a[5], a[6], a[7] = num(r[1]), num(r[2]), num(r[3]) 15 | args.raw = a 16 | 17 | inDuration, outDuration, inStartTime, outStartTime, inAlpha, midAlpha, outAlpha = unpack @getArgs args, 18 | {0, 0, math.nan, math.nan, 255, 0, 255}, true 19 | 20 | @inDuration = ASS.Duration {inDuration} 21 | @outDuration = ASS.Duration {outDuration} 22 | @inStartTime = ASS.Time {inStartTime} 23 | @outStartTime = ASS.Time {outStartTime} 24 | @inAlpha = ASS.Hex {inAlpha} 25 | @midAlpha = ASS.Hex {midAlpha} 26 | @outAlpha = ASS.Hex {outAlpha} 27 | 28 | return @ 29 | 30 | Fade.getTagParams = => 31 | if @__tag.name == "fade_simple" 32 | return @inDuration\getTagParams!, @outDuration\getTagParams! 33 | 34 | t1, t3 = @inStartTime\getTagParams!, @outStartTime\getTagParams! 35 | inDuration, outDuration = @inDuration\getTagParams!, @outDuration\getTagParams! 36 | t2 = t1 + inDuration 37 | t4 = t3 + outDuration 38 | @checkPositive inDuration, outDuration 39 | return @inAlpha\getTagParams!, @midAlpha\getTagParams!, @outAlpha\getTagParams!, t1, math.max(t2, t1), t3, math.max(t4, t3) 40 | 41 | -- TODO: add method to convert between fades by supplying a line duration 42 | 43 | return Fade 44 | -------------------------------------------------------------------------------- /Aegisub/automation/include/l0/ASSFoundation/Tag/Indexed.moon: -------------------------------------------------------------------------------- 1 | return (ASS, ASSFInst, yutilsMissingMsg, createASSClass, Functional, LineCollection, Line, logger, SubInspector, Yutils) -> 2 | Indexed = createASSClass "Tag.Indexed", ASS.Number, {"value"}, {"number"}, {precision: 0, positive: true} 3 | Indexed.cycle = (down) => 4 | min, max = @__tag.range[1], @__tag.range[2] 5 | if down then 6 | return @value <= min and @set(max) or @add -1 7 | else 8 | return @value >= max and @set(min) or @add 1 9 | 10 | Indexed.lerp = nil 11 | 12 | return Indexed 13 | -------------------------------------------------------------------------------- /Aegisub/automation/include/l0/ASSFoundation/Tag/Move.moon: -------------------------------------------------------------------------------- 1 | return (ASS, ASSFInst, yutilsMissingMsg, createASSClass, Functional, LineCollection, Line, logger, SubInspector, Yutils) -> 2 | Move = createASSClass "Tag.Move", ASS.Tag.Base, {"startPos", "endPos", "startTime", "endTime"}, {ASS.Point, ASS.Point, ASS.Time, ASS.Time} 3 | 4 | msgs = { 5 | getTagParams: { 6 | endsBeforeStart: "move times must evaluate to t1 <= t2, got %d<=%d." 7 | } 8 | } 9 | 10 | Move.new = (args) => 11 | startX, startY, endX, endY, startTime, endTime = unpack @getArgs args, 0, true 12 | if startTime > endTime 13 | startTime, endTime = endTime, startTime 14 | 15 | @readProps args 16 | @startPos = ASS.Point {startX, startY} 17 | @endPos = ASS.Point {endX, endY} 18 | @startTime = ASS.Time {startTime} 19 | @endTime = ASS.Time {endTime} 20 | 21 | return @ 22 | 23 | Move.getSignature = => 24 | @__tag.signature = if @startTime\equal(0) and @endTime\equal(0) -- TODO: remove legacy property 25 | "simple" 26 | else "default" 27 | return @__tag.signature 28 | 29 | Move.getTagParams = => 30 | startX, startY = @startPos\getTagParams! 31 | endX, endY = @endPos\getTagParams! 32 | 33 | if @__tag.signature == "simple" 34 | return startX, startY, endX, endY 35 | 36 | t1, t2 = @startTime\getTagParams!, @endTime\getTagParams! 37 | logger\assert t1 <= t2, msgs.getTagParams.endsBeforeStart, t1, t2 38 | return startX, startY, endX, endY, t1, t2 39 | 40 | return Move 41 | -------------------------------------------------------------------------------- /Aegisub/automation/include/l0/ASSFoundation/Tag/String.moon: -------------------------------------------------------------------------------- 1 | return (ASS, ASSFInst, yutilsMissingMsg, createASSClass, Functional, LineCollection, Line, logger, SubInspector, Yutils) -> 2 | String = createASSClass "Tag.String", {ASS.Tag.Base, ASS.String}, {"value"}, {"string"} 3 | String.add, String.mul, String.div, String.pow, String.mod = String.append, nil, nil, nil, nil 4 | 5 | String.getTagParams = => 6 | @typeCheck {@value} 7 | return @value 8 | 9 | return String 10 | -------------------------------------------------------------------------------- /Aegisub/automation/include/l0/ASSFoundation/Tag/Toggle.moon: -------------------------------------------------------------------------------- 1 | return (ASS, ASSFInst, yutilsMissingMsg, createASSClass, Functional, LineCollection, Line, logger, SubInspector, Yutils) -> 2 | Toggle = createASSClass "Tag.Toggle", ASS.Tag.Base, {"value"}, {"boolean"} 3 | 4 | msgs = { 5 | toggle: { 6 | badState: "argument #1 (state) must be true, false or nil, got a %s." 7 | } 8 | } 9 | 10 | Toggle.new = (args) => 11 | @value = @getArgs(args, false, true)[1] 12 | @readProps args 13 | @typeCheck {@value} 14 | return @ 15 | 16 | Toggle.toggle = (state) => 17 | logger\assert type(state) == "boolean" or state == nil, msgs.toggle.badState, type state 18 | @value = state == nil and not @value or state 19 | return @value 20 | 21 | Toggle.getTagParams = => 22 | @typeCheck {@value} 23 | return @value and 1 or 0 24 | 25 | return Toggle 26 | -------------------------------------------------------------------------------- /Aegisub/automation/include/l0/ASSFoundation/Tag/Transform.moon: -------------------------------------------------------------------------------- 1 | return (ASS, ASSFInst, yutilsMissingMsg, createASSClass, Functional, LineCollection, Line, logger, SubInspector, Yutils) -> 2 | {:list, :math, :string, :table, :unicode, :util, :re } = Functional 3 | Transform = createASSClass "Transform", ASS.Tag.Base, {"tags", "startTime", "endTime", "accel"}, {ASS.Section.Tag, ASS.Time, ASS.Time, ASS.Number} 4 | 5 | msgs = { 6 | changeTagType: { 7 | invalidTransformSignature: "invalid transform signature '%s'." 8 | } 9 | getTagParams: { 10 | transformStartTimeGreaterEndTime: "transform start time must not be greater than the end time, got %d <= %d." 11 | } 12 | } 13 | 14 | Transform.new = (args) => 15 | @readProps args 16 | signature = @__tag.signature 17 | if args.raw 18 | r = {} 19 | switch signature 20 | when "accel" then r[1], r[4] = args.raw[2], args.raw[1] -- \t(,