Completed
Push — master ( f56913...5e615d )
by Mantas
05:13
created

Subtitles::add()   A

Complexity

Conditions 4
Paths 2

Size

Total Lines 21
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 4

Importance

Changes 0
Metric Value
dl 0
loc 21
ccs 11
cts 11
cp 1
c 0
b 0
f 0
rs 9.0534
cc 4
eloc 13
nc 2
nop 3
crap 4
1
<?php namespace Done\Subtitles;
2
3
interface SubtitleContract {
4
5
    public static function convert($from_file_path, $to_file_path);
6
7
    public static function load($file_name_or_file_content, $extension = null); // load file
8
    public function save($file_name); // save file
9
    public function content($format); // output file content (instead of saving to file)
10
11
    public function add($start, $end, $text); // add one line or several
12
    public function remove($from, $till); // delete text from subtitles
13
    public function time($seconds); // add or subtract some amount of seconds from all times
14
15
    public function getInternalFormat();
16
    public function setInternalFormat(array $internal_format);
17
}
18
19
20
class Subtitles implements SubtitleContract {
0 ignored issues
show
Coding Style Compatibility introduced by
Each interface must be in a file by itself

Having each class in a dedicated file usually plays nice with PSR autoloaders and is therefore a well established practice. If you use other autoloaders, you might not want to follow this rule.

Loading history...
21
22
    protected $input;
23
    protected $input_format;
24
25
    protected $internal_format; // data in internal format (when file is converted)
26
27
    protected $converter;
28
    protected $output;
29
30 3
    public static function convert($from_file_path, $to_file_path)
31
    {
32 3
        self::load($from_file_path)->save($to_file_path);
33 3
    }
34
35 11
    public static function load($file_name_or_file_content, $extension = null)
36
    {
37 11
        if (strstr($file_name_or_file_content, "\n") === false) {
38 7
            return self::loadFile($file_name_or_file_content);
39
        } else {
40 4
            if (!$extension) {
41
                throw new \Exception('Specify extension');
42
            }
43 4
            return self::loadString($file_name_or_file_content, $extension);
44
        }
45
    }
46
47 3
    public function save($path)
48
    {
49 3
        $file_extension = self::fileExtension($path);
50 3
        $content = $this->content($file_extension);
51
52 3
        file_put_contents($path, $content);
53
54 3
        return $this;
55
    }
56
57 11
    public function add($start, $end, $text)
58
    {
59
        // @TODO validation
60
        // @TODO check subtitles to not overlap
61 11
        $this->internal_format[] = [
62 11
            'start' => $start,
63 11
            'end' => $end,
64 11
            'lines' => is_array($text) ? $text : [$text],
65
        ];
66 11
        usort($this->internal_format, function ($item1, $item2) {
67 4
            if ($item2['start'] == $item1['start']) {
68
                return 0;
69 4
            } elseif ($item2['start'] < $item1['start']) {
70
                return 1;
71
            } else {
72 4
                return -1;
73
            }
74 11
        });
75
76 11
        return $this;
77
    }
78
79 3
    public function remove($from, $till)
80
    {
81 3
        foreach ($this->internal_format as $k => $block) {
82 3
            if (($from < $block['start'] && $block['start'] < $till) || ($from < $block['end'] && $block['end'] < $till)) {
83 3
                unset($this->internal_format[$k]);
84
            }
85
        }
86
87 3
        $this->internal_format = array_values($this->internal_format); // reorder keys
88
89 3
        return $this;
90
    }
91
92 2
    public function time($seconds)
93
    {
94 2
        foreach ($this->internal_format as &$block) {
95 2
            $block['start'] += $seconds;
96 2
            $block['end'] += $seconds;
97
        }
98 2
        unset($block);
99
100 2
        return $this;
101
    }
102
103 8
    public function content($format)
104
    {
105 8
        $format = strtolower(trim($format, '.'));
106
107 8
        $converter = self::getConverter($format);
108 8
        $content = $converter->internalFormatToFileContent($this->internal_format);
109
110 8
        return $content;
111
    }
112
113
    // for testing only
114 14
    public function getInternalFormat()
115
    {
116 14
        return $this->internal_format;
117
    }
118
119
    // for testing only
120 2
    public function setInternalFormat(array $internal_format)
121
    {
122 2
        $this->internal_format = $internal_format;
123
124 2
        return $this;
125
    }
126
127
    // -------------------------------------- private ------------------------------------------------------------------
128
129 7
    private static function loadFile($path, $extension = null)
130
    {
131 7
        $string = file_get_contents($path);
132 7
        if (!$extension) {
133 7
            $extension = self::fileExtension($path);
134
        }
135
136 7
        return self::loadString($string, $extension);
137
    }
138
139 11
    private static function loadString($text, $extension)
140
    {
141 11
        $converter = new self;
142 11
        $converter->input = self::normalizeNewLines(self::removeUtf8Bom($text));
143
144 11
        $converter->input_format = $extension;
145
146 11
        $input_converter = self::getConverter($extension);
147 11
        $converter->internal_format = $input_converter->fileContentToInternalFormat($converter->input);
148
149 11
        return $converter;
150
    }
151
152 11
    public static function removeUtf8Bom($text)
153
    {
154 11
        $bom = pack('H*','EFBBBF');
155 11
        $text = preg_replace("/^$bom/", '', $text);
156
157 11
        return $text;
158
    }
159
160 15
    private static function getConverter($extension)
161
    {
162 15
        if ($extension == 'stl') {
163 2
            return new StlConverter();
164 15
        } elseif ($extension == 'vtt') {
165 2
            return new VttConverter();
166 13
        } elseif ($extension == 'srt') {
167 9
            return new SrtConverter();
168 4
        } elseif ($extension == 'sbv') {
169 2
            return new SbvConverter();
170 2
        } elseif ($extension == 'sub') {
171 2
            return new SubConverter();
172
        }
173
174
        throw new \Exception('unknown format');
175
    }
176
177 7
    private static function fileExtension($filename) {
178 7
        $parts = explode('.', $filename);
179 7
        $extension = end($parts);
180 7
        $extension = strtolower($extension);
181
182 7
        return $extension;
183
    }
184
185 11
    private static function normalizeNewLines($file_content)
186
    {
187 11
        $file_content = str_replace("\r\n", "\n", $file_content);
188 11
        $file_content = str_replace("\r", "\n", $file_content);
189
190 11
        return $file_content;
191
    }
192
}
193
194
// https://github.com/captioning/captioning has potential, but :(
195
// https://github.com/snikch/captions-php too small