GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — master ( ddf840...09a81b )
by Julien
02:59
created

File::count()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 4
rs 10
cc 1
eloc 2
nc 1
nop 0
1
<?php
2
3
namespace Captioning;
4
5
abstract class File implements FileInterface, \Countable
6
{
7
    const DEFAULT_ENCODING = 'UTF-8';
8
9
    const UNIX_LINE_ENDING    = "\n";
10
    const MAC_LINE_ENDING     = "\r";
11
    const WINDOWS_LINE_ENDING = "\r\n";
12
13
    /**
14
     * @var array
15
     */
16
    protected $cues;
17
18
    /**
19
     * @var string
20
     */
21
    protected $filename;
22
23
    /**
24
     * @var string
25
     */
26
    protected $encoding = self::DEFAULT_ENCODING;
27
28
    /**
29
     * @var bool
30
     */
31
    protected $useIconv;
32
33
    /**
34
     * @var string
35
     */
36
    protected $lineEnding;
37
38
    /**
39
     * @var string
40
     */
41
    protected $fileContent;
42
43
    /**
44
     * @var array
45
     */
46
    protected $stats;
47
48
    /**
49
     * File constructor.
50
     * @param null       $_filename
51
     * @param null       $_encoding
52
     * @param bool|false $_useIconv
53
     */
54
    public function __construct($_filename = null, $_encoding = null, $_useIconv = false)
55
    {
56
        $this->lineEnding = self::UNIX_LINE_ENDING;
57
58
        if ($_filename !== null) {
59
            $this->setFilename($_filename);
60
        }
61
62
        if ($_encoding !== null) {
63
            $this->setEncoding($_encoding);
64
        }
65
66
        $this->useIconv = $_useIconv;
67
68
        if ($this->getFilename() !== null) {
69
            $this->loadFromFile();
70
        }
71
72
        $this->stats = array(
73
            'tooSlow'        => 0,
74
            'slowAcceptable' => 0,
75
            'aBitSlow'       => 0,
76
            'goodSlow'       => 0,
77
            'perfect'        => 0,
78
            'goodFast'       => 0,
79
            'aBitFast'       => 0,
80
            'fastAcceptable' => 0,
81
            'tooFast'        => 0
82
        );
83
    }
84
85
    /**
86
     * @param string $_filename The filename
87
     * @return $this
88
     */
89
    public function setFilename($_filename)
90
    {
91
        $this->filename = file_exists($_filename) ? $_filename : null;
92
93
        return $this;
94
    }
95
96
    /**
97
     * @param string $_encoding
98
     * @return $this
99
     */
100
    public function setEncoding($_encoding)
101
    {
102
        $this->encoding = $_encoding;
103
104
        return $this;
105
    }
106
107
    /**
108
     * @param bool $_useIconv
109
     * @return $this
110
     */
111
    public function setUseIconv($_useIconv)
112
    {
113
        $this->useIconv = $_useIconv;
114
115
        return $this;
116
    }
117
118
    /**
119
     * @param string $_lineEnding
120
     */
121
    public function setLineEnding($_lineEnding)
122
    {
123
        $lineEndings = array(
124
            self::UNIX_LINE_ENDING,
125
            self::MAC_LINE_ENDING,
126
            self::WINDOWS_LINE_ENDING
127
        );
128
        if (!in_array($_lineEnding, $lineEndings)) {
129
            return;
130
        }
131
132
        $this->lineEnding = $_lineEnding;
133
134
        if ($this->getCuesCount() > 0) {
135
            foreach ($this->cues as $cue) {
136
                $cue->setLineEnding($this->lineEnding);
137
            }
138
        }
139
    }
140
141
    /**
142
     * @return string
143
     */
144
    public function getFilename()
145
    {
146
        return $this->filename;
147
    }
148
149
    /**
150
     * @return string
151
     */
152
    public function getFileContent()
153
    {
154
        return $this->fileContent;
155
    }
156
157
    /**
158
     * @return string
159
     */
160
    public function getEncoding()
161
    {
162
        return $this->encoding;
163
    }
164
165
    /**
166
     * @return bool|false
167
     */
168
    public function getUseIconv()
169
    {
170
        return $this->useIconv;
171
    }
172
173
    /**
174
     * @param integer $_index
175
     * @return Cue|null
176
     */
177
    public function getCue($_index)
178
    {
179
        return isset($this->cues[$_index]) ? $this->cues[$_index] : null;
180
    }
181
182
    /**
183
     * @return Cue|null
184
     */
185
    public function getFirstCue()
186
    {
187
        return isset($this->cues[0]) ? $this->cues[0] : null;
188
    }
189
190
    /**
191
     * @return Cue|null
192
     */
193
    public function getLastCue()
194
    {
195
        $count = count($this->cues);
196
197
        return ($count > 0) ? $this->cues[$count - 1] : null;
198
    }
199
200
    /**
201
     * @return array
202
     */
203
    public function getCues()
204
    {
205
        return $this->cues;
206
    }
207
208
    /**
209
     * @return integer
210
     */
211
    public function getCuesCount()
212
    {
213
        return count($this->cues);
214
    }
215
216
    /**
217
     * @param null $_filename
218
     * @return $this
219
     * @throws \Exception
220
     */
221
    public  function loadFromFile($_filename = null)
222
    {
223
        if ($_filename === null) {
224
            $_filename = $this->filename;
225
        } else {
226
            $this->filename = $_filename;
227
        }
228
229
        if (!file_exists($_filename)) {
230
            throw new \Exception('File "'.$_filename.'" not found.');
231
        }
232
233
        if (!($content = file_get_contents($this->filename))) {
234
            throw new \Exception('Could not read file content ('.$_filename.').');
235
        }
236
237
        $this->loadFromString($content);
238
239
        return $this;
240
    }
241
242
    /**
243
     * @param string $_str
244
     * @return $this
245
     */
246
    public function loadFromString($_str)
247
    {
248
        // Clear cues from previous runs
249
        $this->cues = array();
250
        $this->fileContent = $_str;
251
252
        $this->encode();
253
        $this->parse();
254
255
        return $this;
256
    }
257
258
    /**
259
     * Searches a word/expression and returns ids of the matched entries
260
     *
261
     * @param string $_word
262
     * @param boolean $_case_sensitive
263
     * @param boolean $_strict
264
     * @return array containing ids of entries
265
     */
266
    public function search($_word, $_case_sensitive = false, $_strict = false)
267
    {
268
        $list = array();
269
        $pattern = preg_quote($_word, '#');
270
271
        $pattern = str_replace(' ', '( |\r\n|\r|\n)', $pattern);
272
273
        if ($_strict) {
274
            $pattern = '($| |\r\n|\r|\n|\?|\!|\.|,  )'.$pattern.'(^| |\r\n|\r|\n|\?|\!|\.|,)';
275
        }
276
277
        $pattern = '#'.$pattern.'#';
278
279
        if (!$_case_sensitive) {
280
            $pattern .= 'i';
281
        }
282
283
        $i = 0;
284
        foreach ($this->cues as $cue) {
285
            if (preg_match($pattern, $cue->getText())) {
286
                $list[] = $i;
287
            }
288
            $i++;
289
        }
290
291
        return (count($list) > 0) ? $list : -1;
292
    }
293
294
    public function getCueFromStart($_start)
295
    {
296
        $cueClass = self::getExpectedCueClass($this);
297
        $start = is_int($_start) ? $_start : $cueClass::tc2ms($_start);
298
299
        $prev_stop = 0;
300
        $i = 0;
301
        foreach ($this->cues as $cue) {
302
            if (($start > $prev_stop && $start < $cue->getStart()) || ($start >= $cue->getStart() && $start < $cue->getStop())) {
303
                break;
304
            }
305
            $prev_stop = $cue->getStop();
306
            $i++;
307
        }
308
309
        return $i;
310
    }
311
312
    /**
313
     * Add a cue
314
     *
315
     * @param mixed  $_mixed An cue instance or a string representing the text
316
     * @param string $_start A timecode
317
     * @param string $_stop  A timecode
318
     *
319
     * @throws \Exception
320
     * @return File
321
     */
322
    public function addCue($_mixed, $_start = null, $_stop = null)
323
    {
324
        $fileFormat = self::getFormat($this);
325
326
        // if $_mixed is a Cue
327
        if (is_object($_mixed) && class_exists(get_class($_mixed)) && class_exists(__NAMESPACE__.'\Cue') && is_subclass_of($_mixed, __NAMESPACE__.'\Cue')) {
328
            $cueFormat = Cue::getFormat($_mixed);
329
            if ($cueFormat !== $fileFormat) {
330
                throw new \Exception("Can't add a $cueFormat cue in a $fileFormat file.");
331
            }
332
            $_mixed->setLineEnding($this->lineEnding);
333
            $this->cues[] = $_mixed;
334
        } else {
335
            $cueClass = self::getExpectedCueClass($this);
336
            $cue = new $cueClass($_start, $_stop, $_mixed);
337
            $cue->setLineEnding($this->lineEnding);
338
            $this->cues[] = $cue;
339
        }
340
341
        return $this;
342
    }
343
344
    /**
345
     * Removes a cue
346
     *
347
     * @param int $_index
348
     * @return File
349
     */
350
    public function removeCue($_index)
351
    {
352
        if (isset($this->cues[$_index])) {
353
            unset($this->cues[$_index]);
354
        }
355
356
        return $this;
357
    }
358
359
    /**
360
     * Sorts cues
361
     */
362
    public function sortCues()
363
    {
364
        if (count($this->cues) === 0) {
365
            return $this;
366
        }
367
368
        $tmp = array();
369
370
        $count = 0; // useful if 2 cues start at the same time code
371
        foreach ($this->cues as $cue) {
372
            $tmp[$cue->getStartMS().'.'.$count] = $cue;
373
            $count++;
374
        }
375
376
        ksort($tmp);
377
378
        $this->cues = array();
379
        foreach ($tmp as $cue) {
380
            $this->cues[] = $cue;
381
        }
382
383
        return $this;
384
    }
385
386
    /**
387
     * Converts timecodes based on the specified FPS ratio
388
     *
389
     * @param float $_old_fps
390
     * @param float $_new_fps
391
     * @return File
392
     */
393
    public function changeFPS($_old_fps, $_new_fps)
394
    {
395
        $cuesCount = $this->getCuesCount();
396
        for ($i = 0; $i < $cuesCount; $i++) {
397
            $cue = $this->getCue($i);
398
399
            $old_start = $cue->getStart();
400
            $old_stop  = $cue->getStop();
401
402
            $new_start = $old_start * ($_new_fps / $_old_fps);
403
            $new_stop  = $old_stop * ($_new_fps / $_old_fps);
404
405
            $cue->setStart($new_start);
406
            $cue->setStop($new_stop);
407
        }
408
409
        return $this;
410
    }
411
412
    /**
413
     * @param FileInterface $_file
414
     * @return $this
415
     * @throws \Exception
416
     */
417
    public function merge(FileInterface $_file)
418
    {
419
        if (!is_a($_file, get_class($this))) {
420
            throw new \Exception('Can\'t merge! Wrong format: '.$this->getFormat($_file));
421
        }
422
423
        $this->cues = array_merge($this->cues, $_file->getCues());
424
        $this->sortCues();
425
426
        return $this;
427
    }
428
429
    /**
430
     * Shifts a range of subtitles a specified amount of time.
431
     *
432
     * @param int $_time The time to use (ms), which can be positive or negative.
433
     * @param int $_startIndex The subtitle index the range begins with.
434
     * @param int $_endIndex The subtitle index the range ends with.
435
     */
436
    public function shift($_time, $_startIndex = null, $_endIndex = null)
437
    {
438
        if (!is_int($_time)) {
439
            return false;
440
        }
441
        if ($_time == 0) {
442
            return true;
443
        }
444
445
        if (null === $_startIndex) {
446
            $_startIndex = 0;
447
        }
448
        if (null === $_endIndex) {
449
            $_endIndex = $this->getCuesCount() - 1;
450
        }
451
452
        $startCue = $this->getCue($_startIndex);
453
        $endCue   = $this->getCue($_endIndex);
454
455
        //check subtitles do exist
456
        if (!$startCue || !$endCue) {
457
            return false;
458
        }
459
460
        for ($i = $_startIndex; $i <= $_endIndex; $i++) {
461
                $cue = $this->getCue($i);
462
                $cue->shift($_time);
463
        }
464
465
        return true;
466
    }
467
468
    /**
469
     * Auto syncs a range of subtitles given their first and last correct times.
470
     * The subtitles are first shifted to the first subtitle's correct time, and then proportionally
471
     * adjusted using the last subtitle's correct time.
472
     *
473
     * Based on gnome-subtitles (https://git.gnome.org/browse/gnome-subtitles/)
474
     *
475
     * @param int $_startIndex The subtitle index to start the adjustment with.
476
     * @param int $_startTime The correct start time for the first subtitle.
477
     * @param int $_endIndex The subtitle index to end the adjustment with.
478
     * @param int $_endTime The correct start time for the last subtitle.
479
     * @param bool $_syncLast Whether to sync the last subtitle.
480
     * @return bool Whether the subtitles could be adjusted
481
     */
482
    public function sync($_startIndex, $_startTime, $_endIndex, $_endTime, $_syncLast = true)
483
    {
484
        //set first and last subtitles index
485
        if (!$_startIndex) {
486
            $_startIndex = 0;
487
        }
488
        if (!$_endIndex) {
489
            $_endIndex = $this->getCuesCount() - 1;
490
        }
491
        if (!$_syncLast) {
492
            $_endIndex--;
493
        }
494
495
        //check subtitles do exist
496
        $startSubtitle = $this->getCue($_startIndex);
497
        $endSubtitle   = $this->getCue($_endIndex);
498
        if (!$startSubtitle || !$endSubtitle || ($_startTime >= $_endTime)) {
499
            return false;
500
        }
501
502
        $shift = $_startTime - $startSubtitle->getStartMS();
503
        $factor = ($_endTime - $_startTime) / ($endSubtitle->getStartMS() - $startSubtitle->getStartMS());
504
505
        /* Shift subtitles to the start point */
506
        if ($shift) {
507
            $this->shift($shift, $_startIndex, $_endIndex);
508
        }
509
510
        /* Sync timings with proportion */
511
        for ($index = $_startIndex; $index <= $_endIndex; $index++) {
512
            $cue = $this->getCue($index);
513
            $cue->scale($_startTime, $factor);
514
        }
515
516
        return true;
517
    }
518
519
    /**
520
     * @return $this
521
     */
522
    public function build()
523
    {
524
        $this->buildPart(0, $this->getCuesCount() - 1);
525
526
        return $this;
527
    }
528
529
    /**
530
     * Saves the file
531
     *
532
     * @param string $filename
533
     * @param bool $writeBOM
534
     */
535
    public function save($filename = null, $writeBOM = false)
536
    {
537
        if ($filename === null) {
538
            $filename = $this->filename;
539
        }
540
541
        if (trim($this->fileContent) == '') {
542
            $this->build();
543
        }
544
545
        $file_content = $this->fileContent;
546
        if (strtolower($this->encoding) != 'utf-8') {
547
            if ($this->useIconv) {
548
                $file_content = iconv('UTF-8', $this->encoding, $file_content);
549
            } else {
550
                $file_content = mb_convert_encoding($file_content, $this->encoding, 'UTF-8');
551
            }
552
        }
553
554
        if ($writeBOM) {
555
            $file_content = "\xef\xbb\xbf".$file_content;
556
        }
557
558
        $res = file_put_contents($filename, $file_content);
559
        if (!$res) {
560
            throw new \Exception('Unable to save the file.');
561
        }
562
    }
563
564
    /**
565
     * Computes reading speed statistics
566
     */
567
    public function getStats()
568
    {
569
        $this->stats = array(
570
            'tooSlow'        => 0,
571
            'slowAcceptable' => 0,
572
            'aBitSlow'       => 0,
573
            'goodSlow'       => 0,
574
            'perfect'        => 0,
575
            'goodFast'       => 0,
576
            'aBitFast'       => 0,
577
            'fastAcceptable' => 0,
578
            'tooFast'        => 0
579
        );
580
581
        $cuesCount = $this->getCuesCount();
582
        for ($i = 0; $i < $cuesCount; $i++) {
583
            $rs = $this->getCue($i)->getReadingSpeed();
584
585
            if ($rs < 5) {
586
                $this->stats['tooSlow']++;
587
            } elseif ($rs < 10) {
588
                $this->stats['slowAcceptable']++;
589
            } elseif ($rs < 13) {
590
                $this->stats['aBitSlow']++;
591
            } elseif ($rs < 15) {
592
                $this->stats['goodSlow']++;
593
            } elseif ($rs < 23) {
594
                $this->stats['perfect']++;
595
            } elseif ($rs < 27) {
596
                $this->stats['goodFast']++;
597
            } elseif ($rs < 31) {
598
                $this->stats['aBitFast']++;
599
            } elseif ($rs < 35) {
600
                $this->stats['fastAcceptable']++;
601
            } else {
602
                $this->stats['tooFast']++;
603
            }
604
        }
605
606
        return $this->stats;
607
    }
608
609
    /**
610
     * @param $_file
611
     * @return mixed
612
     */
613 View Code Duplication
    public static function getFormat(FileInterface $_file)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
614
    {
615
        if (!is_subclass_of($_file, __NAMESPACE__.'\File')) {
616
            throw new \InvalidArgumentException('Expected subclass of File');
617
        }
618
619
        $fullNamespace = explode('\\', get_class($_file));
620
        $tmp           = explode('File', end($fullNamespace));
621
622
        return $tmp[0];
623
    }
624
625
    /**
626
     * @param FileInterface $_file
627
     * @param bool|true     $_full_namespace
628
     * @return string
629
     */
630
    public static function getExpectedCueClass(FileInterface $_file, $_full_namespace = true)
631
    {
632
        $format = self::getFormat($_file).'Cue';
633
634
        if ($_full_namespace) {
635
            $tmp    = explode('\\', get_class($_file));
636
            array_pop($tmp);
637
            $format = implode('\\', $tmp).'\\'.$format;
638
        }
639
640
        return $format;
641
    }
642
643
    /**
644
     * @param string $_output_format
645
     * @return mixed
646
     */
647
    public function convertTo($_output_format)
648
    {
649
        $fileFormat = self::getFormat($this);
650
        $method     = strtolower($fileFormat).'2'.strtolower(rtrim($_output_format, 'File'));
651
652
        if (method_exists(new Converter(), $method)) {
653
            return Converter::$method($this);
654
        }
655
        return Converter::defaultConverter($this, $_output_format);
656
    }
657
658
    /**
659
     * Encode file content
660
     */
661
    protected function encode()
662
    {
663
        if ($this->useIconv) {
664
            $this->fileContent = iconv($this->encoding, 'UTF-8', $this->fileContent);
665
        } else {
666
            $this->fileContent = mb_convert_encoding($this->fileContent, 'UTF-8', $this->encoding);
667
        }
668
    }
669
670
    /**
671
     * @return array
672
     * @throws \Exception
673
     */
674
    protected function getFileContentAsArray()
675
    {
676
        if (empty($this->fileContent)) {
677
            $this->loadFromFile($this->filename);
678
        }
679
        $fileContent = str_replace( // So we change line endings to one format
680
            array(
681
                self::WINDOWS_LINE_ENDING,
682
                self::MAC_LINE_ENDING,
683
            ),
684
            self::UNIX_LINE_ENDING,
685
            $this->fileContent
686
        );
687
        $fileContentArray = explode(self::UNIX_LINE_ENDING, $fileContent); // Create array from file content
688
689
        return $fileContentArray;
690
    }
691
692
    /**
693
     * @param array $array
694
     * @return mixed
695
     */
696
    protected function getNextValueFromArray(array &$array)
697
    {
698
        $element = each($array);
699
        if (is_array($element)) {
700
            return $element['value'];
701
        }
702
        return false;
703
    }
704
705
    /**
706
     * @return int
707
     */
708
    public function count()
709
    {
710
        return $this->getCuesCount();
711
    }
712
}
713