diff options
Diffstat (limited to 'tvdbmanager.c')
-rw-r--r-- | tvdbmanager.c | 926 |
1 files changed, 926 insertions, 0 deletions
diff --git a/tvdbmanager.c b/tvdbmanager.c new file mode 100644 index 0000000..ecb134c --- /dev/null +++ b/tvdbmanager.c @@ -0,0 +1,926 @@ +/* + * tvdbmanager.c + * + * See the README file for copyright information and how to reach the author. + * + */ + +#include "tvdbmanager.h" +#include "epgd.h" +#include "lib/curl.h" + +extern const char* confDir; + +using namespace std; + +cTVDBManager::cTVDBManager(void) { + bytesDownloaded = 0; + serverTime = 0; + tvdbScraper = NULL; + connection = NULL; + tSeries = NULL; + tSeriesEpsiode = NULL; + tSeriesMedia = NULL; + tSeriesActor = NULL; + tEvents = NULL; + tEpisodes = NULL; + tRecordingList = NULL; + + withutf8 = no; + exsltRegisterAll(); + setlocale(LC_CTYPE, ""); + char* lang; + lang = setlocale(LC_CTYPE, 0); + if (lang) { + if ((strcasestr(lang, "UTF-8") != 0) || (strcasestr(lang, "UTF8") != 0)){ + withutf8 = yes; + } + } + string loc = lang; + size_t index = loc.find_first_of("_"); + string langISO = ""; + if (index > 0) { + langISO = loc.substr(0, index); + } + if (langISO.size() == 2) { + language = langISO.c_str(); + } else { + language = "en"; + } + tell(0, "Using scraping language %s", language.c_str()); +} + +cTVDBManager::~cTVDBManager() { + if (tvdbScraper) + delete tvdbScraper; + if (tSeries) + delete tSeries; + if (tSeriesEpsiode) + delete tSeriesEpsiode; + if (tSeriesMedia) + delete tSeriesMedia; + if (tSeriesActor) + delete tSeriesActor; + if (tEvents) + delete tEvents; + if (tEpisodes) + delete tEpisodes; + if (tRecordingList) + delete tRecordingList; +} + +int cTVDBManager::ConnectDatabase(cDbConnection *conn) { + int status; + connection = conn; + if (!connection) + return fail; + tSeries = new cDbTable(connection, "series"); + if ((status = tSeries->open()) != success) + return status; + tSeriesEpsiode = new cDbTable(connection, "series_episode"); + if ((status = tSeriesEpsiode->open()) != success) + return status; + tSeriesMedia = new cDbTable(connection, "series_media"); + if ((status = tSeriesMedia->open()) != success) + return status; + tSeriesActor = new cDbTable(connection, "series_actor"); + if ((status = tSeriesActor->open()) != success) + return status; + tEvents = new cDbTable(connection, "events"); + if ((status = tEvents->open()) != success) + return status; + tEpisodes = new cDbTable(connection, "episodes"); + if ((status = tEpisodes->open()) != success) + return status; + tRecordingList = new cDbTable(connection, "recordinglist"); + if ((status = tRecordingList->open()) != success) + return status; + return success; +} + +bool cTVDBManager::ConnectScraper(void) { + tvdbScraper = new cTVDBScraper(language); + bool ok = tvdbScraper->Connect(); + return ok; +} + +void cTVDBManager::SetServerTime(void) { + serverTime = tvdbScraper->GetServerTime(); +} + +void cTVDBManager::UpdateSeries(void) { + set<int> updatedSeries; + set<int> updatedEpisodes; + set<int> storedSeries; + set<int> storedEpisodes; + int lastScrap = GetLastScrap(); + if (lastScrap < 1) + return; + bool ok = tvdbScraper->GetUpdatedSeriesandEpisodes(&updatedSeries, &updatedEpisodes, lastScrap); + if (!ok) return; + ok = GetAllIDs(&storedSeries, tSeries, "SeriesId"); + if (!ok) return; + ok = GetAllIDs(&storedEpisodes, tSeriesEpsiode, "EpisodeId"); + if (!ok) return; + + set<int> scrapSeriesIDs; + set<int> scrapEpisodeIDs; + set_intersection(updatedSeries.begin(), updatedSeries.end(), storedSeries.begin(), + storedSeries.end(), std::inserter(scrapSeriesIDs, scrapSeriesIDs.begin())); + set_intersection(updatedEpisodes.begin(), updatedEpisodes.end(), storedEpisodes.begin(), + storedEpisodes.end(), std::inserter(scrapEpisodeIDs, scrapEpisodeIDs.begin())); + + tell(0, "%ld updated Series, %ld updatedEpisodes", updatedSeries.size(), updatedEpisodes.size()); + tell(0, "%ld series to update in db, %ld episodes to update in db", scrapSeriesIDs.size(), scrapEpisodeIDs.size()); + int seriesCur = 1; + for (set<int>::iterator it = scrapSeriesIDs.begin(); !cEpgd::doShutDown && it != scrapSeriesIDs.end(); it++) { + if (seriesCur%10 == 0) + tell(0, "ReScraped %d series...continuing rescraping", seriesCur); + cTVDBSeries *series = ScrapSeries(*it); + if (series) { + SaveSeries(series); + } + delete series; + seriesCur++; + } + if (seriesCur > 1) + tell(0, "ReScraped %d series", seriesCur-1); + + int episodeCur = 1; + for (set<int>::iterator it = scrapEpisodeIDs.begin(); !cEpgd::doShutDown && it != scrapEpisodeIDs.end(); it++) { + if (episodeCur%10 == 0) + tell(0, "ReScraped %d Episodes...continuing rescraping", episodeCur); + cTVDBEpisode *episode = tvdbScraper->GetEpisode(*it); + episode->ReadEpisode(); + SaveSeriesEpisode(episode); + delete episode; + episodeCur++; + } + if (episodeCur > 1) + tell(0, "ReScraped %d Episodes", episodeCur-1); + + UpdateScrapTS(); +} + +int cTVDBManager::GetLastScrap(void) { + int status = success; + int lastScraped = 0; + cDbStatement *selectTime = new cDbStatement(tSeries); + selectTime->build("select "); + selectTime->bind("SeriesLastScraped", cDBS::bndOut); + selectTime->build(" from %s", tSeries->TableName()); + status += selectTime->prepare(); + if (status != success) { + delete selectTime; + return 0; + } + for (int res = selectTime->find(); res; res = selectTime->fetch()) { + lastScraped = tSeries->getIntValue("SeriesLastScraped"); + break; + } + selectTime->freeResult(); + delete selectTime; + return lastScraped; + +} + +void cTVDBManager::UpdateScrapTS(void) { + stringstream upd; + upd << "update " << tSeries->TableName() << " set series_last_scraped=" << serverTime << " where series_id > 0"; + cDbStatement updStmt(connection, upd.str().c_str()); + updStmt.prepare(); + updStmt.execute(); +} + +bool cTVDBManager::GetAllIDs(set<int> *IDs, cDbTable *table, const char* fname) { + int status = success; + cDbStatement *selectIDs = new cDbStatement(table); + selectIDs->build("select "); + selectIDs->bind(fname, cDBS::bndOut); + selectIDs->build(" from %s", table->TableName()); + status += selectIDs->prepare(); + if (status != success) { + delete selectIDs; + return false; + } + for (int res = selectIDs->find(); res; res = selectIDs->fetch()) { + IDs->insert(table->getIntValue(fname)); + } + selectIDs->freeResult(); + delete selectIDs; + return true; +} + +cTVDBSeries *cTVDBManager::ScrapSeries(string search) { + cTVDBSeries *series = tvdbScraper->ScrapInitial(search); + if (!series) { + return NULL; + } + series->ReadSeries(); + series->ReadMedia(); + series->ReadActors(); + return series; +} + +cTVDBSeries *cTVDBManager::ScrapSeries(int seriesID) { + cTVDBSeries *series = tvdbScraper->GetSeries(seriesID); + if (!series->ReadSeries()) { + delete series; + return NULL; + } + series->ReadMedia(); + series->ReadActors(); + return series; +} + +void cTVDBManager::SaveSeries(cTVDBSeries *series) { + if (!series) + return; + SaveSeriesBasics(series); + SaveSeriesMedia(series); + SaveSeriesEpisodes(series); + SaveSeriesActors(series); +} + +void cTVDBManager::SaveSeriesBasics(cTVDBSeries *series) { + tSeries->clear(); + tSeries->setValue("SeriesId", series->seriesID); + tSeries->setValue("SeriesName", series->name.c_str()); + tSeries->setValue("SeriesLastScraped", serverTime); + tSeries->setValue("SeriesLastUpdated", series->lastUpdated); + tSeries->setValue("SeriesOverview", series->overview.c_str()); + tSeries->setValue("SeriesFirstAired", series->firstAired.c_str()); + tSeries->setValue("SeriesIMDBId", series->imbdid.c_str()); + tSeries->setValue("SeriesGenre", series->genre.c_str()); + tSeries->setValue("SeriesRating", series->rating); + tSeries->setValue("SeriesStatus", series->status.c_str()); + tSeries->setValue("SeriesNetwork", series->network.c_str()); + tSeries->store(); +} + +void cTVDBManager::SaveSeriesMedia(cTVDBSeries *series) { + cTVDBFanart *fanart = NULL; + int num = 0; + while((fanart = series->GetFanart())) { + int mediaType = (num==0)?mtFanart1:((num==1)?mtFanart2:mtFanart3); + bool mediaExists = LoadMedia(series->seriesID, 0, 0, 0, mediaType); + bool reloadImage = mediaExists ? ReloadImage(fanart->url) : true; + if (!reloadImage) { + num++; + if (num>2) break; + continue; + } + bool ok = SavePosterBannerFanart(mediaType, fanart, series->seriesID); + if (ok) + num++; + if (num>2) break; + } + + cTVDBPoster *poster = NULL; + num = 0; + while((poster = series->GetPoster())) { + int mediaType = (num==0)?mtPoster1:((num==1)?mtPoster2:mtPoster3); + bool mediaExists = LoadMedia(series->seriesID, 0, 0, 0, mediaType); + bool reloadImage = mediaExists ? ReloadImage(poster->url) : true; + if (!reloadImage) { + num++; + if (num>2) break; + continue; + } + bool ok = SavePosterBannerFanart(mediaType, poster, series->seriesID); + if (ok) + num++; + if (num>2) break; + } + + cTVDBBanner *banner = NULL; + num = 0; + while((banner = series->GetBanner())) { + int mediaType = (num==0)?mtBanner1:((num==1)?mtBanner2:mtBanner3); + bool mediaExists = LoadMedia(series->seriesID, 0, 0, 0, mediaType); + bool reloadImage = mediaExists ? ReloadImage(banner->url) : true; + if (!reloadImage) { + num++; + if (num>2) break; + continue; + } + bool ok = SavePosterBannerFanart(mediaType, banner, series->seriesID); + if (ok) + num++; + if (num>2) break; + } +} + +bool cTVDBManager::SavePosterBannerFanart(int mediaType, cTVDBMedia *media, int seriesID) { + MemoryStruct data; + tSeriesMedia->clear(); + tSeriesMedia->setValue("SeriesId", seriesID); + tSeriesMedia->setValue("SeasonNumber", 0); + tSeriesMedia->setValue("EpisodeId", 0); + tSeriesMedia->setValue("ActorId", 0); + tSeriesMedia->setValue("MediaType", mediaType); + tSeriesMedia->setValue("MediaUrl", media->url.c_str()); + tSeriesMedia->setValue("MediaWidth", media->width); + tSeriesMedia->setValue("MediaHeight", media->height); + tSeriesMedia->setValue("MediaRating", media->rating); + if (GetPicture(media->url.c_str(), &data) == success) { + tSeriesMedia->setValue("MediaContent", data.memory, data.size); + tSeriesMedia->store(); + return true; + } + return false; +} + +void cTVDBManager::SaveSeriesEpisodes(cTVDBSeries *series) { + cTVDBEpisode *episode = NULL; + while((episode = series->GetEpisode())) { + //insert Season Poster + cTVDBSeasonPoster *seasonPoster = series->GetSeasonPoster(episode->season); + if (seasonPoster) { + bool mediaExists = LoadMedia(series->seriesID, episode->season, 0, 0, mtSeasonPoster); + if (!mediaExists) { + tSeriesMedia->clear(); + tSeriesMedia->setValue("SeriesId", series->seriesID); + tSeriesMedia->setValue("SeasonNumber", episode->season); + tSeriesMedia->setValue("EpisodeId", 0); + tSeriesMedia->setValue("ActorId", 0); + tSeriesMedia->setValue("MediaType", mtSeasonPoster); + tSeriesMedia->setValue("MediaUrl", seasonPoster->url.c_str()); + tSeriesMedia->setValue("MediaWidth", seasonPoster->width); + tSeriesMedia->setValue("MediaHeight", seasonPoster->height); + tSeriesMedia->setValue("MediaRating", seasonPoster->rating); + tSeriesMedia->store(); + } + } + //Episode + SaveSeriesEpisode(episode, series->seriesID); + //Episode Image + if (episode->imageUrl.size() > 10) { + bool mediaExists = LoadMedia(series->seriesID, episode->season, episode->id, 0, mtEpisodePic); + if (!mediaExists) { + tSeriesMedia->clear(); + tSeriesMedia->setValue("SeriesId", series->seriesID); + tSeriesMedia->setValue("SeasonNumber", episode->season); + tSeriesMedia->setValue("EpisodeId", episode->id); + tSeriesMedia->setValue("ActorId", 0); + tSeriesMedia->setValue("MediaType", mtEpisodePic); + tSeriesMedia->setValue("MediaUrl", episode->imageUrl.c_str()); + tSeriesMedia->setValue("MediaWidth", episode->width); + tSeriesMedia->setValue("MediaHeight", episode->height); + tSeriesMedia->setValue("MediaRating", 0.0); + tSeriesMedia->store(); + } + } + } +} + +void cTVDBManager::SaveSeriesEpisode(cTVDBEpisode *episode, int seriesID) { + if (!episode) + return; + tSeriesEpsiode->clear(); + tSeriesEpsiode->setValue("EpisodeId", episode->id); + tSeriesEpsiode->setValue("EpisodeNumber", episode->number); + tSeriesEpsiode->setValue("EpisodeName", episode->name.c_str()); + tSeriesEpsiode->setValue("EpisodeOverview", episode->overview.c_str()); + tSeriesEpsiode->setValue("EpisodeFirstAired", episode->firstAired.c_str()); + tSeriesEpsiode->setValue("EpisodeGuestStars", episode->guestStars.c_str()); + tSeriesEpsiode->setValue("EpisodeRating", episode->rating); + tSeriesEpsiode->setValue("EpisodeLastUpdated", episode->lastUpdated); + tSeriesEpsiode->setValue("SeasonNumber", episode->season); + tSeriesEpsiode->setValue("SeriesId", seriesID ? seriesID : episode->seriesID); + tSeriesEpsiode->store(); +} + +void cTVDBManager::SaveSeriesActors(cTVDBSeries *series) { + MemoryStruct data; + cTVDBActor *actor = NULL; + while((actor = series->GetActor())) { + tSeriesActor->clear(); + tSeriesActor->setValue("ActorId", actor->id); + tSeriesActor->setValue("ActorName", actor->name.c_str()); + tSeriesActor->setValue("ActorRole", actor->role.c_str()); + tSeriesActor->setValue("SortOrder", actor->sortOrder); + tSeriesActor->store(); + bool mediaExists = LoadMedia(series->seriesID, 0, 0, actor->id, mtActorThumb); + bool reloadImage = mediaExists ? ReloadImage(actor->thumbUrl) : true; + if (reloadImage && actor->thumbUrl.size() > 10) { + tSeriesMedia->clear(); + tSeriesMedia->setValue("SeriesId", series->seriesID); + tSeriesMedia->setValue("SeasonNumber", 0); + tSeriesMedia->setValue("EpisodeId", 0); + tSeriesMedia->setValue("ActorId", actor->id); + tSeriesMedia->setValue("MediaType", mtActorThumb); + tSeriesMedia->setValue("MediaUrl", actor->thumbUrl.c_str()); + tSeriesMedia->setValue("MediaWidth", actor->thumbUrlWidth); + tSeriesMedia->setValue("MediaHeight", actor->thumbUrlHeight); + tSeriesMedia->setValue("MediaRating", 0.0); + if (GetPicture(actor->thumbUrl.c_str(), &data) == success) { + tSeriesMedia->setValue("MediaContent", data.memory, data.size); + tSeriesMedia->store(); + } + } + } +} + +bool cTVDBManager::LoadMedia(int seriesId, int seasonNumber, int episodeId, int actorId, int mediaType) { + tSeriesMedia->clear(); + tSeriesMedia->setValue("SeriesId", seriesId); + tSeriesMedia->setValue("SeasonNumber", seasonNumber); + tSeriesMedia->setValue("EpisodeId", episodeId); + tSeriesMedia->setValue("ActorId", actorId); + tSeriesMedia->setValue("MediaType", mediaType); + return tSeriesMedia->find(); +} + +bool cTVDBManager::GetSeriesWithEpisodesFromEPG(vector<sSeriesResult> *result) { + int status = success; + cDbValue season; + cDbValue part; + cDbValue number; + + season.setField(tEpisodes->getField("Season")); + part.setField(tEpisodes->getField("Part")); + number.setField(tEpisodes->getField("Number")); + + cDbStatement *selectSeries = new cDbStatement(tEvents); + + selectSeries->build("select "); + selectSeries->bind("EventId", cDBS::bndOut); + selectSeries->bind("Title", cDBS::bndOut, ", "); + selectSeries->bind("ScrSp", cDBS::bndOut, ", "); + selectSeries->bind(&season, cDBS::bndOut, ", "); + selectSeries->bind(&part, cDBS::bndOut, ", "); + selectSeries->bind(&number, cDBS::bndOut, ", "); + selectSeries->bind("ShortText", cDBS::bndOut, ", "); + selectSeries->build(" from thetvdbview"); + + status += selectSeries->prepare(); + + if (status != success) { + delete selectSeries; + return false; + } + + for (int found = selectSeries->find(); found; found = selectSeries->fetch()) { + sSeriesResult res; + res.eventId = tEvents->getBigintValue("EventId"); + res.title = tEvents->getStrValue("Title"); + res.lastScraped = tEvents->getIntValue("ScrSp"); + res.season = season.getIntValue(); + res.part = part.getIntValue(); + res.number = number.getIntValue(); + res.episodeName = tEvents->getStrValue("ShortText"); + result->push_back(res); + } + + selectSeries->freeResult(); + delete selectSeries; + return true; +} + +int cTVDBManager::GetPicture(const char* url, MemoryStruct* data) { + //tell(0,"Download image %s", url); + int maxSize = tSeriesMedia->getField("MediaContent")->getSize(); + data->clear(); + int fileSize = 0; + if (curl.downloadFile(url, fileSize, data) == success) { + bytesDownloaded += fileSize; + if (fileSize < maxSize) + return success; + } + return fail; +} + +bool cTVDBManager::ReloadImage(string url) { + bool reloadImage = false; + if (url.compare(tSeriesMedia->getStrValue("MediaUrl"))) { + reloadImage = true; + } + return reloadImage; +} + +void cTVDBManager::ProcessSeries(sSeriesResult ser) { + //tell(0, "Checking eventID: %d, Title: %s, S%dE%dN%d", ser.eventId, ser.title.c_str(), ser.season, ser.part, ser.number); + map<string, int>::iterator hit = alreadyScraped.find(ser.title); + int seriesID = 0; + int episodeID = 0; + if (hit != alreadyScraped.end()) { + seriesID = (int)hit->second; + if (seriesID == 0) { + //tell(0, "series %s already scraped and nothing found", ser.title.c_str()); + UpdateEvent(ser.eventId, seriesID, episodeID); + return; + } else { + //tell(0, "found series %s in cache, id %d", ser.title.c_str(), seriesID); + } + } + if (seriesID == 0) { + //check if series in database + seriesID = LoadSeriesFromDB(ser.title); + if (seriesID != 0) { + //tell(0, "series %s already in db, id %d", ser.title.c_str(), seriesID); + } else { + //scrap series + cTVDBSeries *series = ScrapSeries(ser.title); + if (series) { + SaveSeries(series); + seriesID = series->seriesID; + //tell(0, "series %s successfully scraped, id %d", ser.title.c_str(), seriesID); + delete series; + series = NULL; + } else { + //tell(0, "series %s not found at tvdb.com", ser.title.c_str()); + } + } + } + alreadyScraped.insert(pair<string, int>(ser.title, seriesID)); + if (seriesID != 0) { + if ((ser.season == 0) && (ser.part == 0) && (ser.episodeName.size() > 0)) { + //try to get part and season from episode name + GetSeasonEpisodeFromEpisodename(seriesID, ser.season, ser.part, ser.episodeName); + } + //tell(0, "downloading episode info"); + //loading season poster and episode picture + if (ser.season > 0) + LoadSeasonPoster(seriesID, ser.season); + if ((ser.season > 0) && (ser.part > 0)) + episodeID = LoadEpisodePicture(seriesID, ser.season, ser.part); + } + //updating event with series data + UpdateEvent(ser.eventId, seriesID, episodeID); +} + +int cTVDBManager::LoadSeriesFromDB(string name) { + int status = success; + int seriesID = 0; + tSeries->clear(); + tSeries->setValue("SeriesName", name.c_str()); + cDbStatement *select = new cDbStatement(tSeries); + select->build("select "); + select->bind("SeriesId", cDBS::bndOut); + select->build(" from %s where ", tSeries->TableName()); + select->bind("SeriesName", cDBS::bndIn | cDBS::bndSet); + status += select->prepare(); + if (status != success) { + delete select; + return seriesID; + } + int res = select->find(); + if (res) { + seriesID = tSeries->getIntValue("SeriesId"); + } + select->freeResult(); + delete select; + return seriesID; +} + +void cTVDBManager::GetSeasonEpisodeFromEpisodename(int seriesID, int &season, int &part, string episodeName) { + int status = success; + tSeriesEpsiode->clear(); + tSeriesEpsiode->setValue("SeriesId", seriesID); + tSeriesEpsiode->setValue("EpisodeName", episodeName.c_str()); + cDbStatement *select = new cDbStatement(tSeriesEpsiode); + select->build("select "); + select->bind("EpisodeNumber", cDBS::bndOut); + select->bind("SeasonNumber", cDBS::bndOut, ", "); + select->build(" from %s where ", tSeriesEpsiode->TableName()); + select->bind("SeriesId", cDBS::bndIn | cDBS::bndSet); + select->bind("EpisodeName", cDBS::bndIn | cDBS::bndSet, " and "); + status += select->prepare(); + if (status != success) { + delete select; + return; + } + int res = select->find(); + if (res) { + season = tSeriesEpsiode->getIntValue("SeasonNumber"); + part = tSeriesEpsiode->getIntValue("EpisodeNumber"); + } + select->freeResult(); + delete select; +} + + +void cTVDBManager::LoadSeasonPoster(int seriesID, int season) { + tSeriesMedia->clear(); + tSeriesMedia->setValue("SeriesId", seriesID); + tSeriesMedia->setValue("SeasonNumber", season); + tSeriesMedia->setValue("EpisodeId", 0); + tSeriesMedia->setValue("ActorId", 0); + tSeriesMedia->setValue("MediaType", mtSeasonPoster); + int found = tSeriesMedia->find(); + if (!found) + return; + string url = tSeriesMedia->getStrValue("MediaUrl"); + if (url.size() < 10) + return; + if (tSeriesMedia->isNull("MediaContent")) { + MemoryStruct data; + if (GetPicture(url.c_str(), &data) == success) { + tSeriesMedia->setValue("MediaContent", data.memory, data.size); + tSeriesMedia->store(); + } + } +} + +int cTVDBManager::LoadEpisodePicture(int seriesID, int season, int part) { + int status = success; + int episodeID = 0; + tSeriesEpsiode->clear(); + tSeriesEpsiode->setValue("EpisodeNumber", part); + tSeriesEpsiode->setValue("SeasonNumber", season); + tSeriesEpsiode->setValue("SeriesId", seriesID); + cDbStatement *select = new cDbStatement(tSeriesEpsiode); + select->build("select "); + select->bind("EpisodeId", cDBS::bndOut); + select->build(" from %s where ", tSeriesEpsiode->TableName()); + select->bind("EpisodeNumber", cDBS::bndIn | cDBS::bndSet); + select->bind("SeasonNumber", cDBS::bndIn | cDBS::bndSet, " and "); + select->bind("SeriesId", cDBS::bndIn | cDBS::bndSet, " and "); + status += select->prepare(); + if (status != success) { + delete select; + return episodeID; + } + int res = select->find(); + if (res) { + episodeID = tSeriesEpsiode->getIntValue("EpisodeId"); + } + select->freeResult(); + delete select; + if (!episodeID) + return episodeID; + //downloading episode picture + tSeriesMedia->clear(); + tSeriesMedia->setValue("SeriesId", seriesID); + tSeriesMedia->setValue("SeasonNumber", season); + tSeriesMedia->setValue("EpisodeId", episodeID); + tSeriesMedia->setValue("ActorId", 0); + tSeriesMedia->setValue("MediaType", mtEpisodePic); + int found = tSeriesMedia->find(); + if (!found) + return episodeID; + string url = tSeriesMedia->getStrValue("MediaUrl"); + if (url.size() < 10) + return episodeID; + if (tSeriesMedia->isNull("MediaContent")) { + MemoryStruct data; + if (GetPicture(url.c_str(), &data) == success) { + tSeriesMedia->setValue("MediaContent", data.memory, data.size); + tSeriesMedia->store(); + } + } + return episodeID; +} + +void cTVDBManager::UpdateEvent(tEventId eventID, int seriesID, int episodeID) { + stringstream upd; + upd << "update " << tEvents->TableName(); + upd << " set scrsp = " << time(0); + upd << ", scrseriesid = " << seriesID; + upd << ", scrseriesepisode = " << episodeID; + upd << " where eventid = " << eventID; + cDbStatement updStmt(connection, upd.str().c_str()); + updStmt.prepare(); + updStmt.execute(); +} + +int cTVDBManager::CleanupSeries(void) { + int numDelete = 0; + set<int> activeSeriesIds; + int status = success; + //fetching seriesIds from current events + cDbStatement *selectSeriesIds = new cDbStatement(tEvents); + selectSeriesIds->build("select distinct "); + selectSeriesIds->bind("ScrSeriesId", cDBS::bndOut); + selectSeriesIds->build(" from %s where ", tEvents->TableName()); + selectSeriesIds->build(" %s is not null ", tEvents->getField("ScrSeriesId")->getDbName()); + selectSeriesIds->build(" and %s > 0 ", tEvents->getField("ScrSeriesId")->getDbName()); + status += selectSeriesIds->prepare(); + if (status != success) { + delete selectSeriesIds; + return numDelete; + } + tEvents->clear(); + + for (int res = selectSeriesIds->find(); res; res = selectSeriesIds->fetch()) { + activeSeriesIds.insert(tEvents->getIntValue("ScrSeriesId")); + } + + selectSeriesIds->freeResult(); + delete selectSeriesIds; + + // fetching seriesIds from recordings + + cDbStatement *selectSeriesIdsRec = new cDbStatement(tRecordingList); + selectSeriesIdsRec->build("select distinct "); + selectSeriesIdsRec->bind("SCRSERIESID", cDBS::bndOut); + selectSeriesIdsRec->build(" from %s where ", tRecordingList->TableName()); + selectSeriesIdsRec->build(" %s is not null ", tRecordingList->getField("SCRSERIESID")->getDbName()); + selectSeriesIdsRec->build(" and %s > 0 ", tRecordingList->getField("SCRSERIESID")->getDbName()); + status += selectSeriesIdsRec->prepare(); + if (status != success) { + delete selectSeriesIdsRec; + return numDelete; + } + tRecordingList->clear(); + for (int res = selectSeriesIdsRec->find(); res; res = selectSeriesIdsRec->fetch()) { + activeSeriesIds.insert(tRecordingList->getIntValue("SCRSERIESID")); + } + selectSeriesIdsRec->freeResult(); + delete selectSeriesIdsRec; + + //fetching all seriesIds from series table + vector<int> storedSeriesIds; + cDbStatement *selectStoredSeriesIds = new cDbStatement(tSeries); + selectStoredSeriesIds->build("select "); + selectStoredSeriesIds->bind("SeriesId", cDBS::bndOut); + selectStoredSeriesIds->build(" from %s where ", tSeries->TableName()); + selectStoredSeriesIds->build(" %s is not null ", tSeries->getField("SeriesId")->getDbName()); + selectStoredSeriesIds->build(" and %s > 0 ", tSeries->getField("SeriesId")->getDbName()); + status += selectStoredSeriesIds->prepare(); + if (status != success) { + delete selectStoredSeriesIds; + return numDelete; + } + tSeries->clear(); + + for (int res = selectStoredSeriesIds->find(); res; res = selectStoredSeriesIds->fetch()) { + storedSeriesIds.push_back(tSeries->getIntValue("SeriesId")); + } + selectStoredSeriesIds->freeResult(); + delete selectStoredSeriesIds; + + numDelete = storedSeriesIds.size() - activeSeriesIds.size(); + if (numDelete < 1) + return numDelete; + for (vector<int>::iterator sId = storedSeriesIds.begin(); sId != storedSeriesIds.end(); sId++) { + set<int>::iterator hit = activeSeriesIds.find(*sId); + if (hit == activeSeriesIds.end()) { + DeleteSeries(*sId); + } + } + return numDelete; +} + +void cTVDBManager::DeleteSeries(int seriesId) { + if (seriesId < 1) + return; + stringstream delSeriesEpisodes; + delSeriesEpisodes << "delete from " << tSeriesEpsiode->TableName(); + delSeriesEpisodes << " where " << tSeriesEpsiode->getField("SeriesId")->getDbName(); + delSeriesEpisodes << " = " << seriesId; + + cDbStatement delEpisodes(connection, delSeriesEpisodes.str().c_str()); + delEpisodes.prepare(); + delEpisodes.execute(); + + stringstream delSeriesActors; + delSeriesActors << "delete from " << tSeriesActor->TableName(); + delSeriesActors << " where " << tSeriesActor->getField("ActorId")->getDbName(); + delSeriesActors << " in ( "; + delSeriesActors << " select series_media.actor_id "; + delSeriesActors << " from series, series_media "; + delSeriesActors << " where series.series_id = series_media.series_id "; + delSeriesActors << " and series_media.media_type = " << mtActorThumb; + delSeriesActors << " and series.series_id = " << seriesId << ")"; + + cDbStatement delActors(connection, delSeriesActors.str().c_str()); + delActors.prepare(); + delActors.execute(); + + stringstream delSeriesMedia; + delSeriesMedia << "delete from " << tSeriesMedia->TableName(); + delSeriesMedia << " where " << tSeriesMedia->getField("SeriesId")->getDbName(); + delSeriesMedia << " = " << seriesId; + + cDbStatement delMedia(connection, delSeriesMedia.str().c_str()); + delMedia.prepare(); + delMedia.execute(); + + stringstream delSeries; + delSeries << "delete from " << tSeries->TableName(); + delSeries << " where " << tSeries->getField("SeriesId")->getDbName(); + delSeries << " = " << seriesId; + + cDbStatement delSer(connection, delSeries.str().c_str()); + delSer.prepare(); + delSer.execute(); +} + +bool cTVDBManager::SearchRecordingDB(string name, string episode, int &seriesId, int &episodeId) +{ + int status = success; + cDbStatement *select = new cDbStatement(tSeries); + + select->build("select "); + select->bind("SeriesId", cDBS::bndOut); + select->build(" from %s where ", tSeries->TableName()); + select->bind("SeriesName", cDBS::bndIn | cDBS::bndSet); + status += select->prepare(); + + if (status != success) + { + delete select; + return false; + } + + tSeries->clear(); + tSeries->setValue("SeriesName", name.c_str()); + int found = select->find(); + + if (found) + { + seriesId = tSeries->getIntValue("SeriesId"); + episodeId = LoadEpisode(episode, seriesId); + } + + select->freeResult(); + delete select; + + return found; +} + +bool cTVDBManager::SearchRecordingOnline(string name, string episode, int &seriesId, int &episodeId) +{ + cTVDBSeries *recSeries = ScrapSeries(name); + + if (recSeries) + { + SaveSeries(recSeries); + seriesId = recSeries->seriesID; + delete recSeries; + episodeId = LoadEpisode(episode, seriesId); + return true; + } + + return false; +} + +int cTVDBManager::LoadEpisode(string name, int seriesId) { + int status = success; + int episodeId = 0; + cDbStatement *select = new cDbStatement(tSeriesEpsiode); + select->build("select "); + select->bind("EpisodeId", cDBS::bndOut); + select->build(" from %s where ", tSeriesEpsiode->TableName()); + select->bind("EpisodeName", cDBS::bndIn | cDBS::bndSet); + select->bind("SeriesId", cDBS::bndIn | cDBS::bndSet, " and "); + status += select->prepare(); + if (status != success) { + delete select; + return false; + } + tSeriesEpsiode->clear(); + tSeriesEpsiode->setValue("EpisodeName", name.c_str()); + tSeriesEpsiode->setValue("SeriesId", seriesId); + int found = select->find(); + if (found) + episodeId = tSeriesEpsiode->getIntValue("EpisodeId"); + select->freeResult(); + delete select; + return episodeId; +} + + +bool cTVDBManager::CheckScrapInfoDB(int scrapSeriesId, int scrapEpisodeId) { + //check if series is in db + tSeries->clear(); + tSeries->setValue("SeriesId", scrapSeriesId); + int found = tSeries->find(); + if (!found) + return false; + if (scrapEpisodeId > 0) { + tSeriesEpsiode->clear(); + tSeriesEpsiode->setValue("EpisodeId", scrapEpisodeId); + found = tSeriesEpsiode->find(); + if (found) { + int season = tSeriesEpsiode->getIntValue("SeasonNumber"); + int part = tSeriesEpsiode->getIntValue("EpisodeNumber"); + if (season) + LoadSeasonPoster(scrapSeriesId, season); + if (season && part) + LoadEpisodePicture(scrapSeriesId, season, part); + } + } + return true; +} + +bool cTVDBManager::CheckScrapInfoOnline(int scrapSeriesId, int scrapEpisodeId) { + cTVDBSeries *seriesRec = ScrapSeries(scrapSeriesId); + if (!seriesRec) + return false; + SaveSeries(seriesRec); + if (scrapEpisodeId > 0) { + int part = 0; + int season = 0; + if (seriesRec->GetPartAndSeason(scrapEpisodeId, season, part)) { + if (season) + LoadSeasonPoster(scrapSeriesId, season); + if (season && part) + LoadEpisodePicture(scrapSeriesId, season, part); + } + } + delete seriesRec; + return true; +} |