Update cc::applications for rewritten cc::input
[cclive.git] / src / cc / application.cpp
blob1a6b7933d8b7fd2831d4226fc97a0492926285b6
1 /* cclive
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/>.
21 #include <ccinternal>
23 #include <iomanip>
24 #include <vector>
25 #include <ctime>
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>
33 #include <ccquvi>
34 #include <ccapplication>
35 #include <ccoptions>
36 #include <ccinput>
37 #include <ccutil>
38 #include <cclog>
39 #include <ccre>
41 namespace cc
44 static void handle_fetch(const quvi_word type, void*)
46 #ifdef HAVE_LIBQUVI_0_9
47 if (type == QUVI_CALLBACK_STATUS_DONE)
48 #else
49 if (type == QUVISTATUSTYPE_DONE)
50 #endif
51 cc::log << " ";
54 static void print_done()
56 cc::log << "done.\n";
59 static void handle_verify(const quvi_word type)
61 #ifdef HAVE_LIBQUVI_0_9
62 if (type == QUVI_CALLBACK_STATUS_DONE)
63 #else
64 if (type == QUVISTATUSTYPE_DONE)
65 #endif
66 print_done();
69 static void handle_resolve(const quvi_word type)
71 #ifdef HAVE_LIBQUVI_0_9
72 if (type == QUVI_CALLBACK_STATUS_DONE)
73 #else
74 if (type == QUVISTATUSTYPE_DONE)
75 #endif
76 cc::log << " ";
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)
83 cc::log << ".";
84 switch (status)
86 case QUVI_CALLBACK_STATUS_FETCH:
87 handle_fetch(type, data);
88 break;
89 case QUVI_CALLBACK_STATUS_HTTP_QUERY_METAINFO:
90 handle_verify(type);
91 break;
92 case QUVI_CALLBACK_STATUS_RESOLVE:
93 handle_resolve(type);
94 break;
97 #else
98 static void status_callback_pt4(const quvi_word status, const quvi_word type,
99 void *data)
101 cc::log << ".";
102 switch (status)
104 case QUVISTATUS_FETCH:
105 handle_fetch(type, data);
106 break;
107 case QUVISTATUS_VERIFY:
108 handle_verify(type);
109 break;
110 case QUVISTATUS_RESOLVE:
111 handle_resolve(type);
112 break;
115 #endif
117 #ifdef HAVE_LIBQUVI_0_9
118 static int status_callback(long status_type, void *data, void *userdata)
119 #else
120 static int status_callback(long status_type, void *data)
121 #endif
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);
128 #else
129 status_callback_pt4(status, type, data);
130 #endif
131 cc::log << std::flush;
133 return QUVI_OK;
136 static void print_retrying(const int retry,
137 const int max_retries,
138 const int retry_wait)
140 if (retry > 0)
142 cc::log
143 << "Retrying "
144 << retry
145 << " of "
146 << max_retries
147 << " ... "
148 << std::flush;
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)
170 vst v;
171 boost::split(v, s, boost::is_any_of("|,"));
172 const size_t m = v.size();
174 if (m ==0)
175 v.push_back("default");
177 std::stringstream r;
178 r << "\n";
180 size_t i = 0, c = 0;
181 BOOST_FOREACH(const std::string& a, v)
183 r << boost::format("%|22s|") % a;
184 ++c;
185 if (++i ==3)
187 if (c <m)
188 r << "\n";
189 i = 0;
192 return r.str();
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();
200 size_t i = 0;
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);
210 print_done();
212 cc::log << "streams (found):" << format_streams(r) << std::endl;
214 catch(const quvi::error& e)
216 print_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(":"));
230 if (vb.size() == 2)
232 // vb[0] = pattern
233 // vb[1] = format
234 if (cc::re::grep(vb[0], url))
236 fmt = vb[1];
237 return;
240 vb.clear();
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);
250 qopts.stream = r;
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();
258 // Parse input.
260 const vst& input_urls = cc::input::parse(vm);
261 const size_t n = input_urls.size();
263 // Set up quvi.
265 quvi::query query; // Throws quvi::error caught in main.cpp
267 quvi::options qopts;
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;
272 // Omit flag.
274 bool omit = vm[OPT__QUIET].as<bool>();
276 // Go to background.
278 #ifdef HAVE_FORK
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);
282 #endif
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);
289 // Print streams.
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)
297 cc::log
298 << "Running in background (pid: "
299 << static_cast<long>(getpid())
300 << ")."
301 << std::endl;
303 #endif
305 // For each input URL.
307 size_t i = 0;
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();
312 exit_status es = ok;
314 BOOST_FOREACH(const std::string& url, input_urls)
316 ++i;
320 int retry = 0;
322 while (retry <= max_retries)
324 print_retrying(retry, max_retries, retry_wait);
325 ++retry;
327 print_checking(i, n);
328 quvi::media m;
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())
339 throw e;
340 else
341 print_quvi_error(e);
344 cc::get(m, _curl, vm);
345 break; // Stop retrying.
347 es = ok;
350 catch(const quvi::error& e)
352 print_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;
362 return es;
365 } // namespace cc
367 // vim: set ts=2 sw=2 tw=72 expandtab: