experimental yt cache (currently no gui integration)

Conflicts:
	src/gui/moviebrowser.cpp
	src/gui/movieinfo.cpp
	src/system/Makefile.am


Origin commit data
------------------
Commit: 70e5e66327
Author: martii <m4rtii@gmx.de>
Date: 2013-06-12 (Wed, 12 Jun 2013)
This commit is contained in:
martii
2013-06-12 17:16:22 +02:00
committed by [CST] Focus
parent ea3897e6bd
commit f717d3598f
9 changed files with 412 additions and 84 deletions

View File

@@ -64,6 +64,7 @@
#include <gui/customcolor.h> #include <gui/customcolor.h>
#include <driver/record.h> #include <driver/record.h>
#include <system/helpers.h> #include <system/helpers.h>
#include <system/ytcache.h>
#include <timerdclient/timerdclient.h> #include <timerdclient/timerdclient.h>
#include <system/hddstat.h> #include <system/hddstat.h>
@@ -1084,6 +1085,10 @@ int CMovieBrowser::exec(const char* path)
TRACE("[mb] stop: %d start:%d \r\n",m_movieSelectionHandler->bookmarks.lastPlayStop,m_movieSelectionHandler->bookmarks.start); TRACE("[mb] stop: %d start:%d \r\n",m_movieSelectionHandler->bookmarks.lastPlayStop,m_movieSelectionHandler->bookmarks.start);
m_currentStartPos = showStartPosSelectionMenu(); // display start menu m_currentStartPos = m_currentStartPos = showStartPosSelectionMenu(); // display start menu m_currentStartPos =
} }
if (show_mode == MB_SHOW_YT)
cYTCache::getInstance()->useCachedCopy(m_movieSelectionHandler);
if(m_currentStartPos >= 0) { if(m_currentStartPos >= 0) {
playing_info = m_movieSelectionHandler; playing_info = m_movieSelectionHandler;
TRACE("[mb] start pos: %d s\r\n",m_currentStartPos); TRACE("[mb] start pos: %d s\r\n",m_currentStartPos);
@@ -1093,6 +1098,10 @@ int CMovieBrowser::exec(const char* path)
refresh(); refresh();
} }
} }
else if ((show_mode == MB_SHOW_YT) && (msg == CRCInput::RC_record) && m_movieSelectionHandler)
{
cYTCache::getInstance()->addToCache(m_movieSelectionHandler);
}
else if (msg == CRCInput::RC_home) else if (msg == CRCInput::RC_home)
{ {
loop = false; loop = false;
@@ -1280,8 +1289,8 @@ std::string CMovieBrowser::getScreenshotName(std::string movie)
std::string ext; std::string ext;
std::string ret; std::string ret;
size_t found = movie.rfind(".ts"); size_t found = movie.find_last_of(".");
if ((found == string::npos) || (found != (movie.length() - 3))) if (found == string::npos)
return ""; return "";
vector<std::string>::iterator it = PicExts.begin(); vector<std::string>::iterator it = PicExts.begin();
@@ -3692,9 +3701,9 @@ void CMovieBrowser::loadYTitles(int mode, std::string search, std::string id)
movieInfo.tfile = ylist[i].tfile; movieInfo.tfile = ylist[i].tfile;
movieInfo.ytdate = ylist[i].published; movieInfo.ytdate = ylist[i].published;
movieInfo.ytid = ylist[i].id; movieInfo.ytid = ylist[i].id;
movieInfo.file.Name = ylist[i].title; movieInfo.file.Name = ylist[i].title;
movieInfo.file.Url = ylist[i].GetUrl(m_settings.ytquality, false); movieInfo.ytitag = m_settings.ytquality;
movieInfo.file.Url = ylist[i].GetUrl(&movieInfo.ytitag, false);
movieInfo.file.Time = toEpoch(movieInfo.ytdate); movieInfo.file.Time = toEpoch(movieInfo.ytdate);
m_vMovieInfo.push_back(movieInfo); m_vMovieInfo.push_back(movieInfo);
} }
@@ -4371,7 +4380,7 @@ static void save_info(CMovieInfo * cmovie, MI_MOVIE_INFO * minfo, char * dpart,
{ {
MI_MOVIE_INFO ninfo; MI_MOVIE_INFO ninfo;
cmovie->copy(minfo, &ninfo); ninfo = *minfo;
ninfo.file.Name = dpart; ninfo.file.Name = dpart;
ninfo.file.Size = spos; ninfo.file.Size = spos;
ninfo.length = spos/secsize/60; ninfo.length = spos/secsize/60;

View File

@@ -97,24 +97,13 @@ bool CMovieInfo::convertTs2XmlName(char *char_filename, int size)
************************************************************************/ ************************************************************************/
bool CMovieInfo::convertTs2XmlName(std::string * filename) bool CMovieInfo::convertTs2XmlName(std::string * filename)
{ {
//TRACE("[mi]->convertTs2XmlName\r\n"); size_t lastdot = filename->find_last_of(".");
int bytes = filename->find(".ts"); if (lastdot != string::npos) {
bool result = false; filename->erase(lastdot + 1);
filename->append("xml");
if (bytes != -1) { return true;
if (bytes > 3) {
if ((*filename)[bytes - 4] == '.') {
bytes = bytes - 4;
}
}
*filename = filename->substr(0, bytes) + ".xml";
result = true;
} else // not a TS file, return!!!!!
{
//TRACE(" not a TS file ");
} }
return false;
return (result);
} }
/************************************************************************ /************************************************************************
@@ -886,6 +875,7 @@ void CMovieInfo::clearMovieInfo(MI_MOVIE_INFO * movie_info)
timePlay.tm_mon = 1; timePlay.tm_mon = 1;
movie_info->file.Name = ""; movie_info->file.Name = "";
movie_info->file.Url = "";
movie_info->file.Size = 0; // Megabytes movie_info->file.Size = 0; // Megabytes
movie_info->file.Time = mktime(&timePlay); movie_info->file.Time = mktime(&timePlay);
movie_info->dateOfLastPlay = mktime(&timePlay); // (date, month, year) movie_info->dateOfLastPlay = mktime(&timePlay); // (date, month, year)
@@ -925,6 +915,7 @@ void CMovieInfo::clearMovieInfo(MI_MOVIE_INFO * movie_info)
movie_info->tfile.clear(); movie_info->tfile.clear();
movie_info->ytdate.clear(); movie_info->ytdate.clear();
movie_info->ytid.clear(); movie_info->ytid.clear();
movie_info->ytitag = 0;
movie_info->marked = false; movie_info->marked = false;
} }
@@ -1028,52 +1019,57 @@ bool CMovieInfo::saveFile_vlc(const CFile & /*file*/, const char */*text*/, cons
* *
* */ * */
void CMovieInfo::copy(MI_MOVIE_INFO * src, MI_MOVIE_INFO * dst) #if 0
MI_MOVIE_INFO& MI_MOVIE_INFO::operator=(const MI_MOVIE_INFO& src)
{ {
//TRACE("[mi]->clearMovieInfo \r\n"); file.Name = src.file.Name;
file.Url = src.file.Url;
file.Size = src.file.Size;
file.Time = src.file.Time;
dateOfLastPlay = src.dateOfLastPlay;
dirItNr = src.dirItNr;
genreMajor = src.genreMajor;
genreMinor = src.genreMinor;
length = src.length;
quality = src.quality;
productionDate = src.productionDate;
parentalLockAge = src.parentalLockAge;
format = src.format;
audio = src.audio;
dst->file.Name = src->file.Name; epgId = src.epgId;
dst->file.Size = src->file.Size; epgEpgId = src.epgEpgId;
dst->file.Time = src->file.Time; epgMode = src.epgMode;
dst->dateOfLastPlay = src->dateOfLastPlay; epgVideoPid = src.epgVideoPid;
dst->dirItNr = src->dirItNr; VideoType = src.VideoType;
dst->genreMajor = src->genreMajor; epgVTXPID = src.epgVTXPID;
dst->genreMinor = src->genreMinor;
dst->length = src->length;
dst->quality = src->quality;
dst->productionDate = src->productionDate;
dst->parentalLockAge = src->parentalLockAge;
dst->format = src->format;
dst->audio = src->audio;
dst->epgId = src->epgId; productionCountry = src.productionCountry;
dst->epgEpgId = src->epgEpgId; epgTitle = src.epgTitle;
dst->epgMode = src->epgMode; epgInfo1 = src.epgInfo1;
dst->epgVideoPid = src->epgVideoPid; epgInfo2 = src.epgInfo2;
dst->VideoType = src->VideoType; epgChannel = src.epgChannel;
dst->epgVTXPID = src->epgVTXPID; serieName = src.serieName;
bookmarks.end = src.bookmarks.end;
bookmarks.start = src.bookmarks.start;
bookmarks.lastPlayStop = src.bookmarks.lastPlayStop;
dst->productionCountry = src->productionCountry; for (unsigned int i = 0; i < MI_MOVIE_BOOK_USER_MAX; i++) {
dst->epgTitle = src->epgTitle; bookmarks.user[i].pos = src.bookmarks.user[i].pos;
dst->epgInfo1 = src->epgInfo1; bookmarks.user[i].length = src.bookmarks.user[i].length;
dst->epgInfo2 = src->epgInfo2; bookmarks.user[i].name = src.bookmarks.user[i].name;
dst->epgChannel = src->epgChannel;
dst->serieName = src->serieName;
dst->bookmarks.end = src->bookmarks.end;
dst->bookmarks.start = src->bookmarks.start;
dst->bookmarks.lastPlayStop = src->bookmarks.lastPlayStop;
for (int i = 0; i < MI_MOVIE_BOOK_USER_MAX; i++) {
dst->bookmarks.user[i].pos = src->bookmarks.user[i].pos;
dst->bookmarks.user[i].length = src->bookmarks.user[i].length;
dst->bookmarks.user[i].name = src->bookmarks.user[i].name;
} }
for (unsigned int i = 0; i < src->audioPids.size(); i++) { for (unsigned int i = 0; i < src.audioPids.size(); i++) {
EPG_AUDIO_PIDS audio_pids; EPG_AUDIO_PIDS audio_pids;
audio_pids.epgAudioPid = src->audioPids[i].epgAudioPid; audio_pids.epgAudioPid = src.audioPids[i].epgAudioPid;
audio_pids.epgAudioPidName = src->audioPids[i].epgAudioPidName; audio_pids.epgAudioPidName = src.audioPids[i].epgAudioPidName;
audio_pids.atype = src->audioPids[i].atype; audio_pids.atype = src.audioPids[i].atype;
dst->audioPids.push_back(audio_pids); audioPids.push_back(audio_pids);
} }
ytdate = src.ytdate;
ytid = src.ytid;
ytitag = src.ytitag;
return *this;
} }
#endif

View File

@@ -46,12 +46,15 @@
#ifndef MOVIEINFO_H_ #ifndef MOVIEINFO_H_
#define MOVIEINFO_H_ #define MOVIEINFO_H_
#define __USE_FILE_OFFSET64 1
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
#include <config.h> #include <config.h>
#endif #endif
#include <string> #include <string>
#include <vector> #include <vector>
#include <stdint.h>
#include "driver/file.h" #include "driver/file.h"
/************************************************************************/ /************************************************************************/
@@ -140,8 +143,10 @@ typedef struct
/************************************************************************/ /************************************************************************/
/************************************************************************/ /************************************************************************/
typedef struct class MI_MOVIE_INFO
{ {
public:
// MI_MOVIE_INFO &operator=(const MI_MOVIE_INFO& src);
CFile file; // not stored in xml CFile file; // not stored in xml
std::string productionCountry; // user defined Country (not from EPG yet, but might be possible) std::string productionCountry; // user defined Country (not from EPG yet, but might be possible)
std::string epgTitle; // plain movie name, usually filled by EPG std::string epgTitle; // plain movie name, usually filled by EPG
@@ -173,7 +178,8 @@ typedef struct
std::string tfile; // thumbnail/cover file name std::string tfile; // thumbnail/cover file name
std::string ytdate; // yt published std::string ytdate; // yt published
std::string ytid; // yt published std::string ytid; // yt published
} MI_MOVIE_INFO; int ytitag; // youtube quality profile
};
typedef std::vector<MI_MOVIE_INFO> MI_MOVIE_LIST; typedef std::vector<MI_MOVIE_INFO> MI_MOVIE_LIST;
typedef std::vector<MI_MOVIE_INFO*> P_MI_MOVIE_LIST; typedef std::vector<MI_MOVIE_INFO*> P_MI_MOVIE_LIST;
@@ -192,7 +198,6 @@ class CMovieInfo
void printDebugMovieInfo(MI_MOVIE_INFO& movie_info); // print movie info on debug channel (RS232) void printDebugMovieInfo(MI_MOVIE_INFO& movie_info); // print movie info on debug channel (RS232)
void clearMovieInfo(MI_MOVIE_INFO* movie_info); // Set movie info structure to initial values void clearMovieInfo(MI_MOVIE_INFO* movie_info); // Set movie info structure to initial values
bool addNewBookmark(MI_MOVIE_INFO* movie_info,MI_BOOKMARK &new_bookmark); // add a new bookmark to the given movie info. If there is no space false is returned bool addNewBookmark(MI_MOVIE_INFO* movie_info,MI_BOOKMARK &new_bookmark); // add a new bookmark to the given movie info. If there is no space false is returned
void copy(MI_MOVIE_INFO* src, MI_MOVIE_INFO* dst);
private:// Functions private:// Functions
bool parseXmlTree (char* text, MI_MOVIE_INFO* movie_info); // this is the 'good' function, but it needs the xmllib which is not currently linked within neutrino. Might be to slow as well. If used, add bookmark parsing bool parseXmlTree (char* text, MI_MOVIE_INFO* movie_info); // this is the 'good' function, but it needs the xmllib which is not currently linked within neutrino. Might be to slow as well. If used, add bookmark parsing

View File

@@ -44,5 +44,6 @@ libneutrino_system_a_SOURCES = \
ping.cpp \ ping.cpp \
settings.cpp \ settings.cpp \
sysload.cpp \ sysload.cpp \
ytcache.cpp \
ytparser.cpp \ ytparser.cpp \
setting_helpers.cpp setting_helpers.cpp

View File

@@ -509,7 +509,7 @@ bool CFileHelpers::copyFile(const char *Src, const char *Dst, mode_t mode)
unlink(Dst); unlink(Dst);
if ((fd1 = open(Src, O_RDONLY)) < 0) if ((fd1 = open(Src, O_RDONLY)) < 0)
return false; return false;
if ((fd2 = open(Dst, O_WRONLY | O_CREAT, 0666)) < 0) { if ((fd2 = open(Dst, O_WRONLY | O_CREAT, mode)) < 0) {
close(fd1); close(fd1);
return false; return false;
} }
@@ -574,7 +574,6 @@ bool CFileHelpers::copyFile(const char *Src, const char *Dst, mode_t mode)
return false; return false;
} }
chmod(Dst, mode);
return true; return true;
} }

254
src/system/ytcache.cpp Normal file
View File

@@ -0,0 +1,254 @@
/*
ytcache.cpp -- cache youtube movies
Copyright (C) 2013 martii
License: GPL
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "ytcache.h"
#include <OpenThreads/ScopedLock>
#include <stdio.h>
#include <unistd.h>
#include <curl/curl.h>
#include <curl/easy.h>
#if LIBCURL_VERSION_NUM < 0x071507
#include <curl/types.h>
#endif
#define URL_TIMEOUT 60
#include "helpers.h"
#include "settings.h"
#include <global.h>
static cYTCache *instance = NULL;
cYTCache::cYTCache(void)
{
cancelled = false;
thread = 0;
}
cYTCache::~cYTCache(void)
{
instance = NULL;
}
cYTCache *cYTCache::getInstance(void)
{
if (!instance)
instance = new cYTCache();
return instance;
}
std::string cYTCache::getName(MI_MOVIE_INFO *mi, std::string ext)
{
char ytitag[10];
snprintf(ytitag, sizeof(ytitag), "%d", mi->ytitag);
return g_settings.downloadcache_dir + "/" + mi->ytid + "-" + std::string(ytitag) + "." + ext;
}
bool cYTCache::useCachedCopy(MI_MOVIE_INFO *mi)
{
std::string cache = getName(mi);
if (!access(cache.c_str(), R_OK)) {
mi->file.Url = cache;
return true;
}
return false;
}
int cYTCache::curlProgress(void *clientp, double /*dltotal*/, double /*dlnow*/, double /*ultotal*/, double /*ulnow*/)
{
cYTCache *caller = (cYTCache *) clientp;
if (caller->cancelled)
return 1;
return 0;
}
bool cYTCache::download(MI_MOVIE_INFO *mi)
{
std::string file = getName(mi);
std::string tmpfile = file + ".tmp";
if (!access(file.c_str(), R_OK) || !access(tmpfile.c_str(), R_OK))
return true;
FILE * fp = fopen(file.c_str(), "wb");
if (!fp) {
perror(file.c_str());
return false;
}
CURL *curl = curl_easy_init();
if (!curl) {
fclose(fp);
return false;
}
curl_easy_setopt(curl, CURLOPT_URL, mi->file.Url.c_str());
curl_easy_setopt(curl, CURLOPT_FILE, fp);
curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, URL_TIMEOUT);
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, (long)1);
curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, cYTCache::curlProgress);
curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, this);
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, (long)0);
char cerror[CURL_ERROR_SIZE];
curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, cerror);
CURLcode res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
fclose(fp);
if (res) {
fprintf(stderr, "curl error: %s\n", cerror);
unlink(tmpfile.c_str());
return false;
}
rename (tmpfile.c_str(), file.c_str());
CMovieInfo cMovieInfo;
CFile File;
File.Name = getName(mi, "xml");
cMovieInfo.convertTs2XmlName(&File.Name);
cMovieInfo.saveMovieInfo(*mi, &File);
std::string thumbnail_dst = getName(mi, "jpg");
std::string thumbnail_src = "/tmp/ytparser/" + mi->ytid + ".jpg";
CFileHelpers::getInstance()->copyFile(thumbnail_src.c_str(), thumbnail_dst.c_str(), 0644);
return true;
}
void *cYTCache::downloadThread(void *arg) {
cYTCache *caller = (cYTCache *)arg;
while (caller->thread) {
MI_MOVIE_INFO mi;
{
OpenThreads::ScopedLock<OpenThreads::Mutex> m_lock(caller->mutex);
if (caller->pending.empty()) {
caller->cancelled = false;
caller->thread = 0;
continue;
}
mi = caller->pending.front();
}
fprintf(stderr, "download start: %s\n", mi.file.Url.c_str());
bool res = caller->download(&mi);
fprintf(stderr, "download end: %s %s\n", mi.file.Url.c_str(), res ? "succeeded" : "failed");
{
OpenThreads::ScopedLock<OpenThreads::Mutex> m_lock(caller->mutex);
if (res)
caller->done.push_front(mi);
else
caller->failed.push_front(mi);
caller->cancelled = false;
if (caller->pending.empty())
caller->thread = 0;
else
caller->pending.pop_front();
}
}
pthread_exit(NULL);
}
bool cYTCache::addToCache(MI_MOVIE_INFO *mi)
{
OpenThreads::ScopedLock<OpenThreads::Mutex> m_lock(mutex);
pending.push_back(*mi);
if (!thread) {
if (pthread_create(&thread, NULL, downloadThread, this)) {
perror("pthread_create");
return false;
}
pthread_detach(thread);
}
return true;
}
void cYTCache::cancel(MI_MOVIE_INFO *mi)
{
OpenThreads::ScopedLock<OpenThreads::Mutex> m_lock(mutex);
if (pending.empty())
return;
if (compareMovieInfo(mi, &pending.front())) {
cancelled = true;
return;
}
for (std::list<MI_MOVIE_INFO>::iterator it = pending.begin(); it != pending.end(); ++it)
if (compareMovieInfo(&(*it), mi)) {
pending.erase(it);
break;
}
}
void cYTCache::cancelAll(void)
{
OpenThreads::ScopedLock<OpenThreads::Mutex> m_lock(mutex);
if (pending.empty())
return;
cancelled = true;
while (thread)
usleep(100000);
cancelled = false;
pending.clear();
}
std::list<MI_MOVIE_INFO> cYTCache::getFailed(bool clear)
{
OpenThreads::ScopedLock<OpenThreads::Mutex> m_lock(mutex);
std::list<MI_MOVIE_INFO> res = failed;
if (clear)
failed.clear();
return res;
}
std::list<MI_MOVIE_INFO> cYTCache::getDone(bool clear)
{
OpenThreads::ScopedLock<OpenThreads::Mutex> m_lock(mutex);
std::list<MI_MOVIE_INFO> res = done;
if (clear)
done.clear();
return res;
}
void cYTCache::clearFailed(void)
{
OpenThreads::ScopedLock<OpenThreads::Mutex> m_lock(mutex);
failed.clear();
}
void cYTCache::clearDone(void)
{
OpenThreads::ScopedLock<OpenThreads::Mutex> m_lock(mutex);
done.clear();
}
bool cYTCache::compareMovieInfo(MI_MOVIE_INFO *a, MI_MOVIE_INFO *b)
{
return a->ytid == b->ytid && a->ytitag == b->ytitag;
return true;
}

62
src/system/ytcache.h Normal file
View File

@@ -0,0 +1,62 @@
/*
ytcache.h -- cache youtube movies
Copyright (C) 2013 martii
License: GPL
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __YTCACHE_H__
#define __YTCACHE_H__
#include <config.h>
#include <string>
#include <list>
#include <OpenThreads/Thread>
#include <OpenThreads/Condition>
#include <gui/movieinfo.h>
class cYTCache
{
private:
pthread_t thread;
bool cancelled;
std::list<MI_MOVIE_INFO> pending;
std::list<MI_MOVIE_INFO> done;
std::list<MI_MOVIE_INFO> failed;
OpenThreads::Mutex mutex;
bool download(MI_MOVIE_INFO *mi);
std::string getName(MI_MOVIE_INFO *mi, std::string ext = "mp4");
static void *downloadThread(void *arg);
static int curlProgress(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow);
bool compareMovieInfo(MI_MOVIE_INFO *a, MI_MOVIE_INFO *b);
public:
static cYTCache *getInstance();
cYTCache();
~cYTCache();
bool useCachedCopy(MI_MOVIE_INFO *mi);
bool addToCache(MI_MOVIE_INFO *mi);
void cancel(MI_MOVIE_INFO *mi);
void cancelAll(void);
std::list<MI_MOVIE_INFO> getDone(bool clear = false);
std::list<MI_MOVIE_INFO> getFailed(bool clear = false);
void clearDone(void);
void clearFailed(void);
};
#endif

View File

@@ -63,27 +63,29 @@ void cYTVideoInfo::Dump()
printf("===================================================================\n"); printf("===================================================================\n");
} }
std::string cYTVideoInfo::GetUrl(int fmt, bool mandatory) std::string cYTVideoInfo::GetUrl(int *fmt, bool mandatory)
{ {
int default_fmt = 0;
if (!*fmt)
fmt = &default_fmt;
yt_urlmap_iterator_t it; yt_urlmap_iterator_t it;
if (fmt) { if (*fmt) {
if ((it = formats.find(fmt)) != formats.end()) if ((it = formats.find(*fmt)) != formats.end()) {
return it->second.GetUrl(); return it->second.GetUrl();
if (mandatory) }
if (mandatory) {
*fmt = 0;
return ""; return "";
}
} }
if ((it = formats.find(37)) != formats.end()) // 1080p MP4
return it->second.GetUrl(); int itags[] = { 37 /* 1080p MP4*/, 22 /* 720p MP4 */, 18 /* 270p/360p MP4 */, 0 };
if ((it = formats.find(22)) != formats.end()) // 720p MP4 for (int *fmtp = itags; *fmtp; fmtp++)
return it->second.GetUrl(); if ((it = formats.find(*fmtp)) != formats.end()) {
#if 0 *fmt = *fmtp;
if ((it = formats.find(35)) != formats.end()) // 480p FLV return it->second.GetUrl();
return it->second.GetUrl(); }
if ((it = formats.find(34)) != formats.end()) // 360p FLV
return it->second.GetUrl();
#endif
if ((it = formats.find(18)) != formats.end()) // 270p/360p MP4
return it->second.GetUrl();
return ""; return "";
} }

View File

@@ -62,7 +62,7 @@ class cYTVideoInfo
bool ret; bool ret;
void Dump(); void Dump();
std::string GetUrl(int fmt = 0, bool mandatory = true); std::string GetUrl(int *fmt = NULL, bool mandatory = true);
}; };