+2

Lập trình giúp chúng ta thoải mái hơn? (tiếp)

Tình hình là thời gian gần đây download phim trên torrent có vẻ khó khăn hơn rất nhiều, và subtitle tiếng Việt cho mấy phim cũ cũ lại càng ít đi, không hiểu cái thằng subscene nó xóa sub đi làm gì không biết :-s

Sau khi tìm được cái torrent nhiều seed, vất cả cắm máy, xong rồi lên subscene lại thấy không có cái sub nào vừa vặn T.T chỉ muốn đập bàn và hét lên >"< cái thì chậm hơn, cái thì nhanh hơn, cái thì chuẩn timing nhưng lại dịch không chuẩn. haizz, xem bằng sub English cũng được nhưng mà mình có cảm giác phim hay mà không có sub Việt giống như coca không được ướp lạnh mà đã vội vàng cho vào cốc đá ấy, vị không được đậm đà :-s

Ờ thì sub Việt dịch không hay thì vất luôn chứ còn gì, còn cái sub nhanh chậm thì có thể chế biến được. Lượn 1 hồi trên google thì có mấy phần mềm chỉnh sub, đọc đau cả đầu vì nó lằng nhằng quá (hoặc mình quá lười để làm), dùng chính cái MPC thì chỉnh lúc được lúc không, mà cái chính là nội dung cái sub vẫn bị lệch. Hừm, đã thế làm luôn cái tool sync lại cái sub, nhanh gọn trong 1 nốt. Mình thích cái gì cũng 1 nốt cho đời thanh thản.

Cần phải làm gì?

Có vẻ mục đích khá đơn giản, nên chỉ cần:

  • Load lại cái sub theo từng dòng.
  • Dòng nào quy định thời gian thì cộng hoặc trừ đi thời gian bị lệch.
  • Những dòng còn lại giữ nguyên.

Định dạng file sub

Có mấy loại gì đó, đuôi là srt hay ssa/ass, chúng ta quan tâm đến cái thằng srt thôi.

1
00:00:41,010 --> 00:00:43,010
Trans by OmegaQ and Alpha, sync by Alpha.

2
00:00:43,010 --> 00:00:46,100
<i>Hoa Kỳ giờ đây là 1 vùng đất hoang tàn.</i>

3
00:00:47,890 --> 00:00:49,810
<i>Bên trong nó là một thành phố.</i>

4
00:00:51,770 --> 00:00:54,690
<i>Phía ngoài những bức tường ranh giới
là hoang mạc.</i>

5
00:00:54,980 --> 00:00:56,730
<i>Một trái đất bị nguyền rủa.</i>

6
00:00:58,240 --> 00:01:01,570
<i>Bên trong những bức tường
là một thành phố bị nguyền rủa,</i>

7
00:01:01,820 --> 00:01:05,160
<i>trải dài từ Boston tới tận Washington DC.</i>

8
00:01:06,330 --> 00:01:09,000
<i>Một quang cảnh bằng
bê-tông không thể bị phá vỡ.</i>

Chúng ta có thể thấy mỗi 1 lời thoại được quy định bằng 3 dòng

  • Số thứ tự
  • Thời điểm bắt đầu xuất hiện và thời điểm biến mất
  • Nội dung lời thoại

Bắt tay vào làm

    public function subtitles()
    {
        $filename = 'test_sub.srt';
        $output = 'sync_sub.srt';
        $file = fopen($output, 'wb');
        $output = "\xEF\xBB\xBF" . $output;

        $lines = file($filename, FILE_IGNORE_NEW_LINES);
        $flag = 1;

        foreach ($lines as $key => $line) {
            $b = mb_convert_encoding($line, 'HTML-ENTITIES', 'UTF-8');

            if ((int)$b == $flag) {
                $flag++;
                fputs($file, $b . "\n");
                $a = $key + 1;
                $modify = self::changeTime($lines[$key + 1]);
            } else {
                if ($a == $key) {
                    fputs($file, $modify . "\n");
                } else {
                    fputs($file, $line . "\n");
                }
            }
        }

        fclose($file);
    }

Đoạn code trên dùng để load toàn bộ file theo từng dòng. Tưởng đơn giản nhưng có 1 vấn đề xảy ra là bị lỗi UTF-8, loay hoay mãi mới tìm được cách là chuyển định dạng của file sub về UTF-8 và thêm đoạn này vào:

 $b = mb_convert_encoding($line, 'HTML-ENTITIES', 'UTF-8');

thì sẽ hết bị lỗi 😄

Rồi, giờ ta sẽ làm thế nào để xác định dòng chứa thời gian. Để ý là dòng thời gian sẽ nằm dưới dòng số thứ tự, thế thì mình làm 1 cái biến flag, cho chạy từ 1, nếu cái flag đó bằng với dòng chứa số thứ tự thì tăng flag++ và dòng ngay sau đó là dòng chứa thời gian -> lấy ra và chế biến. Những dòng còn lại thì giữ nguyên.

À, cái vấn đề nữa là lúc mình ghi lại ra file output thì lại bị lỗi UTF-8 -_- haizz, tiếng Việt thật là khổ. Ờ nhưng mà không sao, lại mất 1 hồi tìm tòi thì chúng ta chỉ cần thêm dòng

 $output = "\xEF\xBB\xBF" . $output;

như phía trên kia là xong thôi, giờ thì chú tâm vào cái hàm changeTime nữa là xong.

Chỉnh lại thời gian

    public function changeTime($time) {
        $time = explode(' --> ', $time);
        $addTime = 85.995;//second
        $time0 = self::addTime($time[0], $addTime);
        $time1 = self::addTime($time[1], $addTime);

        return implode(' --> ', [$time0, $time1]);
    }

Ở trên mình cho thời gian cần thêm vào để sub chạy đúng là 85.995 giây để tăng độ khó cho game :v còn trên thực tế mà cái sub nào bị lệch như thế này thì vất đi chứ giữ lại làm gì :-s

00:00:43,010 --> 00:00:46,100

CHúng ta tách dòng này ra làm 2 mốc thời gian bằng ký tự --> và cộng thêm cho cả 2 mốc thời gian này 1 khoảng 85.995 giây. Và đó là công việc của thằng addTime(), mình chỉ có nhiệm vụ tách ra rồi nối lại thôi, không quan tâm tới việc của người khác.

Cộng thêm thời gian

00:00:43,010

Khỉ thật, lằng nhắng phết đấy nhưng mà mình làm xong rồi và viết lại thì thấy đơn giản lắm 😃) Đại ý là thế này, tách cái thằng trên thành giờ bình thường 00:00:43 và giờ micro giây 0.010.

Ta tách bằng dấu , rồi gán lại cái micro giây bằng dấu . xong rồi cộng với $addTime lấy phần dư gán lại vào micro giây này, còn phần thừa cộng tiếp vào cái giờ bình thường kia, chú ý lúc là string lúc là integer, hàm xử lý của nó như thế này:

    public function addTime($time, $addTime) {
        $explodeTime = explode(',', $time);
        $explodeTime[1] = +('0.' . $explodeTime[1]);
        $a = $explodeTime[1] + $addTime;

        $microTime = $a - floor($a);
        $addTime = floor($a);
        $normalTime = $explodeTime[0];
        $normalTimeArr = explode(':', $normalTime);
        $normalSecond = +$normalTimeArr[2] + $addTime;
        $normalMinute = +$normalTimeArr[1];
        $normalHour = +$normalTimeArr[0];

        if ($normalSecond > 59) {
            $xxx = (int)($normalSecond / 60);
            $normalSecond = $normalSecond - $xxx * 60;
            $normalMinute = $normalMinute + $xxx;

            if ($normalMinute > 59) {
                $xxx = (int)($normalMinute / 60);
                $normalMinute = $normalMinute - $xxx * 60;
                $normalHour = $normalHour + $xxx;
            }
        }

        $normalTime = implode(':', [
            $normalHour < 10 ? '0' . $normalHour : $normalHour,
            $normalMinute < 10 ? '0' . $normalMinute : $normalMinute,
            $normalSecond < 10 ? '0' . $normalSecond : $normalSecond,
        ]);

        $microTimeArr = explode('.', number_format($microTime, 3));

        return $normalTime . ',' . $microTimeArr[1];
    }

Có vẻ ghê gớm nhưng thật ra là ghê gớm thật. À, mà ko biết có ai băn khoăn cái đoạn

number_format($microTime, 3);
```

này không nhỉ? Khá là thú vị :D

### Kết quả

Subtile của phim `Dredd` đã được sync lại, chạy nhanh hơn `85.995` giây :-s

![1.JPG](https://images.viblo.asia/70cb76e3-6d73-4b62-8ea7-3836c0fcf0fe.jpg)

## Kết luận

- Hướng dẫn vừa rồi áp dụng cho cộng thêm thời gian cho sub chạy chậm, đối với sub chạy nhanh thì trừ đi thời gian, làm tương tự.
- Thêm form upload file nữa là ngon lành luôn.
- Cuối cùng là thưởng thức bộ phim thôi.:v


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí