-
Notifications
You must be signed in to change notification settings - Fork 0
/
sub.ls
553 lines (442 loc) · 14.4 KB
/
sub.ls
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
/*
#### sub ####
A handy-dandy script file for doing various subbing tasks.
You should read through this whole file and tweak accordingly
before you actually start using it. A lot of comments are included
to help you around.
Besides node.js, LiveScript and the npm packages, usage of this script
also requires that you have xdelta3 and mkvtoolnix in your PATH.
Using this assumes that you are using a specific kind of filenaming scheme
for your project files. It's probably best to demonstrate by example.
Any files marked with * are used by this script, so they're the
important bits as far as usage is concerned.
Note: You will never need to touch the subswap-generated scripts
manually - the only thing that matters for work is the
master script.
## Common Files ##
Show.00.premux.720p.mkv * - premux files
Show.00.premux.720p.ass * - master scripts
Show.00.fonts.zip * - all episode fonts in a zip
Show.00.chapters.xml * - chapter files
Show.00.release.lang.ass * - subswap-generated scripts
Show.00.keyframes.txt - keyframes
Show.00.wraw.720p.mkv - wraws
## Encoder Files ##
Show.00.CR.1080p.mkv * - (softsubbed) simulcast rips
Show.00/0.part.mkv * - encodes done in multiple parts
Show.00.mux.video.mkv * - final video for the episode
Show.00.mux.audio.mka * - final audio for the episode
Show.00.avs - the avs file
Show.00.chapters.qpfile - self-explanatory
Show.00.work.keyframes.avs - keyframe generation avs
Show.00.work.video-720p.avs - wraw video encoding avs
The "Show.00" part above is what's called "prefix" in commands
defined below. If you want to change that, you'll need to edit
all the prefix definitions accordingly. For example, if you had
all the episodes in their own subfolders, you'd change it to
"#num/#name.#num" and then you would run the script from the
parent directory (so that you only need one copy of it).
*/
### CONSTANTS ###
# Edit as appropriate for each show.
group = "" # group name used in releases.
irc = '' # IRC channel info for torrent comment, ie '#channel@irc.rizon.net'
name = "" # short work name eg. Usagi, Uchouten, etc.
show = "" # filename eg. Gochuumon wa Usagi Desu ka etc.
title = "" # mkv title name, eg. Is the Order a Rabbit?
episodes = titlify [ # episode titles
"Episode 1"
"Episode 2"
"Etc."
]
langs = { # subtitle track languages and names
eng: "English"
enm: "English (JP honorifics)"
}
# For single track shows just have the one you need.
# Note that you'll need to edit the target.mux function below too.
# Instructions can be found at the relevant part.
### REQUIRES ###
# Don't touch these.
require 'shelljs/global'
require! {
\buffer-crc32
\cutlass
\zpad
\optimist
\subswap
\unzip
\fs
\nt
}
crc = buffer-crc32
ass = cutlass
### SETUP ###
# Don't touch these either.
# font muxing related stuff
filename = /\/([^\/]+\.(?:ttf|otf|ttc))$/i
ext = /\.(ttf|otf|ttc)$/i
# helper functions
function titlify episodes
ret = {}
for title, index in episodes
key = index + 1
key = key < 10 and "0#key" or "#key"
ret[key] = title
ret
run = (cmd, callback) !->
cmd .= replace /\r\n|\r|\n/g ' '
# console.log cmd
code, output <-! exec cmd, {+async, -silent}
callback output, code
log = -> console~log ...
extract = (archive, target, next) !->
if typeof! target == \Function and !next
next = target
target = "./" + archive.replace /\.zip$/ ''
stream = fs.create-read-stream archive .pipe unzip.Extract path: target
stream.on \close (err) !->
if err then return next err
else return next void
# removes comment lines and inline comments from script
strip = (script) ->
lines = []
for line in script.events
if not line.comment
line.actor = ''
line.effect = ''
line.text = line.text.replace /\{[^\}\\]*\}/g ''
lines.push line
script.events = lines
script
# version global - unset by default for regular releases
vx = ""
# resolution global - set to 720p by default
res = "720p"
# command running code
target = {}
cmd = (command, queue) !->
if queue?length
next = zpad queue.shift!
cb = !-> cmd command, queue
if typeof! next is \String and range = next.match /(\d+)-(\d+)/
start = parse-int range.1, 10
end = parse-int range.2, 10
pre = [start to end]
queue = pre.concat queue
next = zpad queue.shift!
# console.log next, queue
target[command] next, cb
set-timeout (!->
argv = optimist.argv._
command = argv.shift!
cmd command, argv
), 0
### COMMANDS ###
# A lot of useful commands are included here by default,
# but you can also expand them with your own ones.
# To do so, simply add a new command like so:
#
# target.example = (num, next) !->
#
# prefix = "#name.#num"
#
# # do stuff here
#
# # all commands need to end with this
# next!
#
# Pre-defined commands follow below.
## `swaps`
# Pre-processes basic honorifics to swap syntax.
# Can be expanded freely, though you should only
# run this script once per episode script since
# it is NOT idempotent.
target.swaps = (num, next) !->
prefix = "#name.#num"
main = new ass.Script cat "#prefix.premux.#res.ass"
for line in main.events
t = line.text
t = t
# the actual swaps are done here with regex replacements
.replace /\s+/g ' '
.replace /\b-san\b/g '{**-san}'
.replace /\b-kun\b/g '{**-kun}'
.replace /\b-chan\b/g '{**-chan}'
.replace /\b-sama\b/g '{**-sama}'
.replace /\b-senpai\b/g '{**-senpai}'
.replace /\b-sensei\b/g '{**-sensei}'
# only apply the swaps to lines with styles
#that begin with Default or Alternative
if line.style.match /^(?:Default|Alternative)/
line.text = t
# write over the old script version with no swaps
main.to-ass!.to "#prefix.premux.#res.ass"
next!
## `subs`
# Same as above, but also extracts the script from a softsubbed simulcast rip.
# Also generates a plain text file for easy etherpad copypasting.
target.subs = (num, next) !->
prefix = "#name.#num"
# Before running this command for the first time, open up the script
# from the simulcast rip in Aegisub and look at the styles
# You should list all dialogue styles from the script here so that
# any other lines with any other styles will be considered signs
main-styles =
"show-main"
"show-overlap"
# I rename rips as Show.XX.CR/DAISUKI.1080p.mkv but you can edit this
# if you don't feel like doing that yourself or use another scheme
ep = (ls "#prefix.CR.*.mkv")?0
<-! run "mkvextract tracks #ep 2:#prefix.CR.raw.ass"
main = new ass.Script cat "#prefix.CR.raw.ass"
dialogue = []
signs = []
plain = []
for line in main.events
t = line.text
t = t
.replace /\s+/g ' '
.replace /\b-san\b/g '{**-san}'
.replace /\b-kun\b/g '{**-kun}'
.replace /\b-chan\b/g '{**-chan}'
.replace /\b-sama\b/g '{**-sama}'
.replace /\b-senpai\b/g '{**-senpai}'
.replace /\b-sensei\b/g '{**-sensei}'
# here we check that the current line
# has a dialogue style listed above
if (main-styles.index-of line.style) > -1
# CR likes to use styles with internal for italics
# so we can add {\i1} to the beginning of any lines
# to match up with CR's italics
if line.style.match /internal/
t = "{\\i1}" + t
# same for styles with "top" in the name
if line.style.match /top/
t = "{\\an8}" + t
# I generally have a style called DefaultTop
# to have 5px (at 720p) lower vertical margin
line.style = "DefaultTop"
else
line.style = "Default"
line.text = t
dialogue.push line
# lines that are considered sings will be preceded
# with a {TS XX:XX} timestamp and put at the top
# of the file for maximum pad convenience
else
ts = line.get-start-time!
ts-prefix = '{' + "TS #{zpad ts.mm}:#{zpad ts.ss}" + '}'
# t = t.replace /\{\\.*?\}/g ''
line.text = ts-prefix + t
line.style = "Sign"
signs.push line
main.events = signs.concat dialogue
for line in main.events
plain.push line.text
main.header {
"Title": "[#group] #show - #num"
"PlayResX": 1280
"PlayResY": 720
"YCbCr Matrix": "TV.709"
}
main.to-ass!.to "#prefix.CR.ass"
plain.join "\r\n" .to "#prefix.CR.txt"
next!
## `video`
# This and the following commands are mainly for encoder usage.
# `video` will mux a video encoded in multiple parts # into
# a single "Show.XX.mux.video.mkv" file.
target.video = (num, next) !->
prefix = "#name.#num"
parts = ls "./#prefix/*.part.mkv"
first-part = parts.shift!
cmd = """
mkvmerge -o "#prefix.mux.video.mkv"
--disable-track-statistics-tags
"#first-part"
"""
for part in parts
cmd += """
"+#part"
"""
console.log "Muxing video for episode #num..."
<-! run cmd
next!
## `video-skip`
# This simply skips the video muxing
# if it has already been ran before.
target.video-skip = (num, next) !->
if test \-e "#name.#num.mux.video.mkv" then return next!
<-! target.video num
next!
## `premux`
# This will do the actual premux.
# You can mux chapters in at this point already,
# but you can also leave that for the actual mux
# by moving the --chapters "#prefix.chapters.xml"
# part to the main muxing command below.
target.premux = (num, next) !->
prefix = "#name.#num"
<-! target.video-skip num
cmd = """
mkvmerge -o "#prefix.premux.#res.mkv"
--disable-track-statistics-tags
--language "0:und"
--track-name "0:H.264 (10-bit)"
--compression "0:none"
-d 0 -A -S -T --no-global-tags --no-chapters
"(" "#prefix.mux.video.mkv" ")"
--language "0:jpn"
--track-name "0:Japanese 2.0 AAC"
--compression "0:none"
-a 0 -D -S -T --no-global-tags --no-chapters
"(" "#prefix.mux.audio.mka" ")"
--chapters "#prefix.chapters.xml"
--title "#title - #num"
"""
console.log "Premuxing episode #num..."
<-! run cmd
next!
# Encoding-related commands end here.
## `mux`
# This is the main muxing command.
# Used for QC and release muxing.
target.mux = (num, next) !->
prefix = "#name.#num"
main = new ass.Script cat "#prefix.premux.#res.ass"
# do sort by time here so you can keep your master script nicely organized
main.sort!
# this is where the magic happens, * indicates the swaps to perform
scripts = subswap main, '*'
for lang, script of scripts
(strip script).to-ass!.to "#prefix.release.#lang.ass"
# if you're not going to use multiple scripts,
# you can simply simply comment out the above
# and uncomment the following line and adjust
# the lang part to what you defined in the
# langs constant up at the top.
/* main.to-ass!.to "#prefix.release.lang.ass" */
# unzip fonts
if test \-e "./#prefix.fonts/" then rm \-Rf "./#prefix.fonts/*"
<-! extract "#prefix.fonts.zip" "./#prefix.fonts/"
fonts = ls "./#prefix.fonts/*"
# release filename (without CRC) is defined here
# vx is for v2, v3, etc - it's not set by default
# you will need to edit various strings to change
# the filename scheme properly, places are marked
## FILENAME SCHEME ##
cmd = """
mkvmerge -o "[#group] #show - #num#vx (#res).mkv"
--disable-track-statistics-tags
"#prefix.premux.#res.mkv"
"""
for l, n of langs
cmd += """
--language "0:#l"
--track-name "0:#n"
"#prefix.release.#l.ass"
"""
for f in fonts
file = (f.match filename)?1
fext = (file.match ext)?1
mime = 'application/x-truetype-font'
cmd += """
--attachment-mime-type "#mime"
--attachment-name "#file"
--attach-file "#f"
"""
# MKV title is handled here
if not episodes[num]
# warn the user if no episode title is present
# and use just Show Title - 00 as the title
console.log "WARNING: No episode title present!"
cmd += """
--title "#title - #num"
"""
else
# otherwise mux with the actual episode title included
cmd += """
--title "#title - #num - #{episodes[num]}"
"""
# you can also add --chapters to the above
# if you mux chapters only at this point
console.log "Muxing episode #num#vx..."
<-! run cmd
next!
## `crc`
# CRC32 hash the episode mux and append it to the filename.
target.crc = (num, next) !->
## FILENAME SCHEME ##
file = "[#group] #show - #num#vx (#res)"
checksum = void
parts = <[ B KB MB GB ]>
size = 0
console.log "Hashing episode #num#vx..."
source = fs.create-read-stream "#file.mkv"
source.on \data (chunk) !->
if chunk
size += chunk.length
checksum := crc chunk, checksum
<-! source.on \end
text = checksum.to-string \hex .to-upper-case!
ext = 0
while size > 1024
size := size / 1024
ext++
log "Filesize: #{size.to-fixed 2} #{parts[ext]}, CRC32: #text"
## FILENAME SCHEME (the latter is how CRC32 is appended) ##
mv "./#file.mkv" "./#file [#text].mkv"
next!
## `patch`
# Creates an .xdelta patch from premux to release.
target.patch = (num, next) !->
premux = "#name.#num.premux.#res.mkv"
## FILENAME SCHEME ##
file = (ls "[#group] #show - #num#vx (#res)*.mkv")?0
console.log "Premux patching episode #num#vx..."
<-! run """xdelta3 -e -s #premux "#file" #name.#num#vx.mux.xdelta"""
next!
## `torrent`
# Creates a torrent file for the release mux.
target.torrent = (num, next) !->
## FILENAME SCHEME ##
input = (ls "[#group] #show - #num#vx*.mkv")?0
torrent = input + ".torrent"
tracker = "http://open.nyaatorrents.info:6544/announce"
opts = {
comment: irc
# trackers used in the torrent are defined here
# edit how you wish, but the first one should
# match the one defined above
announce-list: [
[new Buffer "http://open.nyaatorrents.info:6544/announce"]
[new Buffer "udp://open.demonii.com:1337/announce"]
[new Buffer "udp://tracker.openbittorrent.com:80/announce"]
[new Buffer "udp://tracker.publicbt.com:80/announce"]
]
}
console.log "Creating torrent for episode #num#vx..."
err, tor <-! nt.make-write torrent, tracker, "#__dirname", [input], opts
if err then throw err
next!
## `rel`
# Runs the release creation process.
target.rel = (num, next) !->
<-! target.mux num
<-! target.crc num
<-! target.patch num
<-! target.torrent num
next!
## `v2`
# Same as above, except run with version set to v2.
target.v2 = (num, next) !->
vx := "v2"
<-! target.rel num
next!
## `v3`
# Hopefully you won't have a need for this.
target.v3 = (num, next) !->
vx := "v3"
<-! target.rel num
next!