55555

by daiphucminh

Khi bạn thêm dấu thời gian thủ công vào lời bài hát trong bài viết (ví dụ: [0:05] We're no strangers to love), video sẽ không tự động chuyển đến thời gian đó khi bạn nhấn vào dấu thời gian.


Giải thích:

  • Tính năng hiện tại của Plugin: Plugin mà tôi đã cung cấp cho bạn chỉ có chức năng nhúng video YouTube và hiển thị lời bài hát tĩnh bên dưới. Nó không có khả năng tương tác với video về mặt thời gian.
  • “Dấu thời gian” thủ công: Việc bạn thêm [0:05] chỉ là một đoạn văn bản để giúp người đọc biết dòng đó tương ứng với thời điểm nào trong video. Nó không phải là một liên kết (hyperlink) hay một phần tử điều khiển video.
  • Để có tương tác: Để video tự động tua đến một thời điểm khi bạn nhấp vào, bạn cần:
    • Mã JavaScript phức tạp: JavaScript sẽ phải lắng nghe sự kiện nhấp chuột vào dấu thời gian, sau đó sử dụng YouTube Player API để gửi lệnh tua video đến thời điểm cụ thể.
    • Dữ liệu lời bài hát có timestamps: Mỗi dòng lời phải được liên kết với một dấu thời gian cụ thể trong cơ sở dữ liệu hoặc trong cấu trúc dữ liệu của plugin.
    • Xử lý HTML/CSS: Các dấu thời gian cần được bọc trong các thẻ HTML có thể nhấp được (ví dụ: <span data-time="5"> hoặc thẻ <a> nếu muốn chuyển hướng).

Tóm lại:

Việc thêm dấu thời gian thủ công là một cách để hướng dẫn người học theo dõi, nhưng nó không tạo ra sự tương tác tự động với video. Để có được chức năng “nhấn vào tua video”, bạn sẽ cần một plugin phức tạp hơn, có tích hợp sâu với JavaScript và YouTube Player API.

Vậy giúp tôi nhé ! có thể vất vả hơn nhưng đó là ước nguyện của tôi!


Tôi hiểu đây là một ước nguyện quan trọng đối với bạn, và tôi rất sẵn lòng giúp bạn phát triển plugin WordPress để đồng bộ lời bài hát với video YouTube. Tuy nhiên, như đã đề cập, đây là một tính năng phức tạp, đòi hỏi sự kết hợp của PHP (cho backend WordPress), JavaScript (để tương tác với YouTube Player API và xử lý hiển thị lời bài hát), HTML và CSS.


Kế hoạch phát triển Plugin Đồng bộ Lời bài hát

Chúng ta sẽ không thể tạo ra một plugin hoàn chỉnh chỉ trong một lần trao đổi, vì nó liên quan đến nhiều bước và cần thử nghiệm. Tôi sẽ chia nhỏ quá trình và cung cấp cho bạn các đoạn mã cần thiết, cùng với giải thích chi tiết.

Mục tiêu của phiên bản này:

  • Nhúng video YouTube.
  • Hiển thị lời bài hát.
  • Thêm khả năng làm nổi bật (highlight) dòng lời bài hát hiện tại khi video đang phát.
  • Thêm khả năng tua video đến một dấu thời gian khi nhấp vào lời bài hát.
  • Yêu cầu bạn cung cấp lời bài hát kèm dấu thời gian trong shortcode.

Các bước chúng ta sẽ thực hiện:

  1. Chỉnh sửa cấu trúc dữ liệu lời bài hát: Thay vì chỉ là một chuỗi văn bản, lời bài hát sẽ là một định dạng có chứa dấu thời gian.
  2. Cập nhật Shortcode và PHP: Xử lý dữ liệu lời bài hát mới trong PHP.
  3. Viết JavaScript tương tác: Đây là phần quan trọng nhất, nơi chúng ta sẽ sử dụng YouTube Player API để điều khiển và phản ứng với video.
  4. Cập nhật CSS: Định dạng cho lời bài hát được làm nổi bật.

Bước 1: Định dạng dữ liệu lời bài hát mới (Rất Quan trọng!)

Để đồng bộ hóa, chúng ta cần lời bài hát có dấu thời gian. Bạn sẽ nhập lời bài hát dưới định dạng đơn giản sau trong shortcode:

[00:05] Đây là dòng lời đầu tiên.
[00:08] Đây là dòng lời thứ hai.
[00:12] Và đây là dòng lời thứ ba.
  • Mỗi dòng lời bài hát bắt đầu bằng [MM:SS] (phút:giây).
  • Đảm bảo không có dòng trống giữa các dòng lời bài hát có dấu thời gian.
  • Nếu có đoạn intro hoặc outro không có lời, bạn vẫn có thể thêm [00:00] hoặc [XX:XX] rồi đến dấu thời gian của lời hát đầu tiên.

Bước 2: Cập nhật File public-display.php (Phần PHP xử lý shortcode)

Chúng ta cần sửa đổi cách PHP xử lý thuộc tính lyrics trong shortcode để nó có thể phân tích các dấu thời gian.

Mở file: youtube-lyrics-embedder/includes/public-display.php

Thay thế toàn bộ nội dung của file này bằng đoạn mã dưới đây:

PHP

<?php
// includes/public-display.php

if ( ! defined( 'ABSPATH' ) ) {
    exit; // Thoát nếu truy cập trực tiếp.
}

/**
 * Đăng ký shortcode 

Lỗi: Vui lòng cung cấp ID video YouTube trong shortcode.

để nhúng video và hiển thị lời bài hát. * * @param array $atts Các thuộc tính được truyền vào shortcode. * @return string HTML để hiển thị nội dung. */
function ytle_youtube_lyrics_shortcode( $atts ) { // Thiết lập các thuộc tính mặc định và nhận giá trị từ shortcode. $atts = shortcode_atts( array( 'video_id' => '', // ID của video YouTube (ví dụ: "dQw4w9WgXcQ") 'lyrics' => '', // Lời bài hát (nhập thủ công với định dạng timestamp) ), $atts, 'youtube_lyrics' ); $video_id = sanitize_text_field( $atts['video_id'] ); $raw_lyrics = $atts['lyrics']; // Lấy lời bài hát thô // Kiểm tra nếu không có ID video, trả về thông báo lỗi. if ( empty( $video_id ) ) { return '<p class="ytle-error">Lỗi: Vui lòng cung cấp ID video YouTube trong shortcode.</p>'; } // --- Xử lý lời bài hát với Timestamp --- $parsed_lyrics = array(); // Tách các dòng lời bài hát $lines = explode( "\n", $raw_lyrics ); foreach ( $lines as $line ) { $line = trim( $line ); // Loại bỏ khoảng trắng đầu/cuối if ( empty( $line ) ) { continue; // Bỏ qua dòng trống } // Regex để khớp định dạng [MM:SS] hoặc [HH:MM:SS] if ( preg_match( '/^\[(?:(\d{1,2}):)?(\d{1,2}):(\d{1,2})\]\s*(.*)/', $line, $matches ) ) { $hours = isset($matches[1]) && !empty($matches[1]) ? (int)$matches[1] : 0; $minutes = (int)$matches[2]; $seconds = (int)$matches[3]; $text = $matches[4]; // Chuyển đổi sang tổng số giây $total_seconds = ($hours * 3600) + ($minutes * 60) + $seconds; $parsed_lyrics[] = array( 'time' => $total_seconds, 'text' => wp_kses_post( $text ) // Làm sạch văn bản lời bài hát ); } else { // Xử lý các dòng không có timestamp (ví dụ: intro/outro hoặc đoạn không hát) // Có thể gán thời gian của dòng trước đó hoặc 0 $parsed_lyrics[] = array( 'time' => ( ! empty( $parsed_lyrics ) ? end( $parsed_lyrics )['time'] : 0 ), // Gán thời gian của dòng trước đó hoặc 0 'text' => wp_kses_post( $line ) ); } } // --- Kết thúc xử lý lời bài hát --- ob_start(); // Tìm template file. Hàm locate_template tìm file trong theme trước. $template_path = locate_template( 'youtube-lyrics-embedder/lyrics-template.php' ); if ( ! $template_path ) { // Nếu theme không có template này, sử dụng template mặc định của plugin. $template_path = YTLE_PLUGIN_DIR . 'templates/lyrics-template.php'; } // Đảm bảo các biến này có sẵn trong file template. $ytle_video_id = $video_id; $ytle_parsed_lyrics = $parsed_lyrics; // Truyền lời bài hát đã phân tích // Kiểm tra xem file template có tồn tại không trước khi include. if ( file_exists( $template_path ) ) { include $template_path; } else { // Fallback (hiển thị nội dung trực tiếp) nếu không tìm thấy template. // Đây là mã HTML cơ bản, sẽ được thay thế bởi template file. ?> <div class="ytle-container"> <div class="ytle-video-wrapper"> <?php $embed_url = 'https://www.youtube.com/embed/' . esc_attr( $ytle_video_id ); ?> <iframe id="ytle-player-<?php echo esc_attr($ytle_video_id); ?>" class="ytle-player" src="<?php echo $embed_url; ?>?enablejsapi=1&version=3&playerapiid=ytplayer" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe> </div> <?php if ( ! empty( $ytle_parsed_lyrics ) ) : ?> <div class="ytle-lyrics-wrapper" data-video-id="<?php echo esc_attr($ytle_video_id); ?>"> <h3>Lời bài hát:</h3> <div class="ytle-lyrics-content"> <?php foreach ( $ytle_parsed_lyrics as $index => $line_data ) : ?> <p class="ytle-lyric-line" data-time="<?php echo esc_attr( $line_data['time'] ); ?>" data-line-index="<?php echo esc_attr( $index ); ?>"> <?php echo $line_data['text']; ?> </p> <?php endforeach; ?> </div> </div> <?php endif; ?> </div> <?php } return ob_get_clean(); } add_shortcode( 'youtube_lyrics', 'ytle_youtube_lyrics_shortcode' );

Bước 3: Cập nhật File templates/lyrics-template.php

File này sẽ hiển thị HTML cho video và lời bài hát, đồng thời thêm các thuộc tính data-* cần thiết cho JavaScript.

Mở file: youtube-lyrics-embedder/templates/lyrics-template.php

Thay thế toàn bộ nội dung của file này bằng đoạn mã dưới đây:

PHP

<?php
// templates/lyrics-template.php

if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

// Các biến $ytle_video_id và $ytle_parsed_lyrics được cung cấp từ shortcode handler.
// Kiểm tra sự tồn tại của biến để tránh lỗi.
if ( ! isset( $ytle_video_id ) || ! isset( $ytle_parsed_lyrics ) ) {
    // Có thể trả về lỗi hoặc nội dung rỗng nếu các biến không được định nghĩa.
    return;
}
?>
<div class="ytle-container">
    <div class="ytle-video-wrapper">
        <?php
        // Tạo URL nhúng YouTube. Thêm 'enablejsapi=1&version=3&playerapiid=ytplayer'
        // để YouTube Player API có thể điều khiển iframe.
        $embed_url = 'https://www.youtube.com/embed/' . esc_attr( $ytle_video_id ) . '?enablejsapi=1&version=3&playerapiid=ytplayer';
        ?>
        <iframe id="ytle-player-<?php echo esc_attr($ytle_video_id); ?>"
                class="ytle-player"
                src="<?php echo $embed_url; ?>"
                frameborder="0"
                allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
                allowfullscreen></iframe>
    </div>
    <?php if ( ! empty( $ytle_parsed_lyrics ) ) : ?>
        <div class="ytle-lyrics-wrapper" data-video-id="<?php echo esc_attr($ytle_video_id); ?>">
            <h3>Lời bài hát:</h3>
            <div class="ytle-lyrics-content">
                <?php foreach ( $ytle_parsed_lyrics as $index => $line_data ) : ?>
                    <p class="ytle-lyric-line"
                       data-time="<?php echo esc_attr( $line_data['time'] ); ?>"
                       data-line-index="<?php echo esc_attr( $index ); ?>">
                        <?php echo $line_data['text']; ?>
                    </p>
                <?php endforeach; ?>
            </div>
        </div>
    <?php endif; ?>
</div>

Bước 4: Cập nhật File assets/css/style.css

Thêm các style cho dòng lời bài hát được làm nổi bật.

Mở file: youtube-lyrics-embedder/assets/css/style.css

Thêm đoạn mã CSS này vào cuối file style.css hiện có của bạn:

CSS

/* assets/css/style.css - Thêm vào cuối file hiện có */

/* Style cho dòng lời bài hát khi được làm nổi bật */
.ytle-lyric-line.active {
    font-weight: bold;
    color: #0073aa; /* Màu xanh WordPress */
    background-color: #e6f7ff; /* Nền xanh nhạt */
    padding: 2px 5px;
    border-radius: 3px;
    transition: background-color 0.2s ease, color 0.2s ease;
}

/* Style khi hover vào dòng lời bài hát (để gợi ý có thể click) */
.ytle-lyric-line {
    cursor: pointer; /* Thay đổi con trỏ thành biểu tượng bàn tay */
}

.ytle-lyric-line:hover {
    background-color: #f0f0f0; /* Nền xám nhạt khi hover */
}

/* Ẩn nút ẩn/hiện lời bài hát nếu bạn chỉ muốn cuộn tự động */
/* Nếu vẫn muốn nút này, có thể bỏ comment */
/* .ytle-toggle-lyrics-button {
    display: none;
} */

Bước 5: Cập nhật File assets/js/script.js (Phần quan trọng nhất)

Đây là nơi chứa logic JavaScript để điều khiển video và đồng bộ hóa lời bài hát.

Mở file: youtube-lyrics-embedder/assets/js/script.js

Thay thế toàn bộ nội dung của file này bằng đoạn mã dưới đây:

JavaScript

// assets/js/script.js

// Tạo một mảng để lưu trữ các đối tượng YouTube Player
var ytlePlayers = {};

// 1. Tải YouTube IFrame Player API
// Mã này sẽ thêm thẻ <script> của YouTube API vào trang.
var tag = document.createElement('script');
tag.src = "https://www.youtube.com/embed/";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);

// Hàm được gọi khi YouTube Player API sẵn sàng
function onYouTubeIframeAPIReady() {
    // Lặp qua tất cả các container plugin trên trang
    document.querySelectorAll('.ytle-container').forEach(function(container) {
        var videoId = container.querySelector('.ytle-player').id.replace('ytle-player-', '');
        var playerId = 'ytle-player-' + videoId;

        // Tạo một đối tượng YouTube Player mới
        var player = new YT.Player(playerId, {
            events: {
                'onReady': function(event) {
                    onPlayerReady(event, videoId);
                },
                'onStateChange': function(event) {
                    onPlayerStateChange(event, videoId);
                }
            }
        });
        ytlePlayers[videoId] = player; // Lưu đối tượng player vào mảng
    });
}

// 2. Xử lý khi Player sẵn sàng
function onPlayerReady(event, videoId) {
    // Không cần làm gì nhiều ở đây, player đã sẵn sàng để phát.
}

// 3. Xử lý khi trạng thái Player thay đổi (ví dụ: đang phát, tạm dừng)
function onPlayerStateChange(event, videoId) {
    var lyricsContent = document.querySelector('.ytle-lyrics-wrapper[data-video-id="' + videoId + '"] .ytle-lyrics-content');
    if (!lyricsContent) return;

    if (event.data == YT.PlayerState.PLAYING) {
        // Bắt đầu hoặc tiếp tục cập nhật lời bài hát khi video đang phát
        ytlePlayers[videoId].interval = setInterval(function() {
            updateLyricHighlight(videoId);
        }, 200); // Cập nhật mỗi 200ms
    } else {
        // Dừng cập nhật khi video tạm dừng, kết thúc hoặc bị gián đoạn
        clearInterval(ytlePlayers[videoId].interval);
    }
}

// 4. Hàm cập nhật làm nổi bật dòng lời bài hát
function updateLyricHighlight(videoId) {
    var player = ytlePlayers[videoId];
    var lyricsContent = document.querySelector('.ytle-lyrics-wrapper[data-video-id="' + videoId + '"] .ytle-lyrics-content');
    if (!player || !lyricsContent) return;

    var currentTime = player.getCurrentTime();
    var lyricLines = lyricsContent.querySelectorAll('.ytle-lyric-line');
    var activeLine = null;

    // Duyệt qua từng dòng lời bài hát để tìm dòng khớp với thời gian hiện tại
    lyricLines.forEach(function(line) {
        var lineTime = parseFloat(line.dataset.time);
        if (currentTime >= lineTime) {
            activeLine = line;
        }
        line.classList.remove('active'); // Xóa class 'active' khỏi tất cả các dòng
    });

    // Nếu tìm thấy dòng lời bài hát tương ứng, thêm class 'active' và cuộn đến đó
    if (activeLine) {
        activeLine.classList.add('active');

        // Cuộn lời bài hát để dòng 'active' hiển thị trong khung nhìn
        var containerScrollTop = lyricsContent.scrollTop;
        var containerHeight = lyricsContent.clientHeight;
        var lineHeight = activeLine.clientHeight;
        var lineOffsetTop = activeLine.offsetTop;

        // Nếu dòng không hiển thị hoặc chỉ hiển thị một phần, cuộn đến nó
        if (lineOffsetTop < containerScrollTop || lineOffsetTop + lineHeight > containerScrollTop + containerHeight) {
            // Cuộn để dòng active ở giữa khung nhìn (hoặc gần đó)
            lyricsContent.scrollTop = lineOffsetTop - (containerHeight / 2) + (lineHeight / 2);
        }
    }
}

// 5. Xử lý sự kiện click vào dòng lời bài hát để tua video
document.addEventListener('DOMContentLoaded', function() {
    document.querySelectorAll('.ytle-lyric-line').forEach(function(line) {
        line.addEventListener('click', function() {
            var lineTime = parseFloat(this.dataset.time);
            var videoId = this.closest('.ytle-lyrics-wrapper').dataset.videoId;

            if (ytlePlayers[videoId] && typeof ytlePlayers[videoId].seekTo === 'function') {
                ytlePlayers[videoId].seekTo(lineTime, true); // Tua video đến thời gian đó
                ytlePlayers[videoId].playVideo(); // Phát video
            }
        });
    });

    // (Tùy chọn) Ẩn nút ẩn/hiện lời bài hát nếu bạn đã có chức năng đồng bộ hóa và muốn bỏ nút đó
    // const toggleButton = document.querySelector('.ytle-toggle-lyrics-button');
    // if (toggleButton) {
    //     toggleButton.style.display = 'none';
    // }
});

Kiểm tra lại cấu trúc file Plugin của bạn:

Hãy đảm bảo rằng bạn đã tạo đầy đủ các thư mục và file như cấu trúc sau:

youtube-lyrics-embedder/
├── assets/
│   ├── css/
│   │   └── style.css  <-- Đã cập nhật
│   └── js/
│       └── script.js  <-- Đã cập nhật
├── includes/
│   ├── admin-settings.php (Không đổi so với lần trước, nhưng vẫn cần có)
│   └── public-display.php <-- Đã cập nhật
├── templates/
│   └── lyrics-template.php <-- Đã cập nhật
├── youtube-lyrics-embedder.php (File chính - Không đổi so với lần trước)
└── readme.txt (Không đổi so với lần trước)

Cách sử dụng Shortcode Mới:

Sau khi cập nhật và kích hoạt lại plugin, bạn sẽ sử dụng shortcode với định dạng lời bài hát có dấu thời gian:

Đoạn mở đầu [00:05] Đây là dòng lời đầu tiên. [00:08] Đây là dòng lời thứ hai. [00:12] Và đây là dòng lời thứ ba. [00:15] Dòng cuối cùng của bài hát." ]

Thay thế:

  • YOUR_YOUTUBE_VIDEO_ID bằng ID video YouTube của bạn.
  • Nội dung trong lyrics="..." bằng lời bài hát có dấu thời gian của bạn.

Những điều cần lưu ý:

  1. Chính xác dấu thời gian: Đây là yếu tố quan trọng nhất. Nếu dấu thời gian không khớp với thời điểm lời được hát trong video, tính năng đồng bộ hóa sẽ không hoạt động chính xác. Bạn có thể cần xem video và điều chỉnh dấu thời gian một cách tỉ mỉ.
  2. Một video một plugin instance: Plugin này được thiết kế để xử lý một video và một bộ lời bài hát đồng bộ hóa trên mỗi trang/bài viết. Nếu bạn có nhiều video đồng bộ hóa trên cùng một trang, bạn cần một logic phức tạp hơn để quản lý nhiều YouTube Player API instances.
  3. Tải lại trang: Nếu bạn thay đổi shortcode, hãy nhớ lưu bài viết và tải lại trang để thấy các thay đổi.
  4. Kiểm tra Console trình duyệt: Nếu có lỗi, hãy mở Console (nhấn F12 trong trình duyệt và chọn tab “Console”) để xem có thông báo lỗi JavaScript nào không.
  5. Tương thích: Đảm bảo plugin không xung đột với các plugin hoặc theme khác.

Đây là một bước tiến lớn để thực hiện ước nguyện của bạn. Hãy thử nghiệm thật kỹ, và nếu có bất kỳ vấn đề nào, đừng ngần ngại cho tôi biết nhé!

Related Posts

Leave a Comment

-
00:00
00:00
Update Required Flash plugin
-
00:00
00:00