summaryrefslogtreecommitdiff
path: root/scraper/thetvdbscraper
diff options
context:
space:
mode:
authorhorchi <vdr@jwendel.de>2017-03-05 16:39:28 +0100
committerhorchi <vdr@jwendel.de>2017-03-05 16:39:28 +0100
commite2a48d8701f91b8e24fbe9e99e91eb72a87bb749 (patch)
tree726f70554b4ca985a09ef6e30a7fdc8df089993c /scraper/thetvdbscraper
downloadvdr-epg-daemon-e2a48d8701f91b8e24fbe9e99e91eb72a87bb749.tar.gz
vdr-epg-daemon-e2a48d8701f91b8e24fbe9e99e91eb72a87bb749.tar.bz2
git init1.1.103
Diffstat (limited to 'scraper/thetvdbscraper')
-rw-r--r--scraper/thetvdbscraper/thetvdbscraper.c188
-rw-r--r--scraper/thetvdbscraper/thetvdbscraper.h39
-rw-r--r--scraper/thetvdbscraper/tvdbactor.c66
-rw-r--r--scraper/thetvdbscraper/tvdbactor.h54
-rw-r--r--scraper/thetvdbscraper/tvdbepisode.c147
-rw-r--r--scraper/thetvdbscraper/tvdbepisode.h45
-rw-r--r--scraper/thetvdbscraper/tvdbmedia.c202
-rw-r--r--scraper/thetvdbscraper/tvdbmedia.h111
-rw-r--r--scraper/thetvdbscraper/tvdbmirrors.c88
-rw-r--r--scraper/thetvdbscraper/tvdbmirrors.h32
-rw-r--r--scraper/thetvdbscraper/tvdbseries.c281
-rw-r--r--scraper/thetvdbscraper/tvdbseries.h69
12 files changed, 1322 insertions, 0 deletions
diff --git a/scraper/thetvdbscraper/thetvdbscraper.c b/scraper/thetvdbscraper/thetvdbscraper.c
new file mode 100644
index 0000000..e83690c
--- /dev/null
+++ b/scraper/thetvdbscraper/thetvdbscraper.c
@@ -0,0 +1,188 @@
+
+#include "../../lib/curl.h"
+#include "thetvdbscraper.h"
+
+using namespace std;
+
+cTVDBScraper::cTVDBScraper(string language) {
+ apiKey = "E9DBB94CA50832ED";
+ baseURL = "thetvdb.com";
+ this->language = language;
+ mirrors = NULL;
+ xmlInitParser();
+}
+
+cTVDBScraper::~cTVDBScraper() {
+ if (mirrors)
+ delete mirrors;
+}
+
+cTVDBSeries *cTVDBScraper::ScrapInitial(string seriesName) {
+ cTVDBSeries *series = NULL;
+ int seriesID = ReadSeries(seriesName);
+ if (seriesID) {
+ series = new cTVDBSeries(seriesID, language, apiKey, mirrors);
+ }
+ return series;
+}
+
+cTVDBSeries *cTVDBScraper::GetSeries(int seriesID) {
+ return new cTVDBSeries(seriesID, language, apiKey, mirrors);
+}
+
+cTVDBEpisode *cTVDBScraper::GetEpisode(int episodeID) {
+ return new cTVDBEpisode(episodeID, language, apiKey, mirrors);
+}
+
+bool cTVDBScraper::Connect(void) {
+ stringstream url;
+ url << baseURL << "/api/" << apiKey << "/mirrors.xml";
+ string mirrorsXML;
+ bool ok = false;
+ if (curl.GetUrl(url.str().c_str(), &mirrorsXML)) {
+ mirrors = new cTVDBMirrors();
+ ok = mirrors->ParseXML(mirrorsXML);
+ }
+ return ok;
+}
+
+int cTVDBScraper::GetServerTime(void) {
+ string url = "http://thetvdb.com/api/Updates.php?type=none";
+ string serverTimeXML;
+ if (!curl.GetUrl(url.c_str(), &serverTimeXML)) {
+ return 0;
+ }
+ xmlDoc *doc = SetXMLDoc(serverTimeXML);
+ if (doc == NULL)
+ return 0;
+ //Root Element has to be <Items>
+ xmlNode *node = NULL;
+ node = xmlDocGetRootElement(doc);
+ if (!(node && !xmlStrcmp(node->name, (const xmlChar *)"Items"))) {
+ xmlFreeDoc(doc);
+ return 0;
+ }
+ node = node->children;
+ xmlNode *cur_node = NULL;
+ for (cur_node = node; cur_node; cur_node = cur_node->next) {
+ if ((cur_node->type == XML_ELEMENT_NODE) && !xmlStrcmp(cur_node->name, (const xmlChar *)"Time")) {
+ node = cur_node;
+ break;
+ } else {
+ node = NULL;
+ }
+ }
+ if (!node) {
+ xmlFreeDoc(doc);
+ return 0;
+ }
+ xmlChar *node_content = xmlNodeListGetString(doc, cur_node->xmlChildrenNode, 1);
+ int serverTime = atoi((const char *)node_content);
+ xmlFree(node_content);
+ xmlFreeDoc(doc);
+ return serverTime;
+}
+
+bool cTVDBScraper::GetUpdatedSeriesandEpisodes(set<int> *updatedSeries, set<int> *updatedEpisodes, int lastScrap) {
+ stringstream url;
+ url << "http://thetvdb.com/api/Updates.php?type=all&time=" << lastScrap;
+ string updatedXML;
+ if (!curl.GetUrl(url.str().c_str(), &updatedXML)) {
+ return false;
+ }
+ xmlDoc *doc = SetXMLDoc(updatedXML);
+ if (doc == NULL)
+ return false;
+ //Root Element has to be <Items>
+ xmlNode *node = NULL;
+ node = xmlDocGetRootElement(doc);
+ if (!(node && !xmlStrcmp(node->name, (const xmlChar *)"Items"))) {
+ xmlFreeDoc(doc);
+ return false;
+ }
+
+ xmlNode *cur_node = node->children;
+ for (; cur_node; cur_node = cur_node->next) {
+ if ((cur_node->type == XML_ELEMENT_NODE) && !xmlStrcmp(cur_node->name, (const xmlChar *)"Series")) {
+ xmlChar *node_content = xmlNodeListGetString(doc, cur_node->xmlChildrenNode, 1);
+ int seriesId = atoi((const char *)node_content);
+ xmlFree(node_content);
+ updatedSeries->insert(seriesId);
+ } else if ((cur_node->type == XML_ELEMENT_NODE) && !xmlStrcmp(cur_node->name, (const xmlChar *)"Episode")) {
+ xmlChar *node_content = xmlNodeListGetString(doc, cur_node->xmlChildrenNode, 1);
+ int episodeId = atoi((const char *)node_content);
+ xmlFree(node_content);
+ updatedEpisodes->insert(episodeId);
+ }
+ }
+ xmlFreeDoc(doc);
+ return true;
+}
+
+
+int cTVDBScraper::ReadSeries(string seriesName) {
+ int seriesID = 0;
+ stringstream url;
+ string seriesXML;
+ char* escUrl = curl.EscapeUrl(seriesName.c_str());
+
+ url << mirrors->GetMirrorXML() << "/api/GetSeries.php?seriesname=" << escUrl << "&language=" << language.c_str();
+ curl.Free(escUrl);
+
+ if (curl.GetUrl(url.str().c_str(), &seriesXML))
+ seriesID = ParseXML(seriesXML);
+
+ return seriesID;
+}
+
+int cTVDBScraper::ParseXML(string xml) {
+ int seriesID = 0;
+ xmlDoc *doc = SetXMLDoc(xml);
+ if (doc == NULL)
+ return seriesID;
+ //Root Element has to be <Data>
+ xmlNode *node = NULL;
+ node = xmlDocGetRootElement(doc);
+ if (!(node && !xmlStrcmp(node->name, (const xmlChar *)"Data"))) {
+ xmlFreeDoc(doc);
+ return seriesID;
+ }
+ //Searching for <Series>
+ node = node->children;
+ xmlNode *cur_node = NULL;
+ for (cur_node = node; cur_node; cur_node = cur_node->next) {
+ if ((cur_node->type == XML_ELEMENT_NODE) && !xmlStrcmp(cur_node->name, (const xmlChar *)"Series")) {
+ node = cur_node;
+ break;
+ } else {
+ node = NULL;
+ }
+ }
+ if (!node) {
+ xmlFreeDoc(doc);
+ return seriesID;
+ }
+ //now read the first series
+ node = node->children;
+ xmlChar *node_content;
+ for (cur_node = node; cur_node; cur_node = cur_node->next) {
+ if (cur_node->type == XML_ELEMENT_NODE) {
+ node_content = xmlNodeListGetString(doc, cur_node->xmlChildrenNode, 1);
+ if (!node_content)
+ continue;
+ if (!xmlStrcmp(cur_node->name, (const xmlChar *)"seriesid")) {
+ seriesID = atoi((const char *)node_content);
+ xmlFree(node_content);
+ break;
+ }
+ xmlFree(node_content);
+ }
+ }
+ xmlFreeDoc(doc);
+ return seriesID;
+}
+
+xmlDoc *cTVDBScraper::SetXMLDoc(string xml) {
+ xmlDoc *doc = xmlReadMemory(xml.c_str(), xml.size(), "noname.xml", NULL, 0);
+ return doc;
+}
diff --git a/scraper/thetvdbscraper/thetvdbscraper.h b/scraper/thetvdbscraper/thetvdbscraper.h
new file mode 100644
index 0000000..051842c
--- /dev/null
+++ b/scraper/thetvdbscraper/thetvdbscraper.h
@@ -0,0 +1,39 @@
+#ifndef __TVSCRAPER_TVDBSCRAPER_H
+#define __TVSCRAPER_TVDBSCRAPER_H
+#include <iostream>
+#include <string>
+#include <sstream>
+#include <vector>
+#include <map>
+#include <set>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include "tvdbseries.h"
+#include "tvdbmirrors.h"
+
+using namespace std;
+
+// --- cTVDBScraper -------------------------------------------------------------
+
+class cTVDBScraper {
+private:
+ string apiKey;
+ string baseURL;
+ string language;
+ cTVDBMirrors *mirrors;
+ xmlDoc *SetXMLDoc(string xml);
+ int ParseXML(string xml);
+ int ReadSeries(string seriesName);
+public:
+ cTVDBScraper(string language);
+ virtual ~cTVDBScraper(void);
+ bool Connect(void);
+ int GetServerTime(void);
+ cTVDBSeries *ScrapInitial(string seriesName);
+ bool GetUpdatedSeriesandEpisodes(set<int> *updatedSeries, set<int> *updatedEpisodes, int lastScrap);
+ cTVDBSeries *GetSeries(int seriesID);
+ cTVDBEpisode *GetEpisode(int episodeID);
+};
+
+
+#endif //__TVSCRAPER_TVDBSCRAPER_H
diff --git a/scraper/thetvdbscraper/tvdbactor.c b/scraper/thetvdbscraper/tvdbactor.c
new file mode 100644
index 0000000..f64846a
--- /dev/null
+++ b/scraper/thetvdbscraper/tvdbactor.c
@@ -0,0 +1,66 @@
+#include <iostream>
+#include <string>
+#include <sstream>
+#include <vector>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include "tvdbactor.h"
+
+using namespace std;
+
+cTVDBActors::cTVDBActors(string language, cTVDBMirrors *mirrors) {
+ this->language = language;
+ this->mirrors = mirrors;
+}
+
+cTVDBActors::~cTVDBActors() {
+}
+
+void cTVDBActors::ParseXML(string xml, vector<cTVDBActor*> *actors) {
+ xmlDoc *doc = xmlReadMemory(xml.c_str(), xml.size(), "noname.xml", NULL, 0);
+ if (doc == NULL)
+ return;
+ //Root Element has to be <Actors>
+ xmlNode *node = NULL;
+ node = xmlDocGetRootElement(doc);
+ if (!(node && !xmlStrcmp(node->name, (const xmlChar *)"Actors"))) {
+ xmlFreeDoc(doc);
+ return;
+ }
+ //Looping through actors
+ node = node->children;
+ xmlNode *cur_node = NULL;
+ for (cur_node = node; cur_node; cur_node = cur_node->next) {
+ if ((cur_node->type == XML_ELEMENT_NODE) && !xmlStrcmp(cur_node->name, (const xmlChar *)"Actor")) {
+ cTVDBActor *actor = ReadEntry(doc, cur_node->children);
+ actors->push_back(actor);
+ }
+ }
+ xmlFreeDoc(doc);
+}
+
+cTVDBActor *cTVDBActors::ReadEntry(xmlDoc *doc, xmlNode *node) {
+ xmlNode *cur_node = NULL;
+ xmlChar *node_content;
+ cTVDBActor *actor = new cTVDBActor();
+ for (cur_node = node; cur_node; cur_node = cur_node->next) {
+ if (cur_node->type == XML_ELEMENT_NODE) {
+ node_content = xmlNodeListGetString(doc, cur_node->xmlChildrenNode, 1);
+ if (!node_content)
+ continue;
+ if (!xmlStrcmp(cur_node->name, (const xmlChar *)"Image")) {
+ actor->thumbUrl = mirrors->GetMirrorBanner() + (const char *)node_content;
+ } else if (!xmlStrcmp(cur_node->name, (const xmlChar *)"Name")) {
+ actor->name = (const char *)node_content;
+ } else if (!xmlStrcmp(cur_node->name, (const xmlChar *)"Role")) {
+ actor->role = (const char *)node_content;
+ } else if (!xmlStrcmp(cur_node->name, (const xmlChar *)"id")) {
+ actor->id = atoi((const char *)node_content);
+ } else if (!xmlStrcmp(cur_node->name, (const xmlChar *)"SortOrder")) {
+ actor->sortOrder = atoi((const char *)node_content);
+ }
+ xmlFree(node_content);
+ }
+ }
+ return actor;
+} \ No newline at end of file
diff --git a/scraper/thetvdbscraper/tvdbactor.h b/scraper/thetvdbscraper/tvdbactor.h
new file mode 100644
index 0000000..ed77199
--- /dev/null
+++ b/scraper/thetvdbscraper/tvdbactor.h
@@ -0,0 +1,54 @@
+#ifndef __TVSCRAPER_TVDBACTORS_H
+#define __TVSCRAPER_TVDBACTORS_H
+
+#include <iostream>
+#include <string>
+#include <sstream>
+#include <vector>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include "tvdbmirrors.h"
+
+using namespace std;
+
+// --- cTVDBActor -------------------------------------------------------------
+class cTVDBActor {
+public:
+ cTVDBActor(void) {
+ thumbUrl = "";
+ name = "";
+ role = "";
+ id = 0;
+ sortOrder = 0;
+ thumbUrlWidth = 300;
+ thumbUrlHeight = 450;
+ };
+ string thumbUrl;
+ int thumbUrlWidth;
+ int thumbUrlHeight;
+ string name;
+ string role;
+ int id;
+ int sortOrder;
+ void Dump() {
+ cout << "Actor name: " << name << ", ID: " << id << endl;
+ cout << "Actor role: " << role << endl;
+ cout << "Actor thumb: " << thumbUrl << endl;
+ cout << "Actor SortOrder: " << sortOrder << endl;
+ }
+};
+
+// --- cTVDBActors --------------------------------------------------------
+
+class cTVDBActors {
+private:
+ cTVDBMirrors *mirrors;
+ string language;
+ cTVDBActor *ReadEntry(xmlDoc *doc, xmlNode *node);
+public:
+ cTVDBActors(string language, cTVDBMirrors *mirrors);
+ virtual ~cTVDBActors(void);
+ void ParseXML(string xml, vector<cTVDBActor*> *actors);
+};
+
+#endif //__TVSCRAPER_TVDBACTORS_H
diff --git a/scraper/thetvdbscraper/tvdbepisode.c b/scraper/thetvdbscraper/tvdbepisode.c
new file mode 100644
index 0000000..b9ac510
--- /dev/null
+++ b/scraper/thetvdbscraper/tvdbepisode.c
@@ -0,0 +1,147 @@
+
+#include <iostream>
+#include <string>
+#include <sstream>
+#include <vector>
+
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+
+#include "../../lib/curl.h"
+#include "tvdbepisode.h"
+
+using namespace std;
+
+cTVDBEpisode::cTVDBEpisode(void) {
+ id = 0;
+ seriesID = 0;
+ number = 0;
+ season = 0;
+ combinedEpisode = 0;
+ combinedSeason = 0;
+ name = "";
+ firstAired = "";
+ guestStars = "";
+ overview = "";
+ rating = 0.0;
+ imageUrl = "";
+ width = 400;
+ height = 225;
+ imgFlag = 0;
+ seasonId = 0;
+ lastUpdated = 0;
+}
+
+cTVDBEpisode::cTVDBEpisode(int ID, string language, string apiKey, cTVDBMirrors *mirrors) {
+ this->language = language;
+ this->apiKey = apiKey;
+ this->mirrors = mirrors;
+ id = ID;
+ seriesID = 0;
+ number = 0;
+ season = 0;
+ combinedEpisode = 0;
+ combinedSeason = 0;
+ name = "";
+ firstAired = "";
+ guestStars = "";
+ overview = "";
+ rating = 0.0;
+ imageUrl = "";
+ width = 400;
+ height = 225;
+ imgFlag = 0;
+ seasonId = 0;
+ lastUpdated = 0;
+}
+
+void cTVDBEpisode::ReadEpisode(void) {
+ stringstream url;
+ url << mirrors->GetMirrorXML() << "/api/" << apiKey << "/episodes/" << id << "/" << language << ".xml";
+ string episodeXML;
+ if (curl.GetUrl(url.str().c_str(), &episodeXML)) {
+ ParseXML(episodeXML);
+ }
+}
+
+void cTVDBEpisode::ParseXML(string xml) {
+ xmlDoc *doc = xmlReadMemory(xml.c_str(), xml.size(), "noname.xml", NULL, 0);
+ if (doc == NULL)
+ return;
+ //Root Element has to be <Data>
+ xmlNode *node = NULL;
+ node = xmlDocGetRootElement(doc);
+ if (!(node && !xmlStrcmp(node->name, (const xmlChar *)"Data"))) {
+ xmlFreeDoc(doc);
+ return;
+ }
+ //Looping through episodes
+ node = node->children;
+ xmlNode *cur_node = NULL;
+ for (cur_node = node; cur_node; cur_node = cur_node->next) {
+ if ((cur_node->type == XML_ELEMENT_NODE) && !xmlStrcmp(cur_node->name, (const xmlChar *)"Episode")) {
+ ReadEpisodeFromXML(doc, cur_node->children, mirrors);
+ }
+ }
+ xmlFreeDoc(doc);
+}
+
+void cTVDBEpisode::ReadEpisodeFromXML(xmlDoc *myDoc, xmlNode *node, cTVDBMirrors *mirrors) {
+ xmlNode *cur_node = NULL;
+ xmlChar *node_content;
+ for (cur_node = node; cur_node; cur_node = cur_node->next) {
+ if (cur_node->type == XML_ELEMENT_NODE) {
+ node_content = xmlNodeListGetString(myDoc, cur_node->xmlChildrenNode, 1);
+ if (!node_content)
+ continue;
+ if (!xmlStrcmp(cur_node->name, (const xmlChar *)"id")) {
+ id = atoi((const char *)node_content);
+ } else if (!xmlStrcmp(cur_node->name, (const xmlChar *)"EpisodeNumber")) {
+ number = atoi((const char *)node_content);
+ } else if (!xmlStrcmp(cur_node->name, (const xmlChar *)"seriesid")) {
+ seriesID = atoi((const char *)node_content);
+ } else if (!xmlStrcmp(cur_node->name, (const xmlChar *)"SeasonNumber")) {
+ season = atoi((const char *)node_content);
+ } else if (!xmlStrcmp(cur_node->name, (const xmlChar *)"Combined_episodenumber")) {
+ combinedEpisode = atoi((const char *)node_content);
+ } else if (!xmlStrcmp(cur_node->name, (const xmlChar *)"Combined_season")) {
+ combinedSeason = atoi((const char *)node_content);
+ } else if (!xmlStrcmp(cur_node->name, (const xmlChar *)"EpisodeName")) {
+ name = (const char *)node_content;
+ } else if (!xmlStrcmp(cur_node->name, (const xmlChar *)"FirstAired")) {
+ firstAired = (const char *)node_content;
+ } else if (!xmlStrcmp(cur_node->name, (const xmlChar *)"GuestStars")) {
+ guestStars = (const char *)node_content;
+ } else if (!xmlStrcmp(cur_node->name, (const xmlChar *)"Overview")) {
+ overview = (const char *)node_content;
+ } else if (!xmlStrcmp(cur_node->name, (const xmlChar *)"Rating")) {
+ rating = atof((const char *)node_content);
+ } else if (!xmlStrcmp(cur_node->name, (const xmlChar *)"filename")) {
+ imageUrl = mirrors->GetMirrorBanner() + (const char *)node_content;
+ } else if (!xmlStrcmp(cur_node->name, (const xmlChar *)"thumb_width")) {
+ width = atoi((const char *)node_content);
+ } else if (!xmlStrcmp(cur_node->name, (const xmlChar *)"thumb_height")) {
+ height = atoi((const char *)node_content);
+ } else if (!xmlStrcmp(cur_node->name, (const xmlChar *)"EpImgFlag")) {
+ imgFlag = atoi((const char *)node_content);
+ } else if (!xmlStrcmp(cur_node->name, (const xmlChar *)"seasonid")) {
+ seasonId = atoi((const char *)node_content);
+ } else if (!xmlStrcmp(cur_node->name, (const xmlChar *)"lastupdated")) {
+ lastUpdated = atoi((const char *)node_content);
+ }
+ xmlFree(node_content);
+ }
+ }
+}
+
+void cTVDBEpisode::Dump() {
+ cout << "----------------------------------------" << endl;
+ cout << "Season " << season << ", Episode " << number << ", Name: " << name << ", ID: " << id << ", SeasonID " << seasonId << endl;
+ cout << "combinedSeason: " << combinedSeason << ", combinedEpisode: " << combinedEpisode << endl;
+ cout << "First Aired: " << firstAired << endl;
+ cout << "Guest Stars: " << guestStars << endl;
+ cout << "Overview: " << overview << endl;
+ cout << "Rating: " << rating << endl;
+ cout << "imageUrl: " << imageUrl << ", Size: " << width << " x " << height << ", Flag: " << imgFlag << endl;
+ cout << "Last Update: " << lastUpdated << endl;
+}
diff --git a/scraper/thetvdbscraper/tvdbepisode.h b/scraper/thetvdbscraper/tvdbepisode.h
new file mode 100644
index 0000000..945278b
--- /dev/null
+++ b/scraper/thetvdbscraper/tvdbepisode.h
@@ -0,0 +1,45 @@
+#ifndef __TVSCRAPER_TVDBEPISODE_H
+#define __TVSCRAPER_TVDBEPISODE_H
+
+#include <iostream>
+#include <string>
+#include <sstream>
+#include <vector>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include "tvdbmirrors.h"
+
+using namespace std;
+
+// --- cTVDBEpisode -------------------------------------------------------------
+class cTVDBEpisode {
+private:
+ string apiKey;
+ cTVDBMirrors *mirrors;
+ string language;
+ void ParseXML(string xml);
+public:
+ cTVDBEpisode(void);
+ cTVDBEpisode(int ID, string language, string apiKey, cTVDBMirrors *mirrors);
+ int id;
+ int seriesID;
+ int number;
+ int season;
+ int combinedSeason;
+ int combinedEpisode;
+ string name;
+ string firstAired;
+ string guestStars;
+ string overview;
+ float rating;
+ string imageUrl;
+ int width;
+ int height;
+ int imgFlag;
+ int seasonId;
+ int lastUpdated;
+ void ReadEpisode(void);
+ void ReadEpisodeFromXML(xmlDoc *myDoc, xmlNode *node, cTVDBMirrors *mirrors);
+ void Dump();
+};
+#endif //cTVDBEpisode
diff --git a/scraper/thetvdbscraper/tvdbmedia.c b/scraper/thetvdbscraper/tvdbmedia.c
new file mode 100644
index 0000000..7495f3b
--- /dev/null
+++ b/scraper/thetvdbscraper/tvdbmedia.c
@@ -0,0 +1,202 @@
+#include "tvdbmedia.h"
+
+using namespace std;
+
+cTVDBSeriesMedia::cTVDBSeriesMedia(string language, cTVDBMirrors *mirrors) {
+ this->language = language;
+ fallbackLanguage = "en";
+ this->mirrors = mirrors;
+}
+
+cTVDBSeriesMedia::~cTVDBSeriesMedia() {
+}
+
+void cTVDBSeriesMedia::ParseXML(string xml, vector<cTVDBBanner*> *banners, vector<cTVDBFanart*> *fanarts, vector<cTVDBPoster*> *posters, vector<cTVDBSeasonPoster*> *seasonPosters) {
+ xmlDoc *doc = xmlReadMemory(xml.c_str(), xml.size(), "noname.xml", NULL, 0);
+ this->banners = banners;
+ this->fanarts = fanarts;
+ this->posters = posters;
+ this->seasonPosters = seasonPosters;
+ if (doc == NULL)
+ return;
+ //Root Element has to be <Banners>
+ xmlNode *node = NULL;
+ node = xmlDocGetRootElement(doc);
+ if (!(node && !xmlStrcmp(node->name, (const xmlChar *)"Banners"))) {
+ xmlFreeDoc(doc);
+ return;
+ }
+ //Looping through banners
+ node = node->children;
+ xmlNode *cur_node = NULL;
+ for (cur_node = node; cur_node; cur_node = cur_node->next) {
+ if ((cur_node->type == XML_ELEMENT_NODE) && !xmlStrcmp(cur_node->name, (const xmlChar *)"Banner")) {
+ ReadEntry(doc, cur_node->children);
+ }
+ }
+ xmlFreeDoc(doc);
+}
+
+void cTVDBSeriesMedia::ReadEntry(xmlDoc *doc, xmlNode *node) {
+ xmlNode *cur_node = NULL;
+ xmlChar *node_content;
+ for (cur_node = node; cur_node; cur_node = cur_node->next) {
+ if (cur_node->type == XML_ELEMENT_NODE) {
+ node_content = xmlNodeListGetString(doc, cur_node->xmlChildrenNode, 1);
+ if (!node_content)
+ continue;
+ if (!xmlStrcmp(cur_node->name, (const xmlChar *)"BannerType")) {
+
+ if (!xmlStrcmp(node_content, (const xmlChar *)"poster"))
+ ReadPoster(doc, node);
+ else if (!xmlStrcmp(node_content, (const xmlChar *)"fanart"))
+ ReadFanart(doc, node);
+ else if (!xmlStrcmp(node_content, (const xmlChar *)"series"))
+ ReadBanner(doc, node);
+ else if (!xmlStrcmp(node_content, (const xmlChar *)"season"))
+ ReadSeasonPoster(doc, node);
+
+ }
+ xmlFree(node_content);
+ }
+ }
+}
+
+void cTVDBSeriesMedia::ReadFanart(xmlDoc *doc, xmlNode *node) {
+ xmlNode *cur_node = NULL;
+ xmlChar *node_content;
+ cTVDBFanart *fanart = new cTVDBFanart();
+ //default size
+ fanart->width = 1920;
+ fanart->height = 1080;
+ for (cur_node = node; cur_node; cur_node = cur_node->next) {
+ if (cur_node->type == XML_ELEMENT_NODE) {
+ node_content = xmlNodeListGetString(doc, cur_node->xmlChildrenNode, 1);
+ if (!node_content)
+ continue;
+ if (!xmlStrcmp(cur_node->name, (const xmlChar *)"BannerPath")) {
+ fanart->url = mirrors->GetMirrorBanner() + (const char *)node_content;
+ } else if (!xmlStrcmp(cur_node->name, (const xmlChar *)"Language")) {
+ fanart->language = (const char *)node_content;
+ } else if (!xmlStrcmp(cur_node->name, (const xmlChar *)"Rating")) {
+ fanart->rating = atof((const char *)node_content);
+ } else if (!xmlStrcmp(cur_node->name, (const xmlChar *)"ThumbnailPath")) {
+ fanart->thumbUrl = mirrors->GetMirrorBanner() + (const char *)node_content;
+ } else if (!xmlStrcmp(cur_node->name, (const xmlChar *)"BannerType2")) {
+ string fanartSize = (const char *)node_content;
+ size_t posX = fanartSize.find("x");
+ fanart->width = atoi(fanartSize.substr(0, posX).c_str());
+ fanart->height = atoi(fanartSize.substr(posX+1).c_str());
+ }
+ xmlFree(node_content);
+ }
+ }
+ if ( (fanart->url.size() == 0) ||
+ ((fanart->language.compare(language)) && (fanart->language.compare(fallbackLanguage)))) {
+ delete fanart;
+ return;
+ }
+ fanarts->push_back(fanart);
+}
+
+void cTVDBSeriesMedia::ReadPoster(xmlDoc *doc, xmlNode *node) {
+ xmlNode *cur_node = NULL;
+ xmlChar *node_content;
+ cTVDBPoster *poster = new cTVDBPoster();
+ //default size
+ poster->width = 400;
+ poster->height = 578;
+ for (cur_node = node; cur_node; cur_node = cur_node->next) {
+ if (cur_node->type == XML_ELEMENT_NODE) {
+ node_content = xmlNodeListGetString(doc, cur_node->xmlChildrenNode, 1);
+ if (!node_content)
+ continue;
+ if (!xmlStrcmp(cur_node->name, (const xmlChar *)"BannerPath")) {
+ poster->url = mirrors->GetMirrorBanner() + (const char *)node_content;
+ } else if (!xmlStrcmp(cur_node->name, (const xmlChar *)"Language")) {
+ poster->language = (const char *)node_content;
+ } else if (!xmlStrcmp(cur_node->name, (const xmlChar *)"Rating")) {
+ poster->rating = atof((const char *)node_content);
+ } else if (!xmlStrcmp(cur_node->name, (const xmlChar *)"BannerType2")) {
+ string posterSize = (const char *)node_content;
+ size_t posX = posterSize.find("x");
+ poster->width = atoi(posterSize.substr(0, posX).c_str());
+ poster->height = atoi(posterSize.substr(posX+1).c_str());
+ }
+ xmlFree(node_content);
+ }
+ }
+ if ( (poster->url.size() == 0) ||
+ ((poster->language.compare(language)) && (poster->language.compare(fallbackLanguage)))) {
+ delete poster;
+ return;
+ }
+ posters->push_back(poster);
+}
+
+void cTVDBSeriesMedia::ReadSeasonPoster(xmlDoc *doc, xmlNode *node) {
+ xmlNode *cur_node = NULL;
+ xmlChar *node_content;
+ cTVDBSeasonPoster *poster = new cTVDBSeasonPoster();
+ poster->width = 400;
+ poster->height = 578;
+ bool add = true;
+ for (cur_node = node; cur_node; cur_node = cur_node->next) {
+ if (cur_node->type == XML_ELEMENT_NODE) {
+ node_content = xmlNodeListGetString(doc, cur_node->xmlChildrenNode, 1);
+ if (!node_content)
+ continue;
+ if (!xmlStrcmp(cur_node->name, (const xmlChar *)"BannerPath")) {
+ poster->url = mirrors->GetMirrorBanner() + (const char *)node_content;
+ } else if (!xmlStrcmp(cur_node->name, (const xmlChar *)"Language")) {
+ poster->language = (const char *)node_content;
+ } else if (!xmlStrcmp(cur_node->name, (const xmlChar *)"Rating")) {
+ poster->rating = atof((const char *)node_content);
+ } else if (!xmlStrcmp(cur_node->name, (const xmlChar *)"Season")) {
+ poster->season = atoi((const char *)node_content);
+ } else if (!xmlStrcmp(cur_node->name, (const xmlChar *)"BannerType2")) {
+ string bt2 = (const char *)node_content;
+ if (!bt2.compare("seasonwide"))
+ add = false;
+ }
+ xmlFree(node_content);
+ }
+ }
+ if ( (poster->url.size() == 0) ||
+ (poster->season == 0) ||
+ (!add) ||
+ ((poster->language.compare(language)) && (poster->language.compare(fallbackLanguage)))) {
+ delete poster;
+ return;
+ }
+ seasonPosters->push_back(poster);
+}
+
+void cTVDBSeriesMedia::ReadBanner(xmlDoc *doc, xmlNode *node) {
+ xmlNode *cur_node = NULL;
+ xmlChar *node_content;
+ cTVDBBanner *banner = new cTVDBBanner();
+ banner->width = 758;
+ banner->height = 140;
+ for (cur_node = node; cur_node; cur_node = cur_node->next) {
+ if (cur_node->type == XML_ELEMENT_NODE) {
+ node_content = xmlNodeListGetString(doc, cur_node->xmlChildrenNode, 1);
+ if (!node_content)
+ continue;
+ if (!xmlStrcmp(cur_node->name, (const xmlChar *)"BannerPath")) {
+ banner->url = mirrors->GetMirrorBanner() + (const char *)node_content;
+ } else if (!xmlStrcmp(cur_node->name, (const xmlChar *)"Language")) {
+ banner->language = (const char *)node_content;
+ } else if (!xmlStrcmp(cur_node->name, (const xmlChar *)"Rating")) {
+ banner->rating = atof((const char *)node_content);
+ }
+ xmlFree(node_content);
+ }
+ }
+ if ( (banner->url.size() == 0) ||
+ ((banner->language.compare(language)) && (banner->language.compare(fallbackLanguage)))) {
+ delete banner;
+ return;
+ }
+ banners->push_back(banner);
+}
diff --git a/scraper/thetvdbscraper/tvdbmedia.h b/scraper/thetvdbscraper/tvdbmedia.h
new file mode 100644
index 0000000..4277c39
--- /dev/null
+++ b/scraper/thetvdbscraper/tvdbmedia.h
@@ -0,0 +1,111 @@
+#ifndef __TVSCRAPER_TVDBMEDIA_H
+#define __TVSCRAPER_TVDBMEDIA_H
+
+#include <iostream>
+#include <string>
+#include <sstream>
+#include <vector>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include "tvdbmirrors.h"
+
+using namespace std;
+
+// --- cTVDBMedia -------------------------------------------------------------
+class cTVDBMedia {
+public:
+ cTVDBMedia(void) {
+ url = "";
+ language = "";
+ width = 0;
+ height = 0;
+ rating = 0.0;
+ };
+ string url;
+ string language;
+ int width, height;
+ double rating;
+};
+
+// --- cTVDBFanart -------------------------------------------------------------
+class cTVDBFanart : public cTVDBMedia {
+public:
+ cTVDBFanart(void) {
+ thumbUrl = "";
+ };
+ string thumbUrl;
+ void Dump() {
+ cout << "Url: " << url << endl;
+ cout << "Url Thumbnail: " << thumbUrl << endl;
+ cout << "Language: " << language << endl;
+ cout << "Size: " << width << " x " << height << endl;
+ cout << "Rating: " << rating << endl;
+ };
+};
+
+// --- cTVDBPoster -------------------------------------------------------------
+class cTVDBPoster : public cTVDBMedia {
+public:
+ cTVDBPoster(void) {
+ };
+ void Dump() {
+ cout << "Url: " << url << endl;
+ cout << "Language: " << language << endl;
+ cout << "Size: " << width << " x " << height << endl;
+ cout << "Rating: " << rating << endl;
+ };
+};
+
+// --- cTVDBSeasonPoster -------------------------------------------------------------
+class cTVDBSeasonPoster : public cTVDBMedia {
+public:
+ cTVDBSeasonPoster(void) {
+ season = 0;
+ };
+ int season;
+ void Dump() {
+ cout << "Url: " << url << endl;
+ cout << "Season: " << season << endl;
+ cout << "Language: " << language << endl;
+ cout << "Size: " << width << " x " << height << endl;
+ cout << "Rating: " << rating << endl;
+ };
+};
+
+// --- cTVDBBanner -------------------------------------------------------------
+class cTVDBBanner : public cTVDBMedia {
+public:
+ cTVDBBanner(void) {
+ };
+ int season;
+ void Dump() {
+ cout << "Url: " << url << endl;
+ cout << "Language: " << language << endl;
+ cout << "Size: " << width << " x " << height << endl;
+ cout << "Rating: " << rating << endl;
+ };
+};
+
+// --- cTVDBSeriesMedia --------------------------------------------------------
+
+class cTVDBSeriesMedia {
+private:
+ string language;
+ string fallbackLanguage;
+ cTVDBMirrors *mirrors;
+ vector<cTVDBBanner*> *banners;
+ vector<cTVDBFanart*> *fanarts;
+ vector<cTVDBPoster*> *posters;
+ vector<cTVDBSeasonPoster*> *seasonPosters;
+ void ReadEntry(xmlDoc *doc, xmlNode *node);
+ void ReadFanart(xmlDoc *doc, xmlNode *node);
+ void ReadPoster(xmlDoc *doc, xmlNode *node);
+ void ReadBanner(xmlDoc *doc, xmlNode *node);
+ void ReadSeasonPoster(xmlDoc *doc, xmlNode *node);
+public:
+ cTVDBSeriesMedia(string language, cTVDBMirrors *mirrors);
+ virtual ~cTVDBSeriesMedia(void);
+ void ParseXML(string xml, vector<cTVDBBanner*> *banners, vector<cTVDBFanart*> *fanarts, vector<cTVDBPoster*> *posters, vector<cTVDBSeasonPoster*> *seasonPosters);
+};
+
+#endif //__TVSCRAPER_TVDBMEDIA_H
diff --git a/scraper/thetvdbscraper/tvdbmirrors.c b/scraper/thetvdbscraper/tvdbmirrors.c
new file mode 100644
index 0000000..2c063ec
--- /dev/null
+++ b/scraper/thetvdbscraper/tvdbmirrors.c
@@ -0,0 +1,88 @@
+#include "tvdbmirrors.h"
+
+using namespace std;
+
+cTVDBMirrors::cTVDBMirrors(void) {
+}
+
+cTVDBMirrors::~cTVDBMirrors() {
+}
+
+string cTVDBMirrors::GetMirrorXML(void) {
+ if (xmlmirrors.size() == 0)
+ return "";
+ int randMirror = rand() % xmlmirrors.size();
+ return xmlmirrors[randMirror];
+}
+string cTVDBMirrors::GetMirrorBanner(void) {
+ if (bannermirrors.size() == 0)
+ return "";
+ int randMirror = rand() % bannermirrors.size();
+ return bannermirrors[randMirror] + "/banners/";
+}
+
+string cTVDBMirrors::GetMirrorZip(void) {
+ if (zipmirrors.size() == 0)
+ return "";
+ int randMirror = rand() % zipmirrors.size();
+ return zipmirrors[randMirror];
+}
+
+bool cTVDBMirrors::ParseXML(string xml) {
+ xmlDoc *doc = xmlReadMemory(xml.c_str(), xml.size(), "noname.xml", NULL, 0);
+ if (doc == NULL)
+ return false;
+ //Root Element has to be <Mirrors>
+ xmlNode *node = NULL;
+ node = xmlDocGetRootElement(doc);
+ if (!(node && !xmlStrcmp(node->name, (const xmlChar *)"Mirrors"))) {
+ xmlFreeDoc(doc);
+ return false;
+ }
+ //Loop through <Mirror>
+ node = node->children;
+ xmlNode *cur_node = NULL;
+ bool ok = false;
+ for (cur_node = node; cur_node; cur_node = cur_node->next) {
+ if ((cur_node->type == XML_ELEMENT_NODE) && !xmlStrcmp(cur_node->name, (const xmlChar *)"Mirror")) {
+ ok = ReadEntry(doc, cur_node->children);
+ }
+ }
+ xmlFreeDoc(doc);
+ return ok;
+}
+
+bool cTVDBMirrors::ReadEntry(xmlDoc *doc, xmlNode *node) {
+ xmlNode *cur_node = NULL;
+ xmlChar *node_content;
+ string path = "";
+ int typemask = 0;
+ for (cur_node = node; cur_node; cur_node = cur_node->next) {
+ if (cur_node->type == XML_ELEMENT_NODE) {
+ node_content = xmlNodeListGetString(doc, cur_node->xmlChildrenNode, 1);
+ if (!node_content)
+ continue;
+ if (!xmlStrcmp(cur_node->name, (const xmlChar *)"mirrorpath")) {
+ path = (const char *)node_content;
+ } else if (!xmlStrcmp(cur_node->name, (const xmlChar *)"typemask")) {
+ typemask = atoi((const char *)node_content);
+ }
+ xmlFree(node_content);
+ }
+ }
+ return CreateMirror(path, typemask);
+}
+
+bool cTVDBMirrors::CreateMirror(string path, int typemask) {
+ if (path.size() < 1)
+ return false;
+ if (typemask < 1 || typemask > 7)
+ return false;
+ if (typemask & 1)
+ xmlmirrors.push_back(path);
+ if (typemask & 2)
+ bannermirrors.push_back(path);
+ if (typemask & 4)
+ zipmirrors.push_back(path);
+ return true;
+} \ No newline at end of file
diff --git a/scraper/thetvdbscraper/tvdbmirrors.h b/scraper/thetvdbscraper/tvdbmirrors.h
new file mode 100644
index 0000000..cf7dc62
--- /dev/null
+++ b/scraper/thetvdbscraper/tvdbmirrors.h
@@ -0,0 +1,32 @@
+#ifndef __TVSCRAPER_TVDBMIRRORS_H
+#define __TVSCRAPER_TVDBMIRRORS_H
+
+#include <iostream>
+#include <string>
+#include <sstream>
+#include <vector>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+
+using namespace std;
+
+// --- cTVDBMirrors -------------------------------------------------------------
+
+class cTVDBMirrors {
+private:
+ vector<string> xmlmirrors;
+ vector<string> bannermirrors;
+ vector<string> zipmirrors;
+ bool ReadEntry(xmlDoc *doc, xmlNode *node);
+ bool CreateMirror(string path, int typemask);
+public:
+ cTVDBMirrors(void);
+ virtual ~cTVDBMirrors(void);
+ bool ParseXML(string xml);
+ string GetMirrorXML(void);
+ string GetMirrorBanner(void);
+ string GetMirrorZip(void);
+};
+
+
+#endif //__TVSCRAPER_TVDBMIRRORS_H
diff --git a/scraper/thetvdbscraper/tvdbseries.c b/scraper/thetvdbscraper/tvdbseries.c
new file mode 100644
index 0000000..21dc78b
--- /dev/null
+++ b/scraper/thetvdbscraper/tvdbseries.c
@@ -0,0 +1,281 @@
+
+#include "../../lib/curl.h"
+#include "tvdbseries.h"
+
+using namespace std;
+
+cTVDBSeries::cTVDBSeries(int ID, string language, string apiKey, cTVDBMirrors *mirrors) {
+ this->language = language;
+ this->apiKey = apiKey;
+ this->mirrors = mirrors;
+ seriesID = ID;
+ name = "";
+ banner = "";
+ fanart = "";
+ poster = "";
+ overview = "";
+ firstAired = "";
+ network = "";
+ imbdid = "";
+ genre = "";
+ rating = 0.0;
+ status = "";
+ currentEpisode = 0;
+ currentActor = 0;
+ currentFanart = 0;
+ currentPoster = 0;
+ currentSeasonPoster = 0;
+ currentBanner = 0;
+}
+
+cTVDBSeries::~cTVDBSeries() {
+ for(std::vector<cTVDBEpisode*>::const_iterator it = episodes.begin(); it != episodes.end(); it++) {
+ delete *it;
+ }
+ episodes.clear();
+ for(std::vector<cTVDBActor*>::const_iterator it = actors.begin(); it != actors.end(); it++) {
+ delete *it;
+ }
+ actors.clear();
+ for(std::vector<cTVDBFanart*>::const_iterator it = fanarts.begin(); it != fanarts.end(); it++) {
+ delete *it;
+ }
+ fanarts.clear();
+ for(std::vector<cTVDBPoster*>::const_iterator it = posters.begin(); it != posters.end(); it++) {
+ delete *it;
+ }
+ posters.clear();
+ for(std::vector<cTVDBSeasonPoster*>::const_iterator it = seasonPosters.begin(); it != seasonPosters.end(); it++) {
+ delete *it;
+ }
+ seasonPosters.clear();
+ for(std::vector<cTVDBBanner*>::const_iterator it = banners.begin(); it != banners.end(); it++) {
+ delete *it;
+ }
+ banners.clear();
+}
+
+bool cTVDBSeries::ReadSeries(void) {
+ stringstream url;
+ url << mirrors->GetMirrorXML() << "/api/" << apiKey << "/series/" << seriesID << "/all/" << language << ".xml";
+ string seriesXML;
+ if (curl.GetUrl(url.str().c_str(), &seriesXML)) {
+ ParseXML(seriesXML);
+ return true;
+ }
+ return false;
+}
+
+void cTVDBSeries::ReadMedia(void) {
+ stringstream url;
+ url << mirrors->GetMirrorXML() << "/api/" << apiKey << "/series/" << seriesID << "/banners.xml";
+ string bannersXML;
+ if (curl.GetUrl(url.str().c_str(), &bannersXML)) {
+ cTVDBSeriesMedia med(language, mirrors);
+ med.ParseXML(bannersXML, &banners, &fanarts, &posters, &seasonPosters);
+ }
+}
+
+void cTVDBSeries::ReadActors(void) {
+ stringstream url;
+ url << mirrors->GetMirrorXML() << "/api/" << apiKey << "/series/" << seriesID << "/actors.xml";
+ string actorsXML;
+ if (curl.GetUrl(url.str().c_str(), &actorsXML)) {
+ cTVDBActors act(language, mirrors);
+ act.ParseXML(actorsXML, &actors);
+ }
+}
+
+void cTVDBSeries::ParseXML(string xml) {
+ xmlDoc *doc = xmlReadMemory(xml.c_str(), xml.size(), "noname.xml", NULL, 0);
+ if (doc == NULL)
+ return;
+ //Root Element has to be <Data>
+ xmlNode *node = NULL;
+ node = xmlDocGetRootElement(doc);
+ if (!(node && !xmlStrcmp(node->name, (const xmlChar *)"Data"))) {
+ xmlFreeDoc(doc);
+ return;
+ }
+ //Looping through episodes
+ node = node->children;
+ xmlNode *cur_node = NULL;
+ for (cur_node = node; cur_node; cur_node = cur_node->next) {
+ if ((cur_node->type == XML_ELEMENT_NODE) && !xmlStrcmp(cur_node->name, (const xmlChar *)"Series")) {
+ ReadSeriesData(doc, cur_node->children);
+ } else if ((cur_node->type == XML_ELEMENT_NODE) && !xmlStrcmp(cur_node->name, (const xmlChar *)"Episode")) {
+ cTVDBEpisode *episode = new cTVDBEpisode();
+ episode->ReadEpisodeFromXML(doc, cur_node->children, mirrors);
+ episodes.push_back(episode);
+ }
+ }
+ xmlFreeDoc(doc);
+}
+
+void cTVDBSeries::ReadSeriesData(xmlDoc *doc, xmlNode *node) {
+ xmlNode *cur_node = NULL;
+ xmlChar *node_content;
+ for (cur_node = node; cur_node; cur_node = cur_node->next) {
+ if (cur_node->type == XML_ELEMENT_NODE) {
+ node_content = xmlNodeListGetString(doc, cur_node->xmlChildrenNode, 1);
+ if (!node_content)
+ continue;
+ if (!xmlStrcmp(cur_node->name, (const xmlChar *)"FirstAired")) {
+ firstAired = (const char *)node_content;
+ } else if (!xmlStrcmp(cur_node->name, (const xmlChar *)"Genre")) {
+ genre = (const char *)node_content;
+ } else if (!xmlStrcmp(cur_node->name, (const xmlChar *)"IMDB_ID")) {
+ imbdid = (const char *)node_content;
+ } else if (!xmlStrcmp(cur_node->name, (const xmlChar *)"Network")) {
+ network = (const char *)node_content;
+ } else if (!xmlStrcmp(cur_node->name, (const xmlChar *)"Overview")) {
+ overview = (const char *)node_content;
+ } else if (!xmlStrcmp(cur_node->name, (const xmlChar *)"Rating")) {
+ rating = atof((const char *)node_content);
+ } else if (!xmlStrcmp(cur_node->name, (const xmlChar *)"SeriesName")) {
+ name = (const char *)node_content;
+ } else if (!xmlStrcmp(cur_node->name, (const xmlChar *)"Status")) {
+ status = (const char *)node_content;
+ } else if (!xmlStrcmp(cur_node->name, (const xmlChar *)"banner")) {
+ banner = mirrors->GetMirrorBanner() + (const char *)node_content;
+ } else if (!xmlStrcmp(cur_node->name, (const xmlChar *)"fanart")) {
+ fanart = mirrors->GetMirrorBanner() + (const char *)node_content;
+ } else if (!xmlStrcmp(cur_node->name, (const xmlChar *)"poster")) {
+ poster = mirrors->GetMirrorBanner() + (const char *)node_content;
+ } else if (!xmlStrcmp(cur_node->name, (const xmlChar *)"lastupdated")) {
+ lastUpdated = atoi((const char *)node_content);
+ }
+ xmlFree(node_content);
+ }
+ }
+}
+
+cTVDBEpisode *cTVDBSeries::GetEpisode(void) {
+ int numEpisodes = episodes.size();
+ if ((numEpisodes < 1) || (currentEpisode >= numEpisodes))
+ return NULL;
+ cTVDBEpisode *epi = episodes[currentEpisode];
+ currentEpisode++;
+ return epi;
+}
+
+cTVDBActor *cTVDBSeries::GetActor(void) {
+ int numActors = actors.size();
+ if ((numActors < 1) || (currentActor >= numActors))
+ return NULL;
+ cTVDBActor *act = actors[currentActor];
+ currentActor++;
+ return act;
+}
+
+cTVDBFanart *cTVDBSeries::GetFanart(void) {
+ int numFanarts = fanarts.size();
+ if ((numFanarts < 1) || (currentFanart >= numFanarts))
+ return NULL;
+ cTVDBFanart *fan = fanarts[currentFanart];
+ currentFanart++;
+ return fan;
+}
+
+cTVDBPoster *cTVDBSeries::GetPoster(void) {
+ int numPosters = posters.size();
+ if ((numPosters < 1) || (currentPoster >= numPosters))
+ return NULL;
+ cTVDBPoster *pos = posters[currentPoster];
+ currentPoster++;
+ return pos;
+}
+
+cTVDBSeasonPoster *cTVDBSeries::GetSeasonPoster(void) {
+ int numSeasonPosters = seasonPosters.size();
+ if ((numSeasonPosters < 1) || (currentSeasonPoster >= numSeasonPosters))
+ return NULL;
+ cTVDBSeasonPoster *pos = seasonPosters[currentSeasonPoster];
+ currentSeasonPoster++;
+ return pos;
+}
+
+cTVDBSeasonPoster *cTVDBSeries::GetSeasonPoster(int season) {
+ int numSeasonPoster = seasonPosters.size();
+ for (int i=0; i<numSeasonPoster; i++) {
+ if (seasonPosters[i]->season == season)
+ return seasonPosters[i];
+ }
+ return NULL;
+}
+
+cTVDBBanner *cTVDBSeries::GetBanner(void) {
+ int numBanners = banners.size();
+ if ((numBanners < 1) || (currentBanner >= numBanners))
+ return NULL;
+ cTVDBBanner *ban = banners[currentBanner];
+ currentBanner++;
+ return ban;
+}
+
+bool cTVDBSeries::GetPartAndSeason(int episodeId, int &season, int &part) {
+ for (vector<cTVDBEpisode*>::iterator ep = episodes.begin(); ep != episodes.end(); ep++) {
+ cTVDBEpisode *episode = *ep;
+ if(episode->id == episodeId) {
+ season = episode->season;
+ part = episode->number;
+ return true;
+ }
+ }
+ return false;
+}
+
+void cTVDBSeries::Dump(int maxEntries) {
+ cout << "--------------------------- Series Info ----------------------------------" << endl;
+ cout << "series " << name << ", ID: " << seriesID <<endl;
+ cout << "Overview: " << overview << endl;
+ cout << "Banner: " << banner << endl;
+ cout << "Poster: " << poster << endl;
+ cout << "Fanart: " << fanart << endl;
+ cout << "imdb: " << imbdid << endl;
+ cout << "FirstAired: " << firstAired << endl;
+ cout << "Network: " << network << endl;
+ cout << "Status: " << status << endl;
+ cout << "lastUpdated: " << lastUpdated << endl;
+ cout << "Genre: " << genre << endl;
+ cout << "Rating: " << rating << endl;
+
+ int size = episodes.size();
+ cout << "--------------------------- " << size << " episodes ----------------------------------" << endl;
+ for (int i=0; i<size; i++) {
+ if (maxEntries && (i == maxEntries)) break;
+ episodes[i]->Dump();
+ }
+
+ size = actors.size();
+ cout << "--------------------------- " << size << " actors ----------------------------------" << endl;
+ for (int i=0; i<size; i++) {
+ if (maxEntries && (i == maxEntries)) break;
+ actors[i]->Dump();
+ }
+
+ int numFanart = fanarts.size();
+ cout << "--------------------------- " << numFanart << " fanarts ----------------------------------" << endl;
+ for (int i=0; i<numFanart; i++) {
+ if (maxEntries && (i == maxEntries)) break;
+ fanarts[i]->Dump();
+ }
+ int numPoster = posters.size();
+ cout << "--------------------------- " << numPoster << " posters ----------------------------------" << endl;
+ for (int i=0; i<numPoster; i++) {
+ if (maxEntries && (i == maxEntries)) break;
+ posters[i]->Dump();
+ }
+ int numSeasonPoster = seasonPosters.size();
+ cout << "--------------------------- " << numSeasonPoster << " season posters ---------------------------" << endl;
+ for (int i=0; i<numSeasonPoster; i++) {
+ if (maxEntries && (i == maxEntries)) break;
+ seasonPosters[i]->Dump();
+ }
+ int numBanner = banners.size();
+ cout << "--------------------------- " << numBanner << " banners ----------------------------------" << endl;
+ for (int i=0; i<numBanner; i++) {
+ if (maxEntries && (i == maxEntries)) break;
+ banners[i]->Dump();
+ }
+}
diff --git a/scraper/thetvdbscraper/tvdbseries.h b/scraper/thetvdbscraper/tvdbseries.h
new file mode 100644
index 0000000..bf7a84d
--- /dev/null
+++ b/scraper/thetvdbscraper/tvdbseries.h
@@ -0,0 +1,69 @@
+#ifndef __TVSCRAPER_TVDBSERIES_H
+#define __TVSCRAPER_TVDBSERIES_H
+
+#include <iostream>
+#include <string>
+#include <sstream>
+#include <vector>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include "tvdbmirrors.h"
+#include "tvdbactor.h"
+#include "tvdbmedia.h"
+#include "tvdbepisode.h"
+
+using namespace std;
+
+// --- cTVDBSeries -------------------------------------------------------------
+
+class cTVDBSeries {
+private:
+ string apiKey;
+ cTVDBMirrors *mirrors;
+ string language;
+ vector<cTVDBEpisode*> episodes;
+ vector<cTVDBActor*> actors;
+ vector<cTVDBFanart*> fanarts;
+ vector<cTVDBPoster*> posters;
+ vector<cTVDBSeasonPoster*> seasonPosters;
+ vector<cTVDBBanner*> banners;
+ int currentEpisode;
+ int currentActor;
+ int currentFanart;
+ int currentPoster;
+ int currentSeasonPoster;
+ int currentBanner;
+ void ParseXML(string xml);
+ void ReadSeriesData(xmlDoc *doc, xmlNode *node);
+public:
+ cTVDBSeries(int ID, string language, string apiKey, cTVDBMirrors *mirrors);
+ virtual ~cTVDBSeries(void);
+ bool ReadSeries(void);
+ void ReadMedia(void);
+ void ReadActors(void);
+ cTVDBEpisode *GetEpisode(void);
+ cTVDBActor *GetActor(void);
+ cTVDBFanart *GetFanart(void);
+ cTVDBPoster *GetPoster(void);
+ cTVDBSeasonPoster *GetSeasonPoster(void);
+ cTVDBSeasonPoster *GetSeasonPoster(int season);
+ cTVDBBanner *GetBanner(void);
+ bool GetPartAndSeason(int episodeId, int &season, int &part);
+ int seriesID;
+ int lastUpdated;
+ string name;
+ string banner;
+ string fanart;
+ string poster;
+ string overview;
+ string firstAired;
+ string network;
+ string imbdid;
+ string genre;
+ float rating;
+ string status;
+ void Dump(int maxEntries = 0);
+};
+
+
+#endif //__TVSCRAPER_TVDBSERIES_H