struct mp_resolve_result *mp_resolve_quvi(const char *url, struct MPOpts *opts) { quvi_t q = quvi_new(); if (quvi_ok(q) == QUVI_FALSE) return NULL; // Don't try to use quvi on an URL that's not directly supported, since // quvi will do a network access anyway in order to check for HTTP // redirections etc. // The documentation says this will fail on "shortened" URLs. if (quvi_supports(q, (char *) url, QUVI_SUPPORTS_MODE_OFFLINE, QUVI_SUPPORTS_TYPE_ANY) == QUVI_FALSE) { quvi_free(q); return NULL; } mp_msg(MSGT_OPEN, MSGL_INFO, "[quvi] Checking URL...\n"); // Can use quvi_query_formats() to get a list of formats like this: // "fmt05_240p|fmt18_360p|fmt34_360p|fmt35_480p|fmt43_360p|fmt44_480p" // (This example is youtube specific.) // That call requires an extra net access. quvi_next_media_url() doesn't // seem to do anything useful. So we can't really do anything useful // except pass through the user's format setting. quvi_media_t m = quvi_media_new(q, (char *) url); if (quvi_ok(q) == QUVI_FALSE) { mp_msg(MSGT_OPEN, MSGL_ERR, "[quvi] %s\n", quvi_errmsg(q)); quvi_free(q); return NULL; } quvi_media_stream_select(m, opts->quvi_format); if (quvi_ok(q) == QUVI_FALSE) { mp_msg(MSGT_OPEN, MSGL_ERR, "[quvi] %s\n", quvi_errmsg(q)); quvi_free(q); return NULL; } struct mp_resolve_result *result = talloc_zero(NULL, struct mp_resolve_result); char *val; quvi_media_get(m, QUVI_MEDIA_STREAM_PROPERTY_URL, &val); if (quvi_ok(q) == QUVI_TRUE) result->url = talloc_strdup(result, val); quvi_media_get(m, QUVI_MEDIA_PROPERTY_TITLE, &val); if (quvi_ok(q) == QUVI_TRUE) result->title = talloc_strdup(result, val); quvi_media_free(m); quvi_free(q); if (!result->url) { talloc_free(result); result = NULL; } return result; }
/* Choose subtitle language from the available languages. */ gint lutil_choose_subtitle(const quvi_t q, const quvi_subtitle_t qsub, const gchar *lang, const lutil_cb_printerr xperr, quvi_subtitle_lang_t *l, const gboolean fail_if_none) { g_assert(xperr != NULL); g_assert(lang != NULL); g_assert(qsub != NULL); g_assert(q != NULL); *l = quvi_subtitle_select(qsub, lang); if (quvi_ok(q) == QUVI_FALSE) { xperr(_("libquvi: while selecting subtitle: %s"), quvi_errmsg(q)); return (EXIT_FAILURE); } else { if (*l == NULL && fail_if_none == TRUE) { xperr(_("libquvi: failed to find any subtitles")); return (EXIT_FAILURE); } return (EXIT_SUCCESS); } }
static gint _copy_subtitle(const gchar *mfpath, const gchar *url, lutil_cb_printerr xperr) { quvi_subtitle_lang_t ql; quvi_subtitle_t qsub; gint r; if (opts.core.subtitle_language == NULL) return (EXIT_SUCCESS); qsub = quvi_subtitle_new(q, url); if (quvi_ok(q) == FALSE) { xperr(_("libquvi: while querying subtitles: %s"), quvi_errmsg(q)); return (EXIT_FAILURE); } _dump_languages(qsub); r = lutil_choose_subtitle(q, qsub, opts.core.subtitle_language, xperr, &ql, FALSE); if (r == EXIT_SUCCESS) { if (ql != NULL) { quvi_subtitle_export_t qse; qse = quvi_subtitle_export_new(ql, opts.core.subtitle_export_format); if (quvi_ok(q) == TRUE) r = _write_subtitle(ql, qse, mfpath, xperr); else xperr(_("libquvi: while exporting subtitle: %s"), quvi_errmsg(q)); quvi_subtitle_export_free(qse); } else g_print(_("skip <transfer>: subtitle extraction\n")); } quvi_subtitle_free(qsub); return (r); }
/* Choose a stream from the available streams. */ gint lutil_choose_stream(const quvi_t q, const quvi_media_t qm, const gchar *stream, const lutil_cb_printerr xperr) { g_assert(stream != NULL); g_assert(xperr != NULL); g_assert(qm != NULL); g_assert(q != NULL); quvi_media_stream_select(qm, stream); if (quvi_ok(q) == QUVI_FALSE) { xperr(_("libquvi: while selecting stream: %s"), quvi_errmsg(q)); return (EXIT_FAILURE); } return (EXIT_SUCCESS); }
/* Resolve URL redirections with exception rules. */ gchar *l_exec_util_resolve_redirections(_quvi_t q, const gchar *url) { lua_State *l; gchar *r; q->status.rc = l_load_util_script(q, script_fname, script_func); if (quvi_ok(q) == QUVI_FALSE) return (NULL); l = q->handle.lua; l_setfield_s(l, US_INPUT_URL, url, -1); /* Set as qargs.input_url */ /* * 1=qargs [qargs: set in l_load_util_script] * 1=returns a string */ if (lua_pcall(l, 1, 1, 0)) { g_string_assign(q->status.errmsg, lua_tostring(l, -1)); /* Keep error code if it was set by a callback: quvi.resolve * calling the network callback responsible for resolving URL * redirections. The error is most likely a network error. */ if (q->status.rc != QUVI_ERROR_CALLBACK) q->status.rc = QUVI_ERROR_SCRIPT; return (NULL); } r = NULL; if (lua_isstring(l, -1)) { const gchar *s = lua_tostring(l, -1); if (g_strcmp0(s, url) != 0) /* Ignore, unless it is different. */ r = g_strdup(s); } else luaL_error(l, "%s: did not return a string", script_func); lua_pop(l, 1); /* quvi.resolve which is called from the script sets q->status.rc . */ return (r); }