1

The command below processes the output of youtube-dl with sed to get the filename of the video

youtube-dl "$URL" 2> /dev/null | \
sed -n 's/^\[download\] Destination: //p; s/^\[download\] \(.*\) has already been downloade.*/\1/p'

Immediately after youtube-dl finishes fetching and parsing the HTML and starts downloading the video, which is a couple/few seconds after it starts executing, it outputs what the filename of the video will be once it's done downloading (postfixed with a .part while it's downloading)

So the crux of the issue and what I'm stuck on is, How do I get the command above to the background (so it keeps downloading) and get the video filename from its standard output, so I can use it to open the video file before it's done downloading.

Wis
  • 213
  • 1
  • 8
  • ytdl already checks if you have downloaded a video, or there is at least a parameter for that. – WGRM Mar 09 '20 at 21:04
  • 1) When the download completes, the `.part` file is replaced by a new one with a new inode (tested: `toutube-dl` 2020.03.08 on Arch Linux); if you open the `.part` you end up playing a deleted file. Are you sure this is what you are looking for? 2) Piping the stdout of a foreground `youtube-dl` won't prevent files from being downloaded, maybe you don't need to send it to the background. 3) Can something like this be of help? `youtube-dl "$URL" | while read -r file; do if [[ "$file" =~ ^\[download\]\ Destination:.*\.mp4 ]]; then vlc "${file#\[download\] Destination: }.part"; fi; done` – fra-san Mar 09 '20 at 22:52
  • @WGRM already taken care of with one youtube-dl command, if it's already downloaded, or if it's unfinished and is resuming downloading, or if it's not in current directory and starts downloading, it output's a similar message. with one or couple sed commands can get the filename no matter what it did. – Wis Mar 10 '20 at 09:08
  • @fra-san thanks for reminding me of the while read stdin loop, I built on it, I uSe Arch bTw (too ;D). though I had no issue with mpv keeping to play a video file that has been renamed after it finishes downloading, could it be a feature that's not in other video players? on a cow fs like btrfs the inode changes even with a rename, right? – Wis Mar 10 '20 at 09:17
  • @Wis That is, in general, a feature of the operating system: a deleted file is not referenced anymore in the directory tree, but it can still be used by programs that retain an handle to it. (See, for some details, the [POSIX description](https://pubs.opengroup.org/onlinepubs/9699919799/functions/unlink.html) for `unlink`, which is the interface [used by `rm`](https://unix.stackexchange.com/q/151951/315749)). – fra-san Mar 10 '20 at 10:05

2 Answers2

1

You could use inotifywait:

$ youtube-dl "$URL" &
$ inotifywait  --event create --format '"%f"' . | xargs vlc

There is a race condition there, if your connection is very fast (mine right now is) the file could be downloaded, and renamed, before your player opens it. Also, if youtube-dl does something like download audio and video separately, you might end up opening the wrong file.

Eduardo Trápani
  • 12,032
  • 1
  • 18
  • 35
0

@fra-san's comment reminded me of the while read loop which you can use to process output line-by-line/procedurally (as opposed to functionally, with pipes), you can use the < operator to pipe the output of a file to that loop with Bash Process Substitution of the youtube-dl command, and you can also send it to the background by adding an & and the while loop still can read the output of it (it's just reading a file, which BPS made).

through testing I found that I can keep playing the video normally even after it finishes downloading and gets renamed, though this might be a feature of mpv.

#!/bin/bash
# ytdl-stream - use youtube-dl to stream videos i.e watch videos as they download
# usage: ytdl-stream [YOUTUBE_DL_OPTIONS] URL 
# you can pipe into it a command to open you video player, e.g:
# echo mpv --mute=yes | ytdl-stream -f 'best[width<=1920,height<=1080]' --write-auto-sub [URL]

test ! -t 0 && player_cmd="$(cat /dev/stdin)" || player_cmd="mpv"

while IFS="" read -r line; do
  filename=$(echo "$line" | sed -n 's/^\[download\] Destination: //p')
  if [[ -z "$filename" ]]; then
    filename=$(echo "$line" | sed -n 's/^\[download\] \(.*\) has already been downloade.*/\1/p')
    [[ -z "$filename" ]] && continue || notify-send "file already downloaded, opening.."
  else
    notify-send "downloading.."
  fi
  withoutExtensions="${filename%.*}"
  withoutExtensions="${withoutExtensions%.*}"
  if [[ -e "$filename" ]]; then
    sleep 0.5 && ($player_cmd "$filename")&
  elif [[ -e "$filename".part ]]; then
    sleep 2
    if [[ -e "$filename".part ]]; then
      notify-send "found .part after sleep again"
      ($player_cmd "$filename".part)&
    else
      sleep 0.5 && ($player_cmd "$withoutExtensions"*)&
    fi
  fi
done < <(youtube-dl "$@" 2> /dev/null)&
Wis
  • 213
  • 1
  • 8