sampotts / plyr

A simple HTML5, YouTube and Vimeo player
https://plyr.io
MIT License
26.35k stars 2.92k forks source link

"data-poster" and "data-thumbnail-src" do not recognize placeholders ("poster" and "thumbnail-src" also) #2807

Open KogucikPL opened 1 month ago

KogucikPL commented 1 month ago

I have a script that replaces placeholders with the corresponding values ​​from a JSON array. In general, the replacement works fine everywhere, but for some reason it doesn't want to work with these attributes. For example:

<span>I like {{activity}}</span
<img src="/assets/images/{{file}} />

gives

<span> I like reading books</span>
<img src="/assets/images/book.png" />

Expected behaviour:

I would like <video class="plyyr" playsinline controls data-poster="/assets/video/{{folder}}/thumb.png" data-thumbnail-src="/assets/video/{{folder}}/preview.vtt"> to change to <video class="plyyr" playsinline controls data-poster="/assets/video/book/thumb.png" data-thumbnail-src="/assets/video/book/preview.vtt"> and then work as "intended", i.e. add a video poster and display thumbnails in the progress bar.

Actual behaviour:

Currently the replacement works. The console and browser see the change. Theoretically, the placeholders change, but despite this, neither the poster nor the preview works. When it comes to lines like this one, after replacing everything works: <source src="/assets/video/{{folder}}/1080p.mp4" type="video/mp4" size="1080" /> When I replace the placeholder manually (i.e. I simply enter the path myself), then everything works perfectly, but with the placeholder it does not want to work, even though the browser and console see the change correctly.

Steps to reproduce:

  1. Create a basic player:
<div class="plyr-player">
            <video class="plyyr" playsinline controls data-poster="/assets/video/book/thumb.png" data-thumbnail-src="/assets/video/book/preview.vtt">
              <source src="/assets/video/book/1080p.mp4" type="video/mp4" size="1080" />
              <source src="/assets/video/book/720p.mp4" type="video/mp4" size="720" />
              <source src="/assets/video/book/480p.mp4" type="video/mp4" size="480" />
              <source src="/assets/video/book/360p.mp4" type="video/mp4" size="360" />
            </video>
</div>
  1. Add placeholders:
<div class="plyr-player">
            <video class="plyyr" playsinline controls data-poster="/assets/video/{{folder}}/thumb.png" data-thumbnail-src="/assets/video/{{folder}}/preview.vtt">
              <source src="/assets/video/{{folder}}/1080p.mp4" type="video/mp4" size="1080" />
              <source src="/assets/video/{{folder}}/720p.mp4" type="video/mp4" size="720" />
              <source src="/assets/video/{{folder}}/480p.mp4" type="video/mp4" size="480" />
              <source src="/assets/video/{{folder}}/360p.mp4" type="video/mp4" size="360" />
            </video>
</div>
  1. Add this script:
document.addEventListener('DOMContentLoaded', () => {
    const jsonUrl = `/assets/file.json?v=${new Date().getTime()}`;

    fetch(jsonUrl)
        .then(response => {
            if (!response.ok) {
                throw new Error('Network response was not ok');
            }
            return response.json();
        })
        .then(data => {
            function replacePlaceholders(template, values) {
                return template.replace(/{{(.*?)}}/g, (match, key) => {
                    return values[key.trim()] || match;
                });
            }

            function replacePlaceholdersInElement(element, values) {
                if (element.childNodes.length) {
                    element.childNodes.forEach(child => {
                        if (child.nodeType === Node.TEXT_NODE) {
                            child.textContent = replacePlaceholders(child.textContent, values);
                        } else if (child.nodeType === Node.ELEMENT_NODE) {
                            replacePlaceholdersInElement(child, values);
                            replacePlaceholdersInAttributes(child, values);
                        }
                    });
                }
            }

            function replacePlaceholdersInAttributes(element, values) {
                Array.from(element.attributes).forEach(attr => {
                    if (attr.name === 'src') {
                        const newSrc = replacePlaceholders(attr.value, values);
                        console.log(`Setting src attribute to: ${newSrc}`); // Debugging line
                        element.setAttribute('src', newSrc);
                    } else {
                        attr.value = replacePlaceholders(attr.value, values);
                    }
                });
            }

            function replacePlaceholdersInDocument(values) {
                Array.from(document.body.childNodes).forEach(node => {
                    if (node.nodeType === Node.ELEMENT_NODE) {
                        replacePlaceholdersInElement(node, values);
                    }
                });
            }

            const values = {};
            data.forEach(item => {
                values[`order${item.order}`] = item.order;
                values[`folder${item.order}`] = item.folder;
                values[`title${item.order}`] = item["title"];
                values[`artist${item.order}`] = item["artist"];
            });

            replacePlaceholdersInDocument(values);

            document.querySelectorAll('img').forEach(img => {
                const srcPlaceholder = img.getAttribute('src');
                const newSrc = replacePlaceholders(srcPlaceholder, values);
                img.setAttribute('src', newSrc);
            });
        })
        .catch(error => {
            console.error('Error loading JSON data:', error);
        });
});
  1. Add a table like this:
[
  {
    "id": 1,
    "order": 1,
    "folder": "book1",
    "title": "Title1",
    "artist": "Artist1"
  },
  {
    "id": 2,
    "order": 2,
    "folder": "book2",
    "title": "Title2",
    "artist": "Artist2"
  }
]

Environment:

Console errors (if any):

None.

Thank you in advance for any help.

KogucikPL commented 1 month ago

I solved the problem using simple php, more specifically:

<?php
$jsonFile = 'path/to/file.json';

$jsonData = file_get_contents($jsonFile);
$dataArray = json_decode($jsonData, true);

function replacePlaceholders($template, $dataArray) {
    foreach ($dataArray as $data) {
        $order = $data['order'];
        foreach ($data as $key => $value) {
            $placeholder = "{{{$key}{$order}}}";
            if (strpos($template, $placeholder) !== false) {
                $template = str_replace($placeholder, $value, $template);
            }
        }
    }
    return $template;
}

ob_start();
?>

<!-- Some HTML code -->
<div class="plyr-player">
            <video class="plyyr" playsinline controls data-poster="/assets/video/{{folder100}}/thumb.png" data-thumbnail-src="/assets/video/{{folder100}}/preview.vtt">
              <source src="/assets/video/{{folder100}}/1080p.mp4" type="video/mp4" size="1080" />
              <source src="/assets/video/{{folder100}}/720p.mp4" type="video/mp4" size="720" />
              <source src="/assets/video/{{folder100}}/480p.mp4" type="video/mp4" size="480" />
              <source src="/assets/video/{{folder100}}/360p.mp4" type="video/mp4" size="360" />
            </video>
          </div>
<!-- Some HTML code -->

<?php
$htmlContent = ob_get_clean();

$replacedContent = replacePlaceholders($htmlContent, $dataArray);

echo $replacedContent;
?>

Maybe it will be useful to someone in the future. I thank myself for helping lol