4

When you have a direct link to a video you can usually right click and the mouse menu will appear. Once there you'll see Save Video As. If you click on that it will download the video to your computer.

I want the same functionality but instead I want to make a button on an HTML page that when you click will do the exact same thing as mentioned above.

How can I do this?

Let's look at this example: I have this link: https://invidious.fdn.fr/latest_version?id=NF_69Dyle1Y&raw&itag=22

If you go on there and right click on the video you'll see this: example video with right click menu

Clicking on "Save Video As" you get: enter image description here

Which is a dialog for saving the video in your local storage.

Now my question is I want to do all this with a click of an html button. I want the dialog for saving to open without having to go on the video itself and right click and so on. Is there a way to do that?

the html a tag download attribute does not work. I've tried using URI like this

<a href='"data:application/octet-stream,"+encodeURIComponent(`https://invidious.fdn.fr/latest_version?id=NF_69Dyle1Y&raw&itag=22`)' download="video.mp4">download video</a>

but it also doesn't work.

BreezeWind
  • 618
  • 1
  • 9
  • 18
  • Would one of these links answer your question? https://stackoverflow.com/questions/11336663/how-to-make-a-browser-display-a-save-as-dialog-so-the-user-can-save-the-conten https://stackoverflow.com/questions/2897619/using-html5-javascript-to-generate-and-save-a-file https://stackoverflow.com/questions/18690450/how-to-generate-and-prompt-to-save-a-file-from-content-in-the-client-browser – Invizio May 27 '20 at 15:38
  • no the download attribute does not work. – BreezeWind May 27 '20 at 15:39
  • (That's only one of the three links; the second one uses a data URI and the third uses a blob) – Invizio May 27 '20 at 15:43
  • Please give me some time to check them before closing my question. – BreezeWind May 27 '20 at 15:43
  • Don't worry, I'm not doing anything (Not even sure I'd have that power since I'm rather new on SO). In the case none of the other links work, please provide details about what you tried and what were the results. – Invizio May 27 '20 at 15:46
  • I've tried what is being said on the other links and I'm still stuck. I'll we try to edit my question to be more clear about what I want. – BreezeWind May 27 '20 at 16:11
  • (Ah, I see you are a man of culture as well - I know that Youtuber) I see what the problem is - basically, you're trying to execute JS code directly in the `href`, which isn't possible. I'll post the details (with a fix) in an answer shortly. – Invizio May 27 '20 at 17:08
  • thank you in advance! – BreezeWind May 27 '20 at 17:10

1 Answers1

7

If your video is located on the same origin as your webpage (not your case)

<a href="/path/to/video.mp4" download="video">Download</a>

Rather simple, does not require Javascript, and works on every browser except IE.


If your video is from a different origin (your case)

When testing my solution, I found out that cross-origin downloads are blocked by Chrome and Firefox for security purposes.

a. If you control the server

If the server implements proprer CORS, or if you have control over the server and can add those CORS, you can use this script that I shamelessly took from this SO question :

<!-- The style="display:none;" is optional, you can remove it if you don't want the feature explained below. -->
<a id="download-link" href="javascript:alert('The video is not yet ready!')" download="video" style="display:none;">Download</a>
<script>

var a = document.getElementById("download-link");

function downloadResource(url, filename) {

  // Current blob size limit is around 500MB for browsers
  if (!filename) filename = url.split('\\').pop().split('/').pop();
  fetch(url, {
      headers: new Headers({
        'Origin': location.origin
      }),
      mode: 'cors'
    })
    .then(response => response.blob())
    .then(blob => {
      let blobUrl = window.URL.createObjectURL(blob);

      // Place the resource in the href of the link
      a.href = blob;

      // Bonus : Only show the link if and when the Javascript code has executed
      a.style.display = "inline";
    })
    .catch(e => console.error(e));

}

downloadResource("https://invidious.fdn.fr/latest_version?id=NF_69Dyle1Y&raw&itag=22");

</script>

I added a little feature that will keep the link hidden until the file is completely downloaded. You can of course change this depending on your requirements.

b. If you don't control the server

If it uses CORS and allows all origins (or at least your origin), the script above should work.

If it doesn't, you're out of luck, sadly. You can still open the video in a new window and tell the user to right-click and "Save As" manually; it's less neat, but at least it works.

Invizio
  • 382
  • 1
  • 8
  • 1
    The answer is very good but unfortunately I don't control the server. Thanks for the answer. – BreezeWind May 27 '20 at 19:01
  • I tried option (a). It pre-downloads the files in the background as soon as downloadResource() is called. If the user clicks the links before the download has finished, it opens a video player in a new tab. If the user clicks after the download has completed, the download happens as expected (although immediately, since the data is already in the browser's memory). – Vern Jensen Oct 27 '22 at 19:30
  • @VernJensen Sorry for the late reply! Indeed, this isn't a drop-in, production-ready solution; as a developer you still have to understand how it works and where to place some things. Notably, the `downloadResource` function _preparatively_ downloads the video file in the background, and will place it in the link when ready. Note that the download will take time and resources, so you shouldn't download it, say, on page load, but if possible you should download it early so the user doesn't have to wait too much. Also, the link shouldn't be visible/clickable until the download is complete. – Invizio Nov 24 '22 at 21:13
  • [2] I didn't want to clutter the snippet with unrelated "beauty" code to keep it simple and readable, and because there's really not a single way of doing it, it depends entirely on the look-and-feel of your website. I leave it to the developers to choose where they place their link, how they decide to handle the link while the download is running (hidden, disabled, make it pop an error message, etc.), when they decide to initiate the download, etc. In any case, I expect people to customize this code _a lot._ Keep in mind we're dodging browser security there, so the solution _will_ be unclean! – Invizio Nov 24 '22 at 21:18