2 * Copyright (C) 2010-2013 Toni Gundogdu <legatvs@gmail.com>
4 * This file is part of cclive <http://cclive.sourceforge.net/>.
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Affero General Public License as
8 * published by the Free Software Foundation, either version 3 of the
9 * License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Affero General Public License for more details.
16 * You should have received a copy of the GNU Affero General Public
17 * License along with this program. If not, see
18 * <http://www.gnu.org/licenses/>.
27 #include <boost/algorithm/string/classification.hpp> // is_any_of
28 #include <boost/algorithm/string/split.hpp>
29 #include <boost/scoped_ptr.hpp>
30 #include <boost/foreach.hpp>
31 #include <boost/format.hpp>
34 #include <ccapplication>
44 static void handle_fetch(const quvi_word type
, void*)
46 #ifdef HAVE_LIBQUVI_0_9
47 if (type
== QUVI_CALLBACK_STATUS_DONE
)
49 if (type
== QUVISTATUSTYPE_DONE
)
54 static void print_done()
59 static void handle_verify(const quvi_word type
)
61 #ifdef HAVE_LIBQUVI_0_9
62 if (type
== QUVI_CALLBACK_STATUS_DONE
)
64 if (type
== QUVISTATUSTYPE_DONE
)
69 static void handle_resolve(const quvi_word type
)
71 #ifdef HAVE_LIBQUVI_0_9
72 if (type
== QUVI_CALLBACK_STATUS_DONE
)
74 if (type
== QUVISTATUSTYPE_DONE
)
79 #ifdef HAVE_LIBQUVI_0_9
80 static void status_callback_pt9(const quvi_word status
, const quvi_word type
,
81 void *data
, void *userdata
)
86 case QUVI_CALLBACK_STATUS_FETCH
:
87 handle_fetch(type
, data
);
89 case QUVI_CALLBACK_STATUS_HTTP_QUERY_METAINFO
:
92 case QUVI_CALLBACK_STATUS_RESOLVE
:
98 static void status_callback_pt4(const quvi_word status
, const quvi_word type
,
104 case QUVISTATUS_FETCH
:
105 handle_fetch(type
, data
);
107 case QUVISTATUS_VERIFY
:
110 case QUVISTATUS_RESOLVE
:
111 handle_resolve(type
);
117 #ifdef HAVE_LIBQUVI_0_9
118 static int status_callback(long status_type
, void *data
, void *userdata
)
120 static int status_callback(long status_type
, void *data
)
123 const quvi_word status
= quvi_loword(status_type
);
124 const quvi_word type
= quvi_hiword(status_type
);
126 #ifdef HAVE_LIBQUVI_0_9
127 status_callback_pt9(status
, type
, data
, userdata
);
129 status_callback_pt4(status
, type
, data
);
131 cc::log
<< std::flush
;
136 static void print_retrying(const int retry
,
137 const int max_retries
,
138 const int retry_wait
)
150 cc::wait(retry_wait
);
154 static void print_checking(const int i
, const int n
)
156 if (n
> 1) cc::log
<< "(" << i
<< " of " << n
<< ") ";
157 cc::log
<< "Checking ... " << std::flush
;
160 static void print_quvi_error(const quvi::error
& e
)
162 cc::log
<< "libquvi: error: " << e
.what() << std::endl
;
165 namespace po
= boost::program_options
;
166 typedef std::vector
<std::string
> vst
;
168 static std::string
format_streams(const std::string
& s
)
171 boost::split(v
, s
, boost::is_any_of("|,"));
172 const size_t m
= v
.size();
175 v
.push_back("default");
181 BOOST_FOREACH(const std::string
& a
, v
)
183 r
<< boost::format("%|22s|") % a
;
195 static application::exit_status
196 print_streams(const quvi::query
& query
, const quvi::options
&qopts
,
197 const vst
& input_urls
, const po::variables_map
& vm
)
199 const size_t n
= input_urls
.size();
202 BOOST_FOREACH(const std::string
& url
, input_urls
)
206 print_checking(++i
,n
);
207 query
.setup_curl(vm
);
209 const std::string r
= query
.streams(url
, qopts
);
212 cc::log
<< "streams (found):" << format_streams(r
) << std::endl
;
214 catch(const quvi::error
& e
)
217 return application::error
;
220 return application::ok
;
223 static void parse_prefer_format(const std::string
& url
, std::string
& fmt
,
224 const po::variables_map
& vm
)
226 vst vb
, va
= vm
[OPT__PREFER_FORMAT
].as
<vst
>();
227 BOOST_FOREACH(const std::string
& s
, va
)
229 boost::split(vb
, s
, boost::is_any_of(":"));
234 if (cc::re::grep(vb
[0], url
))
244 static void set_stream(const std::string
& url
, quvi::options
& qopts
,
245 const po::variables_map
& vm
)
247 std::string r
= vm
[OPT__STREAM
].as
<std::string
>();
248 if (r
== "default" && vm
.count(OPT__PREFER_FORMAT
))
249 parse_prefer_format(url
, r
, vm
);
253 application::exit_status
application::exec(int const argc
, char const **argv
)
255 const boost::scoped_ptr
<cc::options
> o(new cc::options(argc
, argv
));
256 const po::variables_map vm
= o
->values();
260 const vst
& input_urls
= cc::input::parse(vm
);
261 const size_t n
= input_urls
.size();
265 quvi::query query
; // Throws quvi::error caught in main.cpp
268 qopts
.useragent
= vm
[OPT__AGENT
].as
<std::string
>(); /* libquvi 0.9+ */
269 qopts
.resolve
= ! vm
[OPT__NO_RESOLVE
].as
<bool>();
270 qopts
.statusfunc
= status_callback
;
274 bool omit
= vm
[OPT__QUIET
].as
<bool>();
279 const bool background_given
= vm
[OPT__BACKGROUND
].as
<bool>();
280 if (background_given
)
281 cc::go_background(vm
[OPT__LOG_FILE
].as
<std::string
>(), omit
);
284 // Omit std output. Note that --background flips this above.
286 cc::log
.push(cc::omit_sink(omit
));
287 cc::log
.setf(std::ios::fixed
);
291 if_optsw_given(vm
, OPT__PRINT_STREAMS
)
292 return print_streams(query
, qopts
, input_urls
, vm
);
294 #if defined (HAVE_FORK) && defined (HAVE_GETPID)
295 if (background_given
)
298 << "Running in background (pid: "
299 << static_cast<long>(getpid())
305 // For each input URL.
309 const int max_retries
= vm
[OPT__MAX_RETRIES
].as
<cc::max_retries
>().value();
310 const int retry_wait
= vm
[OPT__RETRY_WAIT
].as
<cc::retry_wait
>().value();
314 BOOST_FOREACH(const std::string
& url
, input_urls
)
322 while (retry
<= max_retries
)
324 print_retrying(retry
, max_retries
, retry_wait
);
327 print_checking(i
, n
);
332 set_stream(url
, qopts
, vm
);
333 _curl
= query
.setup_curl(vm
);
334 m
= query
.parse(url
, qopts
);
336 catch(const quvi::error
& e
)
338 if (e
.cannot_retry())
344 cc::get(m
, _curl
, vm
);
345 break; // Stop retrying.
350 catch(const quvi::error
& e
)
353 es
= application::error
;
356 catch(const std::runtime_error
& e
)
358 cc::log
<< "error: " << e
.what() << std::endl
;
359 es
= application::error
;
367 // vim: set ts=2 sw=2 tw=72 expandtab: