00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00032
00033 #ifdef HAVE_CONFIG_H
00034 #include "autoconfig.h"
00035 #endif
00036
00037 #ifdef YOUTUBE
00038
00039 #include <pthread.h>
00040
00041 #include "youtube_video_url.h"
00042 #include "tools.h"
00043 #include "url.h"
00044
00045 using namespace zmm;
00046
00047 #define YOUTUBE_URL_PARAMS_REGEXP "SWF_ARGS.*\\}"
00048 #define YOUTUBE_URL_LOCATION_REGEXP "\nLocation: (http://[^\n]+)\n"
00049 #define YOUTUBE_URL_WATCH "http://www.youtube.com/watch?v="
00050 #define YOUTUBE_URL_GET "http://www.youtube.com/get_video?"
00051 #define YOUTUBE_URL_PARAM_VIDEO_ID "video_id"
00052 #define YOUTUBE_URL_PARAM_T_REGEXP ".*\"t\": \"([^\"]+)\""
00053 #define YOUTUBE_URL_PARAM_T "t"
00054 #define YOUTUBE_IS_HD_AVAILABLE_REGEXP "IS_HD_AVAILABLE[^:]*: *([^,]*)"
00055 YouTubeVideoURL::YouTubeVideoURL()
00056 {
00057 curl_handle = curl_easy_init();
00058 if (!curl_handle)
00059 throw _Exception(_("failed to initialize curl!\n"));
00060
00061 reVideoURLParams = Ref<RExp>(new RExp());
00062 reVideoURLParams->compile(_(YOUTUBE_URL_PARAMS_REGEXP));
00063 redirectLocation = Ref<RExp>(new RExp());
00064 redirectLocation->compile(_(YOUTUBE_URL_LOCATION_REGEXP));
00065 param_t = Ref<RExp>(new RExp());
00066 param_t->compile(_(YOUTUBE_URL_PARAM_T_REGEXP));
00067
00068 HD = Ref<RExp>(new RExp());
00069 HD->compile(_(YOUTUBE_IS_HD_AVAILABLE_REGEXP));
00070
00071
00072
00073
00074 pid = pthread_self();
00075 }
00076
00077 YouTubeVideoURL::~YouTubeVideoURL()
00078 {
00079 if (curl_handle)
00080 curl_easy_cleanup(curl_handle);
00081 }
00082
00083 String YouTubeVideoURL::getVideoURL(String video_id, bool mp4, bool hd)
00084 {
00085 long retcode;
00086 String flv_location;
00087 String watch;
00088 #ifdef TOMBDEBUG
00089 bool verbose = true;
00090 #else
00091 bool verbose = false;
00092 #endif
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115 if (!string_ok(video_id))
00116 throw _Exception(_("No video ID specified!"));
00117
00118 watch = _(YOUTUBE_URL_WATCH) + video_id;
00119
00120 Ref<URL> url(new URL(YOUTUBE_PAGESIZE));
00121
00122 Ref<StringBuffer> buffer = url->download(watch, &retcode, curl_handle,
00123 false, verbose, true);
00124 if (retcode != 200)
00125 {
00126 throw _Exception(_("Failed to get URL for video with id ")
00127 + watch + _("HTTP response code: ") +
00128 String::from(retcode));
00129 }
00130
00131 log_debug("------> GOT BUFFER %s\n", buffer->toString().c_str());
00132
00133 Ref<Matcher> matcher = reVideoURLParams->matcher(buffer->toString());
00134 String params;
00135 if (matcher->next())
00136 {
00137
00138 params = trim_string( matcher->group( 0 ) );
00139
00140
00141
00142
00143
00144
00145
00146
00147 Ref<Matcher> m2 = param_t->matcher(params);
00148 if (m2->next())
00149 {
00150 String hmm = m2->group(1);
00151 if (string_ok(hmm))
00152 params = hmm;
00153 else
00154 {
00155 throw _Exception(_("Could not retrieve \"t\" parameter."));
00156 }
00157 }
00158 }
00159 else
00160 {
00161 throw _Exception(_("Failed to get URL for video with id (step 1)") + video_id);
00162 }
00163
00164 params = _(YOUTUBE_URL_GET) + YOUTUBE_URL_PARAM_VIDEO_ID + '=' +
00165 video_id + '&' + YOUTUBE_URL_PARAM_T + '=' + params;
00166
00167 if (mp4)
00168 {
00169 String format = _("&fmt=18");
00170
00171 if (hd)
00172 {
00173 matcher = HD->matcher(buffer->toString());
00174 if (matcher->next())
00175 {
00176 if (trim_string(matcher->group(1)) == "true")
00177 format = _("&fmt=22");
00178 }
00179 }
00180
00181 params = params + format;
00182 }
00183
00184 buffer = url->download(params, &retcode, curl_handle, true, verbose, true);
00185
00186 matcher = redirectLocation->matcher(buffer->toString());
00187 if (matcher->next())
00188 {
00189 if (string_ok(trim_string(matcher->group(1))))
00190 return trim_string(matcher->group(1));
00191 else
00192 throw _Exception(_("Failed to get URL for video with id (step 2)")+
00193 video_id);
00194 }
00195
00196 if (retcode != 303)
00197 {
00198 throw _Exception(_("Unexpected reply from YouTube: ") +
00199 String::from(retcode));
00200 }
00201
00202 throw _Exception(_("Could not retrieve YouTube video URL"));
00203 }
00204
00205 #endif//YOUTUBE