Skip to content

Commit 5cce2d5

Browse files
authored
Merge pull request johnnoel#4 from Aeolun/master
Added writer for ASS files
2 parents 1cf7424 + d5f2bd0 commit 5cce2d5

File tree

11 files changed

+8258
-2
lines changed

11 files changed

+8258
-2
lines changed

src/ChaosTangent/ASS/Block/Block.php

100644100755
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ public function removeLine(Line $line)
9797
}
9898

9999
/**
100-
* @return array
100+
* @return Line[]
101101
*/
102102
public function getLines()
103103
{

src/ChaosTangent/ASS/Line/Line.php

100644100755
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,4 +160,8 @@ public function getValue()
160160
protected function doParse($value, array $mapping)
161161
{
162162
}
163+
164+
public function toString($mapping = []) {
165+
return $this->key.': '.$this->value;
166+
}
163167
}

src/ChaosTangent/ASS/Line/MappedLine.php

100644100755
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,25 @@ public function applyMapping($value, array $mapping)
5454
}
5555
}
5656

57+
/**
58+
* With a string value and an array mapping, map values to this class
59+
*
60+
* @param string $value
61+
* @param array $mapping
62+
*/
63+
public function reverseMapping($mapping)
64+
{
65+
$classMapping = $this->getMapping();
66+
67+
$string = '';
68+
foreach ($mapping as $attribute) {
69+
$id = $classMapping[$attribute];
70+
$string .= $this->{$id}.',';
71+
}
72+
73+
return trim($string, ',');
74+
}
75+
5776
/**
5877
* {@inheritDoc}
5978
*/
@@ -66,4 +85,12 @@ protected function doParse($value, array $mapping)
6685

6786
$this->applyMapping($value, $mapping);
6887
}
88+
89+
public function toString($mapping = []) {
90+
if (count($mapping)) {
91+
return $this->getKey() . ': ' . $this->reverseMapping($mapping);
92+
} else {
93+
return parent::toString();
94+
}
95+
}
6996
}

src/ChaosTangent/ASS/Reader.php

100644100755
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,5 +31,12 @@ public function fromFile($filename)
3131

3232
public function fromString($string)
3333
{
34+
$script = new Script($string);
35+
if (!$script->isASSScript()) {
36+
throw new InvalidScriptException($script, 'Passed string does not look like a script');
37+
}
38+
39+
$script->parse();
40+
return $script;
3441
}
3542
}

src/ChaosTangent/ASS/Script.php

100644100755
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ public function hasBlock($block)
157157
/**
158158
* Get blocks
159159
*
160-
* @return array An array of blocks
160+
* @return Block[] An array of blocks
161161
*/
162162
public function getBlocks()
163163
{

src/ChaosTangent/ASS/Writer.php

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<?php
2+
3+
namespace ChaosTangent\ASS;
4+
5+
use ChaosTangent\ASS\Exception\InvalidScriptException;
6+
use ChaosTangent\ASS\Line\Format;
7+
8+
/**
9+
* Advanced Sub Station Alpha file reader
10+
*
11+
* @author John Noel <[email protected]>
12+
* @package php-ass
13+
*/
14+
class Writer
15+
{
16+
const VERSION = '1.0.0';
17+
18+
public function toFile($filename, Script $script)
19+
{
20+
if (!file_exists($filename) || !is_writable($filename)) {
21+
throw new \InvalidArgumentException('Unable to write file: '.$filename);
22+
}
23+
24+
file_put_contents($filename, $this->toString($script));
25+
}
26+
27+
public function toString(Script $script)
28+
{
29+
$string = '';
30+
31+
foreach($script->getBlocks() as $block) {
32+
$string .= sprintf("[%s]\n", $block->getId());
33+
foreach($block->getLines() as $line) {
34+
$mapping = [];
35+
if ($line instanceof Format) {
36+
$mapping = $line->getMapping();
37+
}
38+
$value = $line->toString($mapping);
39+
$string .= sprintf("%s\n", $value);
40+
}
41+
}
42+
43+
return $string;
44+
}
45+
}

tests/ChaosTangent/ASS/ScriptTest.php

100644100755
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
<?php
22

3+
use ChaosTangent\ASS\Reader;
34
use ChaosTangent\ASS\Script;
45
use ChaosTangent\ASS\Exception\InvalidScriptException;
56
use ChaosTangent\ASS\Block\ScriptInfo;
7+
use ChaosTangent\ASS\Writer;
68

79
/**
810
* Script test
@@ -121,4 +123,34 @@ public function testIterator()
121123

122124
$this->assertContains($block, $script);
123125
}
126+
127+
/**
128+
* @dataProvider scriptFiles
129+
*/
130+
public function testReadWrite($file, $expectedResultFile)
131+
{
132+
$outputPath = __DIR__.'/../../scripts/'.$expectedResultFile;
133+
$expectedContent = file_get_contents($outputPath);
134+
135+
$reader = new Reader();
136+
$script = $reader->fromFile(__DIR__.'/../../scripts/'.$file);
137+
138+
$writer = new Writer();
139+
$newcontent = $writer->toString($script);
140+
141+
/*
142+
* Expected output is not exactly the same as input, since we remove
143+
* irrelevant information from the file (e.g. extra line feeds, comments and
144+
* code that might've been added by editors).
145+
*/
146+
$this->assertEquals($expectedContent, $newcontent);
147+
}
148+
149+
public function scriptFiles() {
150+
return [
151+
[ 'utf8.ass', 'utf8_output.ass' ],
152+
[ 'small.ass', 'small_output.ass' ],
153+
[ 'minimal.ass', 'minimal_output.ass' ]
154+
];
155+
}
124156
}

tests/scripts/large_output.ass

Lines changed: 7702 additions & 0 deletions
Large diffs are not rendered by default.

tests/scripts/minimal_output.ass

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
[Script Info]
2+
Title: Minimal script
3+
ScriptType: v4.00+
4+
WrapStyle: 0
5+
ScaledBorderAndShadow: yes
6+
PlayResX: 1280
7+
PlayResY: 720

tests/scripts/small_output.ass

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
[Script Info]
2+
Title: Default Aegisub file
3+
ScriptType: v4.00+
4+
WrapStyle: 0
5+
ScaledBorderAndShadow: yes
6+
YCbCr Matrix: TV.601
7+
PlayResX: 1280
8+
PlayResY: 720
9+
[V4+ Styles]
10+
Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding
11+
Style: ED_Romaji,Minion Pro Cond,48,&H00000000,&H000000FF,&H00FFFFFF,&H00000000,-1,0,0,0,100,100,0,0,1,2,0,7,40,40,32,1
12+
Style: ED_English,Minion Pro Cond,48,&H00000000,&H000000FF,&H00FFFFFF,&H00000000,-1,0,0,0,100,100,0,0,1,2,0,1,42,42,28,1
13+
[Events]
14+
Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
15+
Dialogue: 0,0:00:00.98,0:00:05.43,ED_English,,0,0,0,,{\fad(100,200)\blur5\c&H000010&\3c&H80A0C0&}My destiny,
16+
Dialogue: 0,0:00:05.42,0:00:10.56,ED_Romaji,,0,0,0,,{\fad(100,200)\blur5\c&H000010&\3c&H80A0C0&}sotto oshiete hoshii
17+
Dialogue: 0,0:00:05.43,0:00:10.57,ED_English,,0,0,0,,{\fad(100,200)\blur5\c&H000010&\3c&H80A0C0&}won't you tell me?
18+
Dialogue: 0,0:00:12.74,0:00:16.00,ED_Romaji,,0,0,0,,{\fad(100,200)\blur5\c&H000010&\3c&H80A0C0&}aenai
19+
Dialogue: 0,0:00:12.75,0:00:16.01,ED_English,,0,0,0,,{\fad(100,200)\blur5\c&H000010&\3c&H80A0C0&}But you're gone
20+
Dialogue: 0,0:00:17.05,0:00:21.43,ED_Romaji,,0,0,0,,{\fad(100,200)\blur5\c&H000010&\3c&H80A0C0&}ima wa tooi place to be
21+
Dialogue: 0,0:00:17.06,0:00:21.44,ED_English,,0,0,0,,{\fad(100,200)\blur5\c&H000010&\3c&H80A0C0&}in a place so far away
22+
Dialogue: 0,0:00:24.51,0:00:29.40,ED_Romaji,,0,0,0,,{\fad(100,200)\blur5\c&H000010&\3c&H80A0C0&}hitoribocchi todokanai
23+
Dialogue: 0,0:00:24.52,0:00:29.41,ED_English,,0,0,0,,{\fad(100,200)\blur5\c&H000010&\3c&H80A0C0&}Alone and never-reaching
24+
Dialogue: 0,0:00:29.97,0:00:35.55,ED_Romaji,,0,0,0,,{\fad(100,200)\blur5\c&H000010&\3c&H80A0C0&}oshietekureta the truth is free
25+
Dialogue: 0,0:00:29.98,0:00:35.56,ED_English,,0,0,0,,{\fad(100,200)\blur5\c&H000010&\3c&H80A0C0&}Yet you told me the truth is free
26+
Dialogue: 0,0:00:35.56,0:00:38.44,ED_English,,0,0,0,,{\fad(100,200)\blur5\c&H000010&\3c&H80A0C0&}I miss you
27+
Dialogue: 0,0:00:38.44,0:00:41.05,ED_English,,0,0,0,,{\fad(100,200)\blur5\c&H000010&\3c&H80A0C0&}I revere you
28+
Dialogue: 0,0:00:41.05,0:00:48.04,ED_English,,0,0,0,,{\fad(100,200)\blur5\c&H000010&\3c&H80A0C0&\t(0,1500,\c&H281E1D&\3c&HF9CFC2&)}You're my everything
29+
Dialogue: 0,0:00:48.91,0:00:54.27,ED_English,,0,0,0,,{\fad(100,200)\blur5\c&H281E1D&\3c&HF9CFC2&}I will follow you
30+
Dialogue: 0,0:00:54.26,0:01:00.22,ED_Romaji,,0,0,0,,{\fad(100,200)\blur5\c&H281E1D&\3c&HF9CFC2&}subete wa ano toki
31+
Dialogue: 0,0:00:54.27,0:01:00.23,ED_English,,0,0,0,,{\fad(100,200)\blur5\c&H281E1D&\3c&HF9CFC2&}For everything since then
32+
Dialogue: 0,0:01:00.23,0:01:05.89,ED_English,,0,0,0,,{\fad(100,200)\blur5\c&H281E1D&\3c&HF9CFC2&}You're my destiny
33+
Dialogue: 0,0:01:05.88,0:01:10.07,ED_Romaji,,0,0,0,,{\fad(100,200)\blur5\c&H281E1D&\3c&HF9CFC2&}tsuretette
34+
Dialogue: 0,0:01:05.89,0:01:10.08,ED_English,,0,0,0,,{\fad(100,200)\blur5\c&H281E1D&\3c&HF9CFC2&}So take me
35+
Dialogue: 0,0:01:10.07,0:01:16.82,ED_Romaji,,0,0,0,,{\fad(100,200)\blur5\c&H281E1D&\3c&HF9CFC2&}yakusoku no basho e
36+
Dialogue: 0,0:01:10.08,0:01:16.83,ED_English,,0,0,0,,{\fad(100,200)\blur5\c&H281E1D&\3c&HF9CFC2&}to our promised land

0 commit comments

Comments
 (0)