requarks / wiki

Wiki.js | A modern and powerful wiki app built on Node.js
https://js.wiki
GNU Affero General Public License v3.0
24.32k stars 2.69k forks source link

Video is not rendered in view mode, but is ok in edit mode #1459

Open akavato opened 4 years ago

akavato commented 4 years ago

Describe the bug Youtube embedded video is not rendered in view mode, but is ok in edit mode

To Reproduce Steps to reproduce the behavior:

  1. Embed videon on page
  2. Save page
  3. Open page in preview mode

Expected behavior Video should be rendered for viewing, but it's invisible.

Host Info (please complete the following information):

Jhobean commented 4 years ago

Same here. On the night mode. Google chrome on windows 10

NGPixel commented 4 years ago

Videos are not yet supported in the rendering pipeline.

joppehoekstra commented 4 years ago

Any idea as to when this will be implemented?

newfoundfreedom commented 4 years ago

I too have just discovered this bug. Embed video shows just fine in edit mode (whether using Markdown or WYSIWYG editors), but page render fails.

Thanks for all the hard work on this app - embed vids would really help.

brewerc1 commented 4 years ago

Videos are not yet supported in the rendering pipeline.

Perhaps a good approach would be to hide the interface element for features that are not yet supported.

despens commented 4 years ago

It is possible to embed videos via iframes if HTML sanitation is turned off in AdministrationRenderingHTMLSecuritySanitize HTML

grandixximo commented 4 years ago

Also came across this, hope the feature will be implemented soon!

j0lol commented 4 years ago

It is possible to embed videos via iframes if HTML sanitation is turned off in AdministrationRenderingHTMLSecuritySanitize HTML

is it possible to embed iframes in the WYSIWYG or markdown editor?

ccolella-mdc commented 4 years ago

While I am able to use iframes thanks to @despens suggestion, the content fails to load when I am using assets that are uploaded into the editor's asset manager. I was able to display these through a hack before the latest update but now I cannot anymore.

While most of my users can figure out an iframe (either through google, asking me, or looking at an example I did) they cannot upload assets elsewhere like I can.

dude1756 commented 4 years ago

Is there any timeline for implementing support for videos in rendering pipeline? And will this include local video assets? I really like wiki.js but building up a user manual without videos is a bit frustrating. Hope this can be fixed soon.

tenwalls commented 4 years ago

Ooh, just encountered this issue. Good there is a temporary workaround

gengue commented 4 years ago

Videos still not showing, even with "Allow frames" on and "Sanitize HTML" off.

ideasandpixels commented 4 years ago

Anything here? Pretty big deal.

ccolella-mdc commented 4 years ago

this embed share link code from youtube works for me:

<iframe
    width="560"
    height="315"
    src="https://www.youtube.com/embed/Mh5LY4Mz15o"
    frameborder="0"
    allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture"
    allowfullscreen>
</iframe>

And changing the source to a local video also works:

<iframe 
    width="560" 
    height="315" 
    src="/video/test.mp4"
    frameborder="0"
    allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture"
    allowfullscreen>
</iframe>

note: it still works without the allow attribute and that content but i'm not sure if that help it with anything. maybe on mobile. and you can play with the hight and width, or use css for them. Like this:

<iframe 
    width="560" 
    height="315"
    src="/video/test.mp4"
    frameborder="0"
    allowfullscreen>
</iframe>

My Settings:

Security > Block IFrame Embedding: off Rendering > html > Sanitize HTML: on Rendering > html > Allow iframes: on

the first one allows you assets to be loaded in an iframe. The third one allows you to have an iframe on your site. The middle one can be set to either one but on does not hidner you in doing this.

ryanmasuga commented 3 years ago

Would love to have this feature without needing any type of workaround, because I agree with @dude1756 that a "building up a user manual without videos is a bit frustrating".

I tried @ccolella-mdc's settings and can get videos to show in Markdown, but I couldn't get WYSIWYG to work.

What I did for responsively sized videos in Markdown:

  1. Grabbed YouTube CSS example from https://embedresponsively.com/
  2. Put only the 'embed-container' div/iframe into the markdown code
  3. Added the "embed-container" CSS to the "Head HTML Injection" field in our theme at Administration > Theme so that this CSS is available on any page we create.

injected-embed-css

So now we add:

<div class='embed-container'>
<iframe src='https://www.youtube.com/embed/xxx' frameborder='0' allowfullscreen></iframe>
</div>

on any page where we need a responsively sized YouTube video.

ryanmasuga commented 3 years ago

Further - does anyone have a clear explanation of how to get an iframe to show on a WYSIWYG page? I must be confused - I don't see any way to edit source directly on a WYSIWYG page, so I'm not clear how to manually embed an iframe that would actually output an iframe. Is this only possible with the Markdown page type?

ccolella-mdc commented 3 years ago

@ryanmasuga It also works (surprise, surprise) on the HTML editor. I don't use the WYSIWYG editor because it has so many fewer features, and, as a software engineer myself, it feels too limiting.

NGPixel commented 3 years ago

@ryanmasuga The WYSIWYG editor is not an HTML editor and it's not possible to edit / insert HTML code because CKEditor 5 simply doesn't have that feature.

Use the Markdown editor if you need to edit / insert HTML code in your page.

ryanmasuga commented 3 years ago

@ccolella-mdc I hadn't tried the HTML page type yet, but yes - the responsive embed code works there, too.

@NGPixel Thanks. I know some WYSIWYG editors have a "Source" button that can expose the underlying HTML (useful for when something gets so bungled you have to manually fix it...), but I guess that's not the case here. We'll likely carry on with Markdown pages.

Jhobean commented 3 years ago

I think There a solution in progress by @KingRial https://github.com/Requarks/wiki/pull/2160.

Me too I need this implementation...

idimitrakopoulos commented 3 years ago

Another solution is to use youtube's video images to display the video until this is fixed.

i.e.

http://img.youtube.com/vi/{video-id}/0.jpg

Like so ...

[![Audi R8](http://img.youtube.com/vi/KOxbO0EI4MA/0.jpg)](https://www.youtube.com/watch?v=KOxbO0EI4MA "Audi R8")

Technically this is NOT embedding (link is opened in new tab) but for our case it works until it's fixed.

Oh and this only works in Markdown. WYSIWYG editor doesn't have the functionality to link an external image :(

felixgoldstein commented 3 years ago

+1

jebr commented 3 years ago

Is the fix for this issue planned in an upcoming release?

hasielhassan commented 3 years ago

@NGPixel I read on CKEditor documentation that embedded html is indeed a feature, can it be turned on ? https://ckeditor.com/docs/ckeditor5/latest/features/html-embed.html

MaxWaldorf commented 3 years ago

Hoping to see this feature coming soon!

stukev commented 3 years ago

This is direly needed. I'm very surprised it's not included.

Edit: I've created a workaround that might be of use to other people. It's a simple jQuery script. You can add it in the backend under Theme ⇾ Code Injection ⇾ Head HTML injection, and it'll resolve this problem entirely.

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script type="text/javascript" defer>
  $(window).on('load', function() {
  function processID(url) {
    rx = /^.*(?:(?:youtu\.be\/|v\/|vi\/|u\/\w\/|embed\/)|(?:(?:watch)?\?v(?:i)?=|\&v(?:i)?=))([^#\&\?]*).*/;
    return url.match(rx)[1];
  }

  $("oembed").each(function(index) {
    ytid = processID($(this).attr("url"));
    $(this).replaceWith('<iframe id="ytplayer" type="text/html" width="640" height="360" src="https://www.youtube.com/embed/' + ytid + '" frameborder="0"/>')
  });
});
</script>
nideKer commented 3 years ago

@stukev it's works greate for me! Many thanks!

bonesoul commented 3 years ago

any updates on this?

BitWiseSE commented 3 years ago

@stukev—this works for youtube perfectly, I am very grateful, thanks! Anyone have an idea how difficult it would be to have a similar workaround for Vimeo?

stukev commented 3 years ago

@BitWiseSE that would be quite easy actually. just use the same code and replace the "rx" line with a regex to extract the vimeo id and replace the "$(this).replaceWith..." line with the embed code from vimeo.

MaxWaldorf commented 3 years ago

I added the code but nothing coming up...

Anything specific to do on the WYSIWYG editor?

BitWiseSE commented 3 years ago

Administration > Rendering > HTML > Security > Allow iframes (enable)

That is the only change I required to make it work with the script provided by stukev

I am also using the WYSIWYG editor, inserting multimedia.

On 2021-07-21 7:48 AM, MaxWaldorf wrote:

I added the code but nothing coming up...

Anything specific to do on the WYSIWYG editor?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/Requarks/wiki/issues/1459#issuecomment-884204047, or unsubscribe https://github.com/notifications/unsubscribe-auth/AU5OHF4S7N3EBAWVS6DLX5LTY3FZ5ANCNFSM4KSM3ZPA.

BitWiseSE commented 3 years ago

@stukev, thanks for the hints on vimeo, I'll give that a go and see if I can get it working

BitWiseSE commented 3 years ago

Does anyone know how we can post code here, without it getting converted? In particular, I'm trying to put code that has a "div" tag in it, and it converts it. I tried the "< >" code mode, but that did not seem to do the trick.

BitWiseSE commented 3 years ago

I won't pretend to know what I'm doing, but I extended @stukev's original code for youtube insertion, and added a "div" with CSS to make it responsive, so that it will size to the display.

Here is the HTML injection:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script type="text/javascript" defer>
  $(window).on('load', function() {
  function processID(url) {
    rx = /^.*(?:(?:youtu\.be\/|v\/|vi\/|u\/\w\/|embed\/)|(?:(?:watch)?\?v(?:i)?=|\&v(?:i)?=))([^#\&\?]*).*/;
    return url.match(rx)[1];
  }

  $("oembed").each(function(index) {
    ytid = processID($(this).attr("url"));
    $(this).replaceWith('<div class="video-responsive"> <iframe id="ytplayer" type="text/html" width="640" height="360" src="https://www.youtube.com/embed/' + ytid + '" frameborder="0" allowfullscreen></iframe> </div>')
  });
});
</script>

And here is the CSS that you need to override:

.video-responsive {
  overflow: hidden;
  padding-bottom: 56.25%;
  position: relative;
  height: 0
}
.video-responsive iframe {
  left: 0;
  top: 0;
  height: 100%;
  width: 100%;
  position: absolute
}

Hints on doing this were obtained from https://www.ostraining.com/blog/coding/responsive-videos/

grandixximo commented 3 years ago

image

<div> </div>

BitWiseSE commented 3 years ago

thanks @grandixximo, I had tried but with a whole block

I will edit my post! :)

update... I tried, but failed, does not seem to want to work when embedding in other code, I guess?

2nd update... got it. I placed the cursor on the "div" block, and click on the code block, and it put them where they belong

thanks, now I know how :)

grandixximo commented 3 years ago

You do not have the commenting out symbol on your keyboard, you have to use either ctrl+e or the insert code button after selecting your entire code

image

all three of those will pop out by themself if you highlight your code and you press ctl+e on your keyboard

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script type="text/javascript" defer>
  $(window).on('load', function() {
  function processID(url) {
    rx = /^.*(?:(?:youtu\.be\/|v\/|vi\/|u\/\w\/|embed\/)|(?:(?:watch)?\?v(?:i)?=|\&v(?:i)?=))([^#\&\?]*).*/;
    return url.match(rx)[1];
  }

  $("oembed").each(function(index) {
    ytid = processID($(this).attr("url"));
    $(this).replaceWith('<iframe id="ytplayer" type="text/html" width="640" height="360" src="https://www.youtube.com/embed/' + ytid + '" frameborder="0"/>')
  });
});
</script>
BitWiseSE commented 3 years ago

super, even easier, thanks!

grandixximo commented 3 years ago

@BitWiseSE what version are you on? I cannot get my videos to show up

grandixximo commented 3 years ago

I got it wo work on WYSIWYG on latest version

had to disable Sanitize HTML

image

and then add this to the theme

I won't pretend to know what I'm doing, but I extended @stukev's original code for youtube insertion, and added a "div" with CSS to make it responsive, so that it will size to the display.

Here is the HTML injection:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script type="text/javascript" defer>
  $(window).on('load', function() {
  function processID(url) {
    rx = /^.*(?:(?:youtu\.be\/|v\/|vi\/|u\/\w\/|embed\/)|(?:(?:watch)?\?v(?:i)?=|\&v(?:i)?=))([^#\&\?]*).*/;
    return url.match(rx)[1];
  }

  $("oembed").each(function(index) {
    ytid = processID($(this).attr("url"));
    $(this).replaceWith('<div class="video-responsive"> <iframe id="ytplayer" type="text/html" width="640" height="360" src="https://www.youtube.com/embed/' + ytid + '" frameborder="0" allowfullscreen></iframe> </div>')
  });
});
</script>

And here is the CSS that you need to override:

.video-responsive {
  overflow: hidden;
  padding-bottom: 56.25%;
  position: relative;
  height: 0
}
.video-responsive iframe {
  left: 0;
  top: 0;
  height: 100%;
  width: 100%;
  position: absolute
}

Hints on doing this were obtained from https://www.ostraining.com/blog/coding/responsive-videos/

I think in HTML pages you have to enable rendering => HTML => security => allow iframes, and disable Security => block Iframes Embedding

nehpetsyar commented 3 years ago

I've tried to follow along with instruction/conversation that @grandixximo and @BitWiseSE have, but I cannot get it to work for Vimeo. I'll mention I am not a web person, and make no claims to have any idea of what I'm doing here. I'm just IT and have been given responsibility to set up a Wiki. The lack of native video embedding is a major killer if I can't find a work around, I thought for sure this would have been built into a modern wiki platform. I've allowed iframes, and disabled block iframes embedding and disabled html sanitization. Could anyone find it in their heart to modify the HTML injection and instruction mentioned above to allow for Vimeo? Or is it staring me in the face and I'm just missing it. A thousand thank you's a head of time to anyone that takes the time to assist. This would pertain to using the WYSIWYG editor, as none of us on my end are web developers of any kind.

BitWiseSE commented 3 years ago

It's on my to-do list as I need this as well (the current instructions are for youtube only). I will try this evening, but if someone else can try before that, that would be even better :)

On 2021-07-29 11:53 AM, nehpetsyar wrote:

I've tried to follow along with instruction/conversation that @grandixximo https://github.com/grandixximo and @BitWiseSE https://github.com/BitWiseSE have, but I cannot get it to work for Vimeo. I'll mention I am not a web person, and make no claims to have any idea of what I'm doing here. I'm just IT and have been given responsibility to set up a Wiki. The lack of native video embedding is a major killer if I can't find a work around, I thought for sure this would have been built into a modern wiki platform. I've allowed iframes, and disabled block iframes embedding and disabled html sanitization. Could anyone find it in their heart to modify the HTML injection and instruction mentioned above to allow for Vimeo? Or is it staring me in the face and I'm just missing it. A thousand thank you's a head of time to anyone that takes the time to assist.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/Requarks/wiki/issues/1459#issuecomment-889343720, or unsubscribe https://github.com/notifications/unsubscribe-auth/AU5OHFZ444NFTKBGB2NQHRDT2GIRZANCNFSM4KSM3ZPA.

nehpetsyar commented 3 years ago

I understand if you cant get to it, we have lives to live. Whoever takes that on would be a lifesaver, and would have the gratitude of our team and myself. At the very least though, I really do appreciate the quick response.

grandixximo commented 3 years ago

I'm not a developer myself, so the code is probably not the most elegant, but this works for me, youtube and vimeo both

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script type="text/javascript" defer>
$(window).on('load', function () {
    function processID(url) {
        rx = /^.*(?:(?:youtu\.be\/|v\/|vi\/|u\/\w\/|embed\/)|(?:(?:watch)?\?v(?:i)?=|\&v(?:i)?=))([^#\&\?]*).*/;
        var match = url.match(rx);
        var tp = 'yt';
        if (match) {
            return [url.match(rx)[1], tp];
        }
        rx = /^.*(vimeo\.com\/)((channels\/[A-z]+\/)|(groups\/[A-z]+\/videos\/))?([0-9]+)/;
        match = url.match(rx);
        tp = 'vm';
        if (match) {
            return [url.match(rx)[5], tp];
        }
    }
    $("oembed").each(function (index) {
        id = processID($(this).attr("url"));
        if (id[1] == 'yt') {
            ytid = id[0]
            $(this).replaceWith('<div class="video-responsive"> <iframe id="ytplayer" type="text/html" width="640" height="360" src="https://www.youtube.com/embed/' + ytid + '" frameborder="0" allowfullscreen></iframe> </div>')
        } else if (id[1] == 'vm') {
            vmid = id[0]
            $(this).replaceWith('<div class="video-responsive"> <iframe id="vmplayer" type="text/html" width="640" height="360" src="https://player.vimeo.com/video/' + vmid + '" frameborder="0" allowfullscreen></iframe> </div>')
        }
    });
});
</script>

The youtube iframe should work just like it did before, the Vimeo I added I only tested with few videos, hope it works well for you!

NGPixel commented 3 years ago

There's absolutely no need for loading an heavy library like jQuery nowadays... Plain javascript is more than enough.

Also, binding on the load event doesn't guarantee that Vue has finished rendering the page, you should register a callback with the boot loader instead (and add a small setTimeout just to be safe), e.g.:

window.boot.register('vue', () => {
  setTimeout(() => {
    document.querySelectorAll('oembed').forEach(elm => {
      const id = elm.getAttribute('url')
      const newElm = document.createElement('div')
      newElm.classList.add('video-responsive')
      newElm.insertAdjacentHTML('beforeend', `<iframe id="ytplayer" type="text/html" width="640" height="360" src="https://www.youtube.com/embed/${ytid}" frameborder="0" allowfullscreen></iframe>`)
      elm.replaceWith(newElm)
    })
  }, 50)
})
grandixximo commented 3 years ago

Changed the timeout to window.onload to be sure the page is fully loaded before running the script, I removed the use of jQuery and this is the new HTML injection that works for me, youtube and vimeo both, thanks to @NGPixel @BitWiseSE and @stukev Again I code only for fun, so this is NOT elegant code, but it should work

<script type="text/javascript" defer>
window.boot.register('vue', () => {
    window.onload = function interactiveVideos() {
        document.querySelectorAll('oembed').forEach(elm => {
            const url = elm.getAttribute('url')
            const newElm = document.createElement('div')
            newElm.classList.add('video-responsive')
            rx = /^.*(?:(?:youtu\.be\/|v\/|vi\/|u\/\w\/|embed\/)|(?:(?:watch)?\?v(?:i)?=|\&v(?:i)?=))([^#\&\?]*).*/;
            var match = url.match(rx);
            if (match) {
                var ytid = url.match(rx)[1];
                newElm.insertAdjacentHTML('beforeend', `<iframe id="ytplayer" type="text/html" width="640" height="360" src="https://www.youtube.com/embed/${ytid}" frameborder="0" allowfullscreen></iframe>`)
            }
            rx = /^.*(vimeo\.com\/)((channels\/[A-z]+\/)|(groups\/[A-z]+\/videos\/))?([0-9]+)/;
            match = url.match(rx);
            if (match) {
                var vmid = url.match(rx)[5];
                newElm.insertAdjacentHTML('beforeend', `<iframe id="vmplayer" type="text/html" width="640" height="360" src="https://player.vimeo.com/video/${vmid}" frameborder="0" allowfullscreen></iframe>`)
            }
            elm.replaceWith(newElm)
        })
    }
})
</script>

For whomever reads only this, you still have to DISABLE rendering => HTML => security => Sanitize HTML

BitWiseSE commented 3 years ago

Wow, super grateful to all for getting this elegant solution together!

Two comments:

  1. For those reading from this point in the thread, you also need to include the CSS that defines 'video-responsive', see further up in the thread.
  2. I tested the above script. Works for me! However, you can't put both a vimeo and youtube on the same page—both disappear when viewing the page. That's certainly not a concern for me, but I thought I would point it out in case someone tries and wonders what is wrong.
grandixximo commented 3 years ago

For the first comment the CSS for video-responsive is not necessary, it just makes the videos fit the screen, too big IMO, although it is more similar to the WYSIWYG preview, I prefer the more common 640x360 view, at least on PC.

For your second comment, the reason why it didn't work with two videos is because the delay was not working well, I changed it to execute the code only after the page is completely loaded, as the code scans the page for the wrong embedding and fixes it, if the embedding is not there, then the script wont be able to fix the embedding as it only runs once, I tested with ctrl+F5 and it works well (takes about 30 seconds to reload the whole wiki, and the videos will only pop up at the very end) that should take care of that, I edited my old post with refined script

BitWiseSE commented 3 years ago

Thanks, I tried you updated script, and that works. The reason I want the sizing video is for use on a phone, but yeah, indeed typically too big on a PC browser window.