Thursday, January 7, 2010

Youtube-ML

I just dug this one out from the past (beginning of 2008 I think) and I figured I might as well throw it in here along with all the others.

This is a script for giving youtube-dl a whole list of download links instead of doing one-by-one. Nothing to it really.

So first, if you download this stuff, you probably want to compile it with OCaml like this:

ocaml -o youtube-ml str.cma youtube.ml

(Use the str module, and compile youtube.ml as youtube-ml.)

Now that you have the binary executable you need to create a file containing the addresses you want to download and the names of files you want to save those downloads as. These will be separated by a three-hyphen delimiter. Example:

Beat the Horse.mp4 --- http://www.youtube.com/watch?v=8oJgqbgvInk
Pas Encore.mp4 --- http://www.youtube.com/watch?v=FCCoggBkcdM
Centrifuge.mp4 --- http://www.youtube.com/watch?v=C_Gy4vzS4U8
Hail Mary.mp4 --- http://www.youtube.com/watch?v=fYy2p_0DVMU

And then you run the program to start the process, like so:

youtube-ml --best-quality FILE

In this case the files will be downloaded in best quality (as mp4) as well.

I might add that you need youtube-dl installed, because this script does nothing except reading from a file and passing the information to youtube-dl.

The code:
 
1 (**
2 * Youtube-ML
3 *
4 * Use youtube-dl to download videos from a list saved in a file.
5 * Sort of batch-process youtube-dl downloads.
6 *
7 * Compiling:
8 * ocamlc -o youtube-ml str.cma youtube.ml
9 *
10 * Example usage:
11 * Download using a file in best quality:
12 * ./youtube-ml --best-quality list_of_files.txt
13 * Download using a bash ad-hoc file and in quiet mode:
14 * ./youtube-ml --quiet <<$
15 * some_filename.flv --- http://some_address/gibberish
16 * other_filename.flv --- http://other_address/gibberish
17 * $
18 *
19 * Parameters:
20 * --help - show usage information,
21 * --quiet - do not display additional information messages,
22 * --best-quality - download in MP4 instead of FLV format.
23 *
24 * Requires:
25 * youtube-dl (http://bitbucket.org/rg3/youtube-dl/wiki/Home)
26 *
27 * Author:
28 * Konrad Siek
29 *
30 * License:
31 * Copyright 2010 Konrad Siek
32 *
33 * This program is free software: you can redistribute it and/or modify
34 * it under the terms of the GNU General Public License as published by
35 * the Free Software Foundation, either version 3 of the License, or
36 * (at your option) any later version.
37 *
38 * This program is distributed in the hope that it will be useful,
39 * but WITHOUT ANY WARRANTY; without even the implied warranty of
40 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
41 * GNU General Public License for more details.
42 *
43 * You should have received a copy of the GNU General Public License
44 * along with this program. If not, see <http://www.gnu.org/licenses/>.
45 *)
46 open Str;;
47
48 let youtube_cmd = "youtube-dl";;
49 let delimiter = "[\t ]+---[\t ]+";;
50 let best_quality_flag = ref false;;
51 let quiet_flag = ref false;;
52
53 exception InvalidString of string ;;
54
55 type filename = string;;
56 type address = string;;
57 type clip = filename * address;;
58
59 (* Convert line into a tupple of type clip. *)
60 let clip_of_string line =
61 let regex = Str.regexp delimiter in
62 let result = Str.split regex line in
63 match result with
64 | file :: http :: [] -> (file, http)
65 | _ -> raise (InvalidString ("Line '" ^ line ^ "' is invalid."))
66 ;;
67
68 (* Read a file and break it down into tupples. *)
69 let read_file filename =
70 let channel = open_in filename in
71 let rec read channel result =
72 try
73 let line = input_line channel in
74 let clip = clip_of_string line in
75 let result = result @ [clip] in
76 read channel result
77 (* with Invalid_string -> raise Invalid_string *)
78 with
79 | InvalidString message -> raise (InvalidString message)
80 | _ -> result
81 in
82 read channel []
83 ;;
84
85 (* Print completed message. *)
86 let print_completed output =
87 if not !quiet_flag then
88 print_endline ("Download into file '" ^ output ^ "' completed.")
89 ;;
90
91 (* Print incomplete message. *)
92 let print_incomplete output =
93 if not !quiet_flag then
94 print_endline ("Download into file '" ^ output ^ "' problematic.")
95 ;;
96
97 (* Print that a file is being downloaded. *)
98 let print_intro http output =
99 if not !quiet_flag then
100 print_endline ("Downloading " ^ http ^ " as " ^ output)
101 ;;
102
103 (* Download clips listed in one file. *)
104 let download filename =
105 let clips = read_file filename in
106 let download (output, http) =
107 let command = if !best_quality_flag then
108 youtube_cmd ^ " -b -o \"" ^ output ^ "\" -q \"" ^ http ^ "\""
109 else
110 youtube_cmd ^ " -o \"" ^ output ^ "\" -q \"" ^ http ^ "\"" in
111 print_intro http output;
112 let result = Sys.command command in
113 if result = 0 then
114 print_completed output
115 else
116 print_incomplete output
117 in
118 List.iter download clips
119 ;;
120
121 (* Print message on how to use the program. *)
122 let print_usage program_name =
123 let usage =
124 "Usage: \n" ^
125 "\t" ^ program_name ^ " " ^ "filename [filename ...] \n" ^
126 "\t" ^ program_name ^ " " ^ "--best-quality filename [filename ...] \n" ^
127 "\t" ^ program_name ^ " " ^ "--help \n" ^
128 "Files: \n" ^
129 "\t" ^ "The files should consist of lines, each line composed of:" ^
130 "\t\t" ^ " - the file to which save the song," ^
131 "\t\t" ^ " - the delimiter consisting of three hyphens ('---')" ^
132 "\t\t" ^ " which can be surrounded by tabs and spaces," ^
133 "\t\t" ^ " - address of the song."
134 in
135 print_endline usage
136 ;;
137
138 (* Print message that given file does not exist. *)
139 let print_file_not_exists file =
140 let message = "File '" ^ file ^ "' does not exist. " in
141 print_endline message
142 ;;
143
144 (* Process all arguments and conduct appropriate action. *)
145 let rec process_args program args =
146 match args with
147 | arg :: tail ->
148 if String.length arg > 1 && String.get arg 0 = '-' then
149 match arg with
150 | "--help" -> print_usage program
151 | "--best-quality" ->
152 best_quality_flag := true;
153 process_args program tail
154 | "--quiet" ->
155 quiet_flag := true;
156 process_args program tail
157 | _ -> print_usage program
158 else
159 download arg
160 | [] -> ()
161 ;;
162
163 (* Read command-line arguments and launch operations. *)
164 let main () =
165 let length = Array.length Sys.argv in
166 let program = Sys.argv.(0) in
167 if length > 1 then
168 process_args program (List.tl (Array.to_list Sys.argv))
169 else
170 print_usage program
171 ;;
172
173 main ()


The code is also available at GitHub as ocaml/youtube.ml.