You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
988 lines
44 KiB
988 lines
44 KiB
#include <stdbool.h>
|
|
#include <stdlib.h>
|
|
#include <pthread.h>
|
|
#include <bsd/string.h>
|
|
#include <cjson/cJSON.h>
|
|
#include <unistd.h>
|
|
#include <errno.h>
|
|
#include "tvshow.h"
|
|
#include "fileList.h"
|
|
#include "thread.h"
|
|
#include "iofiles.h"
|
|
#include "utils.h"
|
|
|
|
|
|
// JSON maker
|
|
struct fileList *createTVShowDB(progConfig *conf) {
|
|
printInfo("createTVShowDB info", true, "building TV shows' database...\n");
|
|
fileList *showFolders=find(conf, conf->TVpath, "", DI_MODE, false);
|
|
|
|
if (showFolders != NULL ) {
|
|
int foldersListSize=showFolders->listSize, i=0;
|
|
pthread_t *threads=NULL;
|
|
mallocMacro(threads, sizeof(pthread_t)*foldersListSize, "createTVShowDB error");
|
|
|
|
threadStruct *threadObj=NULL;
|
|
mallocMacro(threadObj, sizeof(threadStruct)*foldersListSize, "createTVShowDB error");
|
|
cJSON *tempJSON=NULL;
|
|
// open JSON database/set up cJSON
|
|
if (conf->tvDB_exists==true) {
|
|
tempJSON=cJSON_Duplicate(conf->JSON_tvDB, true);
|
|
}
|
|
for (fileList *tempList = showFolders; tempList != NULL; tempList = tempList->next, i++) {
|
|
threadObj[i].conf=conf;
|
|
threadObj[i].data=tempList->data;
|
|
threadObj[i].oldJSON=NULL;
|
|
threadObj[i].list=NULL;
|
|
threadObj[i].id=0;
|
|
|
|
if (conf->tvDB_exists==true && tempJSON!=NULL) {
|
|
char *tvShowName=replaceAll(tempList->data[1], ".", " ");
|
|
cJSON *item=NULL;
|
|
|
|
cJSON_ArrayForEach(item, tempJSON){
|
|
if (cJSON_GetObjectItem(item, "show")!=NULL && cJSON_GetStringValue(cJSON_GetObjectItem(item, "show"))!=NULL) {
|
|
char *tempStr=cJSON_GetStringValue(cJSON_GetObjectItem(item, "show"));
|
|
if (strcmp(tempStr, tvShowName)==0) { // match
|
|
threadObj[i].id=parseStrToInt(cJSON_GetStringValue(cJSON_GetObjectItem(item, "ID")));
|
|
threadObj[i].oldJSON=cJSON_DetachItemViaPointer(tempJSON, item);
|
|
break;
|
|
}
|
|
} else {
|
|
printError("createTVShowDB warning", false, HYEL, "some errors occured while reading \"%s\", parts of the database will be rebuilt from scratch...\n", conf->dbNameTV);
|
|
threadObj[i].oldJSON=NULL;
|
|
conf->tvDB_exists=false;
|
|
cJSON_Delete(tempJSON);
|
|
tempJSON=NULL;
|
|
break;
|
|
}
|
|
}
|
|
tryFree(tvShowName);
|
|
}
|
|
|
|
pthread_create(&threads[i], NULL, findSeasons, (void *) &threadObj[i]);
|
|
}
|
|
|
|
fileList *showJSON=NULL;
|
|
for (i=0; i<foldersListSize;i++) { // loop through all found tv shows
|
|
pthread_join(threads[i], NULL);
|
|
|
|
showJSON=joinLists(showJSON, threadObj[i].list);
|
|
if (threadObj[i].oldJSON!=NULL){
|
|
cJSON_Delete(threadObj[i].oldJSON);
|
|
}
|
|
}
|
|
if (tempJSON!=NULL){
|
|
cJSON_Delete(tempJSON);
|
|
}
|
|
tryFree(threads);
|
|
tryFree(threadObj);
|
|
freeList(showFolders);
|
|
|
|
// sort shows alphabetically
|
|
msortList(&showJSON, 1, true, STRING);
|
|
|
|
for (fileList *temp=showJSON; temp!=NULL; temp=temp->next) { // remove temp->data[1] (which should be the tv show name), meanwhile temp->data[0] is the whole show JSON
|
|
tryFree(temp->data[temp->dataSize-1]);
|
|
temp->dataSize--;
|
|
}
|
|
char *jsonStr=fileListToJSONStr(showJSON);
|
|
if (jsonStr!=NULL) {
|
|
cJSON_Delete(conf->JSON_tvDB);
|
|
conf->JSON_tvDB=cJSON_Parse(jsonStr);
|
|
}
|
|
tryFree(jsonStr);
|
|
|
|
return showJSON;
|
|
} else {
|
|
printError("createTVShowDB warning", false, HYEL, "could not find anything in \"%s\";\n", conf->TVpath);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void *findSeasons(void *threadArg) { // runs in Show.Name folder and spawns threads in every season folder
|
|
threadStruct *thisThread=(threadStruct *) threadArg;
|
|
progConfig *conf=thisThread->conf;
|
|
|
|
|
|
size_t lenStr1=strlen(thisThread->data[0]);
|
|
size_t lenStr2=strlen(thisThread->data[1]); // thisThread->data[1] name of tv show top folder
|
|
char *showPath=NULL;
|
|
mallocMacro(showPath, lenStr1+lenStr2+2, "findSeasons error");
|
|
strlcpy(showPath, thisThread->data[0], lenStr1+1);
|
|
if (showPath[lenStr1 - 1] != '/') {
|
|
strlcat(showPath, "/", lenStr1+lenStr2+2);
|
|
}
|
|
strlcat(showPath, thisThread->data[1], lenStr1+lenStr2+2);
|
|
if (thisThread->data[1][lenStr2-1] != '/') {
|
|
strlcat(showPath, "/", lenStr1+lenStr2+2);
|
|
}
|
|
// Find all the seasons of the current tv show
|
|
printInfo("findSeasons info", true, "looking for seasons' folders in: \"%s\";\n", showPath);
|
|
fileList *seasonsList = find(conf, showPath, "", DI_MODE, false); // get all seasons folders
|
|
|
|
if (seasonsList!=NULL && seasonsList->data!=NULL) {
|
|
bool showHasExtras=false;
|
|
pthread_t *threads=NULL;
|
|
mallocMacro(threads, sizeof(pthread_t)*seasonsList->listSize, "findSeasons error");
|
|
threadStruct *threadObj=NULL;
|
|
mallocMacro(threadObj, sizeof(threadStruct)*seasonsList->listSize, "findSeasons error");
|
|
// TV show stuff
|
|
int tmdb_id=thisThread->id;
|
|
char *imgURL=NULL;
|
|
|
|
char *tvShowName=replaceAll(thisThread->data[1], ".", " ");
|
|
if (tmdb_id==0) {
|
|
tmdb_id=getShowID(conf, tvShowName); // get the ID for this show
|
|
}
|
|
|
|
int i=0;
|
|
for (fileList *tempList=seasonsList; tempList!=NULL; tempList=tempList->next, i++) { // run thread in every season folder
|
|
size_t tempPathSize=strlen(showPath)+strlen(tempList->data[1])+2;
|
|
char *tempPath=NULL; // path to season
|
|
mallocMacro(tempPath, tempPathSize, "findSeasons error");
|
|
strlcpy(tempPath, showPath, tempPathSize);
|
|
strlcat(tempPath, tempList->data[1], tempPathSize);
|
|
if (tempPath[strlen(tempPath)-1]!='/') {
|
|
strlcat(tempPath, "/", tempPathSize);
|
|
}
|
|
if (strstr(tempPath, conf->TVextraStr)) {
|
|
showHasExtras=true;
|
|
}
|
|
|
|
// search for episodes & stuff
|
|
threadObj[i].conf=thisThread->conf;
|
|
threadObj[i].oldJSON=thisThread->oldJSON;
|
|
threadObj[i].list=NULL;
|
|
threadObj[i].data=NULL;
|
|
mallocMacro(threadObj[i].data, sizeof(char **), "findSeasons error");
|
|
size_t tempSize=strlen(tempPath)+1;
|
|
threadObj[i].data[0]=NULL;
|
|
mallocMacro(threadObj[i].data[0], tempSize, "findSeasons error");
|
|
strlcpy(threadObj[i].data[0], tempPath, tempSize);
|
|
threadObj[i].id=tmdb_id;
|
|
|
|
pthread_create(&threads[i], NULL, findEpisodes, (void *) &threadObj[i]);
|
|
tryFree(tempPath);
|
|
}
|
|
// get TV show poster!
|
|
if (thisThread->oldJSON!=NULL) {
|
|
char *tempStr=cJSON_GetStringValue(cJSON_GetObjectItem(thisThread->oldJSON, "Poster"));
|
|
size_t tempStrLen=strlen(tempStr)+1;
|
|
if (tempStrLen>3) {
|
|
imgURL=NULL;
|
|
mallocMacro(imgURL, tempStrLen, "findSeasons error");
|
|
strlcpy(imgURL, tempStr, tempStrLen);
|
|
}
|
|
}
|
|
if (imgURL==NULL && thisThread->conf->getTVposter==true && tmdb_id>0) {
|
|
imgURL=getShowPoster(thisThread->conf, tmdb_id);
|
|
}
|
|
if (imgURL==NULL) { // if still NULL, getShowPoster didn't work...
|
|
imgURL=genImage(conf->AutogenImgResizeTVCmd, conf->dTVFolder, tvShowName);
|
|
/*
|
|
// useless on genImage? compressed results bigger than original
|
|
if (conf->compressImgTV) {
|
|
imgURL=compressImg(conf->compressImgTVCmd, imgURL, true);
|
|
}
|
|
*/
|
|
}
|
|
|
|
for (int j=0; j<i; j++) {
|
|
pthread_join(threads[j], NULL);
|
|
thisThread->list=joinLists(thisThread->list, threadObj[j].list);
|
|
|
|
tryFree(threadObj[j].data[0]);
|
|
tryFree(threadObj[j].data);
|
|
}
|
|
|
|
if (thisThread->list!=NULL) {
|
|
if (thisThread->list->listSize>1) {
|
|
msortList(&thisThread->list, 0, true, INTEGER);
|
|
}
|
|
|
|
size_t numOfSeasons=seasonsList->listSize;
|
|
if (showHasExtras) {
|
|
numOfSeasons--;
|
|
}
|
|
if (imgURL==NULL) {
|
|
mallocMacro(imgURL, 1, "findSeasons error");
|
|
imgURL[0]='\0';
|
|
}
|
|
size_t showJSONStrSize=strlen("{\"Show\":\"\",\"ID\":\"\",\"Poster\":\"\",\"Seasons\":\"\",\"Episodes\":[],\"Extras\":[]}")+strlen(tvShowName)+intSize(tmdb_id)+strlen(imgURL)+intSize(numOfSeasons)+1;
|
|
char *showJSONStr=NULL;
|
|
mallocMacro(showJSONStr, showJSONStrSize, "findSeasons error");
|
|
showJSONStr[0]='\0';
|
|
snprintf(showJSONStr, showJSONStrSize, "{\"Show\":\"%s\",\"ID\":\"%d\",\"Poster\":\"%s\",\"Seasons\":\"%zu\",\"Episodes\":[", tvShowName, tmdb_id, imgURL, numOfSeasons);
|
|
|
|
i=0;
|
|
size_t extrasJSONStrSize=2, j=0;
|
|
char *extrasJSONStr=NULL;
|
|
mallocMacro(extrasJSONStr, extrasJSONStrSize, "findSeasons error");
|
|
extrasJSONStr[0]='\0';
|
|
for (fileList *tempList=thisThread->list; tempList!=NULL; tempList=tempList->next) {
|
|
if (tempList->dataSize>=2 && tempList->data[1]!=NULL) {
|
|
if (strstr(tempList->data[1], conf->TVextraStr)!=NULL) { // check if this list comes from a 'extras season'
|
|
for (size_t k=1; k<tempList->dataSize; k++) { // iterate over all files in the 'extras' folder
|
|
extrasJSONStrSize+=strlen(tempList->data[k]);
|
|
extrasJSONStr=realloc(extrasJSONStr, extrasJSONStrSize);
|
|
if (extrasJSONStr==NULL)
|
|
fatalError_abort("findSeasons error", "could not realloc;\nError: %s;\n", strerror(errno));
|
|
|
|
if (j>0) {
|
|
extrasJSONStrSize++;
|
|
strlcat(extrasJSONStr, ",", extrasJSONStrSize);
|
|
}
|
|
strlcat(extrasJSONStr, tempList->data[k], extrasJSONStrSize);
|
|
j++;
|
|
}
|
|
} else { //list from a regular season, not extras
|
|
for (size_t k=1; k<tempList->dataSize; k++) {
|
|
showJSONStrSize+=strlen(tempList->data[k]);
|
|
showJSONStr=realloc(showJSONStr, showJSONStrSize);
|
|
if (showJSONStr==NULL)
|
|
fatalError_abort("findSeasons error", "could not realloc;\nError: %s;\n", strerror(errno));
|
|
|
|
if (i>0) {
|
|
showJSONStrSize++;
|
|
strlcat(showJSONStr, ",", showJSONStrSize);
|
|
}
|
|
strlcat(showJSONStr, tempList->data[k], showJSONStrSize);
|
|
i++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
char *tempShowJSONStr=NULL;
|
|
mallocMacro(tempShowJSONStr, showJSONStrSize, "findSeasons error");
|
|
strlcpy(tempShowJSONStr, showJSONStr, showJSONStrSize);
|
|
showJSONStr=realloc(showJSONStr, showJSONStrSize+extrasJSONStrSize);
|
|
if (showJSONStr==NULL) {
|
|
fatalError_abort("findSeasons error", "could not realloc;\nError: %s;\n", strerror(errno));
|
|
}
|
|
showJSONStr[0]='\0';
|
|
snprintf(showJSONStr, showJSONStrSize+extrasJSONStrSize, "%s],\"Extras\":[%s]}", tempShowJSONStr, extrasJSONStr);
|
|
freeList(thisThread->list);
|
|
thisThread->list=newList();
|
|
addData(thisThread->list, showJSONStr);
|
|
addData(thisThread->list, tvShowName);
|
|
|
|
tryFree(threads);
|
|
tryFree(threadObj);
|
|
freeList(seasonsList);
|
|
tryFree(imgURL);
|
|
tryFree(showJSONStr);
|
|
tryFree(tvShowName);
|
|
tryFree(extrasJSONStr);
|
|
tryFree(tempShowJSONStr);
|
|
} else {
|
|
printError("findSeasons warning", false, HYEL, "please note, could not find any \".%s\" in path \"%s\"\n", videoExt, showPath);
|
|
}
|
|
} else {
|
|
printError("findSeasons warning", false, HYEL, "please note, path \"%s\" is empty!\n", showPath);
|
|
}
|
|
tryFree(showPath);
|
|
return NULL;
|
|
}
|
|
|
|
void *findEpisodes(void *threadArg) { // find files of 'this' season
|
|
threadStruct *thisThread = (threadStruct *) threadArg;
|
|
fileList *foundFiles=NULL;
|
|
ioMode mode=TV_MODE | FI_MODE;
|
|
if (strstr(thisThread->data[0], thisThread->conf->TVextraStr)!=NULL) {
|
|
mode=FI_MODE;
|
|
}
|
|
|
|
printInfo("findEpisodes info", true, "looking for episodes in: \"%s\";\n", thisThread->data[0]);
|
|
foundFiles=find(thisThread->conf, thisThread->data[0], videoExt, mode, false); // search for video files in this folder
|
|
if (foundFiles==NULL) {
|
|
thisThread->list=NULL;
|
|
} else {
|
|
size_t thisShowSeason=9999999; // "No season" as start value, because of sorting
|
|
|
|
if ((mode & TV_MODE)!=0) { // if mode has TV_MODE bit set then we are NOT in the folder of the extras
|
|
msortList(&foundFiles, 5, true, INTEGER); // sort list by data[5] ( episode number )
|
|
if (foundFiles->dataSize>4) { // getting season & not in Season.Extras
|
|
thisShowSeason=parseStrToInt(foundFiles->data[4]);
|
|
} else { // could not get current season from filename, trying by getting it from folder name
|
|
if (foundFiles->dataSize>1) {
|
|
// this only works if folder is named using the 'Something.1' format
|
|
char *tempStrPtr=strrchr(foundFiles->data[1], '.');
|
|
size_t tempStrPtrLen=strlen(tempStrPtr);
|
|
char *tempStr=NULL;
|
|
mallocMacro(tempStr, tempStrPtrLen, "findEpisodes error");
|
|
tempStr[0]='\0';
|
|
if (tempStrPtr[tempStrPtrLen-1]=='/') {
|
|
tempStrPtrLen--;
|
|
}
|
|
strlcpy(tempStr, tempStrPtr+1, tempStrPtrLen);
|
|
thisShowSeason=parseStrToInt(tempStr);
|
|
}
|
|
}
|
|
}
|
|
fileList *jsonObjList=newList();
|
|
|
|
unsigned int showId=thisThread->id;
|
|
size_t size=intSize(thisShowSeason)+1;
|
|
char *tempStr=NULL;
|
|
mallocMacro(tempStr, size, "findEpisodes error");
|
|
tempStr[0]='\0';
|
|
intToStr(tempStr, thisShowSeason);
|
|
addData(jsonObjList, tempStr);
|
|
|
|
for (fileList *temp=foundFiles; temp!=NULL; temp=temp->next) { //iterate through episodes
|
|
char *epNum=NULL, *seNum=NULL, *epName=NULL, *epSubs=NULL;
|
|
bool seasonExtra=false;
|
|
|
|
if (thisThread->conf->tvDB_exists && strstr(thisThread->conf->tvDB_str, temp->data[0])) {
|
|
if (thisThread->oldJSON!=NULL){
|
|
cJSON *JSONcopy=cJSON_Duplicate(thisThread->oldJSON, true);
|
|
cJSON *episodesArray=cJSON_GetObjectItem(JSONcopy, "episodes");
|
|
cJSON *item=NULL;
|
|
|
|
if (episodesArray!=NULL) {
|
|
cJSON_ArrayForEach(item, episodesArray) {
|
|
if (item!=NULL) {
|
|
cJSON *obj=cJSON_GetObjectItem(item, "File");
|
|
if (obj!=NULL) {
|
|
char *fileStr=cJSON_GetStringValue(obj);
|
|
if (fileStr!=NULL && strcmp(fileStr, temp->data[0])==0) { //match
|
|
item=cJSON_DetachItemViaPointer(episodesArray, item);
|
|
char *tempSeNum=cJSON_GetStringValue(cJSON_GetObjectItem(item, "Season"));
|
|
char *tempEpNum=cJSON_GetStringValue(cJSON_GetObjectItem(item, "Episode"));
|
|
char *tempEpName=cJSON_GetStringValue(cJSON_GetObjectItem(item, "Title"));
|
|
size_t tempSize=0;
|
|
|
|
tempSize=strlen(tempSeNum)+1;
|
|
if (tempSize>1) {
|
|
seNum=NULL;
|
|
mallocMacro(seNum, tempSize, "findEpisodes error");
|
|
strlcpy(seNum, tempSeNum, tempSize);
|
|
}
|
|
|
|
tempSize=strlen(tempEpNum)+1;
|
|
if (tempSize>1) {
|
|
epNum=NULL;
|
|
mallocMacro(epNum, tempSize, "findEpisodes error");
|
|
strlcpy(epNum, tempEpNum, tempSize);
|
|
}
|
|
tempSize=strlen(tempEpName)+1;
|
|
if (tempSize>1) {
|
|
epName=NULL;
|
|
mallocMacro(epName, tempSize, "findEpisodes error");
|
|
strlcpy(epName, tempEpName, tempSize);
|
|
}
|
|
cJSON_Delete(item);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
cJSON_Delete(JSONcopy);
|
|
}
|
|
//} else {
|
|
// printError("File \"%s\" found in tvDB_str but oldJSON==NULL\n", temp->data[0]);
|
|
}
|
|
}
|
|
|
|
if (temp->data!=NULL && strstr(temp->data[0], thisThread->conf->TVextraStr)!=NULL) {
|
|
seasonExtra=true;
|
|
epName=removeExtension(temp->data[2]); // episode name is filename without extension
|
|
} else { // get episodes' names
|
|
/* temp->data 'format'
|
|
* temp->data[0] full path to file ( ex: ../TV/Show/Season/Show.S01E01.TheOneThatIsAnExample.mp4 )
|
|
* temp->data[1] path to file's folder ( ex: ../TV/Show/Season/ )
|
|
* temp->data[2] filename ( ex: Show.S01E01.TheOneThatIsAnExample.mp4 )
|
|
now filename is split into regex groups... Default would be something like the following
|
|
* temp->data[3] Show
|
|
* temp->data[4] 01
|
|
* temp->data[5] 01
|
|
* temp->data[6] TheOneThatIsAnExample.mp4
|
|
*/
|
|
if (temp->dataSize > 5 ) { // use regexTVgroups instead of hard coded number? See temp->data 'format'
|
|
if (seNum==NULL) {
|
|
size_t tempStrLen=strlen(temp->data[4])+1;
|
|
seNum=NULL;
|
|
mallocMacro(seNum, tempStrLen, "findEpisodes error");
|
|
strlcpy(seNum, temp->data[4], tempStrLen);
|
|
}
|
|
|
|
if (epNum==NULL) {
|
|
size_t tempStrLen=strlen(temp->data[5])+1;
|
|
epNum=NULL;
|
|
mallocMacro(epNum, tempStrLen, "findEpisodes error");
|
|
strlcpy(epNum, temp->data[5], tempStrLen);
|
|
}
|
|
|
|
if (epNum!=NULL && seNum!=NULL && epName==NULL && thisThread->conf->getEpisodeName==true && showId!=0 ) {
|
|
epName=getEpisodeName(thisThread->conf, showId, seNum, epNum, thisThread->conf->TMDBapi);
|
|
}
|
|
} else { // dataSize got weird, shouldn't really happen?
|
|
if (temp->dataSize>0){
|
|
printError("findEpisodes warning", false, HYEL, "file \"%s\" has weird dataSize: %d;\n", temp->data[0], temp->dataSize);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (thisThread->conf->createTVsubs) { // search for subs, convert srt to vtt - no matter if already in DB or not
|
|
if (temp->dataSize>2) {
|
|
epSubs=getSubs(thisThread->conf, temp->data[2], thisThread->data[0]);
|
|
}
|
|
}
|
|
|
|
if (epName==NULL) {
|
|
if (temp->dataSize>5 && seasonExtra==false) {
|
|
if (strcmp(temp->data[6], videoExt)==0) {
|
|
epName=removeExtension(temp->data[2]);
|
|
} else {
|
|
epName=removeExtension(temp->data[6]);
|
|
}
|
|
} else {
|
|
epName=removeExtension(temp->data[2]);
|
|
}
|
|
}
|
|
if (epSubs==NULL) {
|
|
epSubs=NULL;
|
|
mallocMacro(epSubs, 1, "findEpisodes error");
|
|
epSubs[0]='\0';
|
|
}
|
|
if (seNum==NULL) {
|
|
seNum=NULL;
|
|
mallocMacro(seNum, 2, "findEpisodes error");
|
|
seNum[0]='0';
|
|
seNum[1]='\0';
|
|
}
|
|
if (epNum==NULL) {
|
|
epNum=NULL;
|
|
mallocMacro(epNum, 2, "findEpisodes error");
|
|
epNum[0]='0';
|
|
epNum[1]='\0';
|
|
}
|
|
|
|
char *epJSON=NULL;
|
|
if (seasonExtra) {
|
|
size_t epJSONStrSize=strlen("{\"Title\":\"\",\"File\":\"\",\"Subs\":[]}")+strlen(seNum)+strlen(epNum)+strlen(epName)+strlen(temp->data[0])+strlen(epSubs)+1;
|
|
epJSON=NULL;
|
|
mallocMacro(epJSON, epJSONStrSize, "findEpisodes error");
|
|
epJSON[0]='\0';
|
|
snprintf(epJSON, epJSONStrSize, "{\"Title\":\"%s\",\"File\":\"%s\",\"Subs\":[%s]}", epName, temp->data[0], epSubs);
|
|
addData(jsonObjList, epJSON);
|
|
} else if (temp->dataSize>0) {
|
|
size_t epJSONStrSize=strlen("{\"Season\":\"\",\"Episode\":\"\",\"Title\":\"\",\"File\":\"\",\"Subs\":[]}")+strlen(seNum)+strlen(epNum)+strlen(epName)+strlen(temp->data[0])+strlen(epSubs)+1;
|
|
epJSON=NULL;
|
|
mallocMacro(epJSON, epJSONStrSize, "findEpisodes error");
|
|
epJSON[0]='\0';
|
|
snprintf(epJSON, epJSONStrSize, "{\"Season\":\"%s\",\"Episode\":\"%s\",\"Title\":\"%s\",\"File\":\"%s\",\"Subs\":[%s]}", seNum, epNum, epName, temp->data[0], epSubs);
|
|
addData(jsonObjList, epJSON);
|
|
}
|
|
tryFree(epJSON);
|
|
tryFree(epSubs);
|
|
tryFree(epName);
|
|
tryFree(epNum);
|
|
tryFree(seNum);
|
|
}
|
|
tryFree(tempStr);
|
|
thisThread->list=jsonObjList;
|
|
}
|
|
freeList(foundFiles);
|
|
return NULL;
|
|
}
|
|
|
|
char *getShowPoster(progConfig *conf, unsigned int tmdb_id) {
|
|
char *imgURL=NULL;
|
|
size_t posterURLSize=strlen(tmdbSite)+strlen(tmdbTV)+intSize(tmdb_id)+strlen(tmdbP)+strlen(conf->TMDBapi)+strlen(tmdbP_Opts)+strlen(conf->prefImgLangTV)+2;
|
|
char *posterURL=NULL;
|
|
mallocMacro(posterURL, posterURLSize, "getShowPoster error");
|
|
posterURL[0]='\0';
|
|
snprintf(posterURL, posterURLSize, "%s%s%u%s%s%s,%s", tmdbSite, tmdbTV, tmdb_id, tmdbP, conf->TMDBapi, tmdbP_Opts, conf->prefImgLangTV);
|
|
if (posterURL!=NULL) {
|
|
imgURL=getPoster(posterURL, conf, conf->prefImgWidthTV, conf->prefImgRatioTV, conf->prefImgLangTV);
|
|
|
|
if (imgURL==NULL) {
|
|
printError("getShowPoster error", true, HRED, "failed while using URL '%s';\nRetrying without language option...\n", posterURL);
|
|
posterURL[0]='\0';
|
|
snprintf(posterURL, posterURLSize, "%s%s%u%s%s", tmdbSite, tmdbTV, tmdb_id, tmdbP, conf->TMDBapi);
|
|
imgURL=getPoster(posterURL, conf, conf->prefImgWidthTV, conf->prefImgRatioTV, NULL);
|
|
}
|
|
|
|
if (imgURL==NULL) {
|
|
printError("getShowPoster error", true, HRED, "failed while using URL '%s';\n", posterURL);
|
|
} else {
|
|
printInfo("getShowPoster info", true, "got poster for \"%d\", URL: \"%s\";\n", tmdb_id, imgURL);
|
|
if (imgURL!=NULL && conf->dTVImg) { // if image should actually be downloaded, otherwise will just link to imgURL
|
|
if (checkFolder(conf->dTVFolder, true)==0) {
|
|
size_t dlFileStrLen=strlen(imgURL)+strlen(conf->dTVFolder);
|
|
char *dlFileName=NULL;
|
|
mallocMacro(dlFileName, dlFileStrLen, "getShowPoster error");
|
|
dlFileName[0]='\0';
|
|
snprintf(dlFileName, dlFileStrLen, "%s%s", conf->dTVFolder, strrchr(imgURL, '/')+1);
|
|
|
|
if (dlFile(conf, imgURL, dlFileName)==CURLE_OK) { // downloaded poster!
|
|
imgURL=realloc(imgURL, dlFileStrLen+1);
|
|
if (imgURL==NULL)
|
|
fatalError_abort("getShowPoster error", "could not realloc;\nError: %s;\n", strerror(errno));
|
|
|
|
strlcpy(imgURL, dlFileName, dlFileStrLen);
|
|
if (conf->compressImgTV) {
|
|
imgURL=compressImg(conf->compressImgTVCmd, imgURL, true);
|
|
}
|
|
}
|
|
tryFree(dlFileName);
|
|
}
|
|
}
|
|
}
|
|
tryFree(posterURL);
|
|
} else {
|
|
printError("getShowPoster error", false, HRED, "could not build URL request string, something went wrong...\n");
|
|
}
|
|
return imgURL;
|
|
}
|
|
|
|
char *getEpisodeName(progConfig *conf, unsigned int showId, char *seNum, char *epNum, char *TMDBapi) {
|
|
char *epName=NULL;
|
|
char *season="/season/";
|
|
char *episode="/episode/";
|
|
char *apiOpts="?api_key=";
|
|
size_t tempStrSize=strlen(tmdbSite)+strlen(tmdbTV)+intSize(showId)+strlen(season)+strlen(seNum)+strlen(episode)+strlen(epNum)+strlen(apiOpts)+strlen(TMDBapi)+1;
|
|
char *tempStr=NULL;
|
|
mallocMacro(tempStr, tempStrSize, "getEpisodeName error");
|
|
tempStr[0]='\0';
|
|
snprintf(tempStr, tempStrSize, "%s%s%u%s%s%s%s%s%s", tmdbSite, tmdbTV, showId, season, seNum, episode, epNum, apiOpts, TMDBapi);
|
|
memBlock *mem=initBlock();
|
|
printInfo("getEpisodeName info", true, "finding episode name for show: \"%d\", season:\"%s\", episode: \"%s\", URL: \"%s\";\n", showId, seNum, epNum, tempStr);
|
|
getRequest(conf, tempStr, mem, curlMemCb);
|
|
|
|
cJSON *json_root=cJSON_Parse(mem->memory);
|
|
if (json_root!=NULL) {
|
|
cJSON *json_name=cJSON_DetachItemFromObject(json_root, "name");
|
|
if (json_name!=NULL){
|
|
char *tempEpName=cJSON_Print(json_name);
|
|
if (tempEpName!=NULL) {
|
|
// remove quotation marks at the beginning and end of string
|
|
size_t tempEpNameSize=strlen(tempEpName);
|
|
epName=NULL;
|
|
mallocMacro(epName, tempEpNameSize+1, "getEpisodeName error");
|
|
strlcpy(epName, tempEpName+1, tempEpNameSize-1);
|
|
}
|
|
tryFree(tempEpName);
|
|
} else {
|
|
if (cJSON_GetNumberValue(cJSON_GetObjectItem(json_root, "status_code"))!=34) {
|
|
printError("getEpisodeName warning", true, HYEL, " json_name==NULL - JSON received was:\n");
|
|
char *cJSONstr=cJSON_Print(json_root);
|
|
printError("", true, HBLU, cJSONstr);
|
|
printError("", true, HYEL, "\nrequest was: '%s%s%s';", HBLU, tempStr, HYEL);
|
|
printError("", true, HYEL, "\nEND;\n%s", COLOR_RESET);
|
|
tryFree(cJSONstr);
|
|
}
|
|
}
|
|
cJSON_Delete(json_name);
|
|
} else {
|
|
printError("getEpisodeName warning", true, HYEL, " json_root==NULL\n");
|
|
}
|
|
tryFree(tempStr);
|
|
cJSON_Delete(json_root);
|
|
freeBlock(mem);
|
|
char *fixedEpName=replaceAll(epName, "\\\"", "");
|
|
tryFree(epName);
|
|
return fixedEpName;
|
|
}
|
|
|
|
void createShowsHTML(progConfig *conf, fileList *list) {
|
|
printInfo("createShowsHTML info", true, "building HTML for TV shows...\n");
|
|
if (list==NULL || list->dataSize==0) {
|
|
fatalError_abort("createShowsHTML error", "list was NULL\n");
|
|
}
|
|
if (checkFolder(conf->TVhtml, true)==-1) {
|
|
fatalError_exit("createShowsHTML", "could not find \"%s\";\nExiting...\n", conf->TVhtml);
|
|
}
|
|
pthread_t *threads=NULL;
|
|
mallocMacro(threads, sizeof(pthread_t)*list->listSize, "createShowsHTML error");
|
|
threadStruct *threadObj=NULL;
|
|
mallocMacro(threadObj, sizeof(threadStruct)*list->listSize, "createShowsHTML error");
|
|
size_t i=0;
|
|
for (fileList *temp=list; temp!=NULL; temp=temp->next) {
|
|
threadObj[i].conf=conf;
|
|
threadObj[i].data=temp->data;
|
|
threadObj[i].oldJSON=NULL;
|
|
threadObj[i].list=newList();
|
|
threadObj[i].id=i;
|
|
|
|
pthread_create(&threads[i], NULL, showHTML, (void *) &threadObj[i]);
|
|
i++;
|
|
}
|
|
|
|
i=0;
|
|
fileList *htmlList=newList();
|
|
addData(htmlList, TV_HTML_TOP);
|
|
|
|
char *htmlStr=NULL;
|
|
for (fileList *temp=list; temp!=NULL; temp=temp->next) {
|
|
pthread_join(threads[i], NULL);
|
|
char *showFile=NULL;
|
|
char *showPoster=NULL;
|
|
if (checkFolder(threadObj[i].list->data[0], false)==0) {
|
|
showFile=getRelativePath(conf->TVhtml, threadObj[i].list->data[0]);
|
|
} else {
|
|
fatalError_exit("createShowsHTML", "could not find \"%s\";\nExiting...\n", threadObj[i].list->data[0]);
|
|
}
|
|
|
|
if (checkFolder(threadObj[i].list->data[1], false)==0) {
|
|
showPoster=getRelativePath(conf->TVhtml, threadObj[i].list->data[1]);
|
|
} else {
|
|
fatalError_exit("createShowsHTML", "could not find \"%s\";\nExiting...\n", threadObj[i].list->data[1]);
|
|
}
|
|
|
|
if (showPoster==NULL) {
|
|
showPoster=NULL;
|
|
mallocMacro(showPoster, 1, "createShowsHTML error");
|
|
showPoster[0]='\0';
|
|
}
|
|
char *showName=threadObj[i].list->data[2];
|
|
|
|
size_t htmlStrSize=strlen(TV_HTML_FRAME)+strlen(showFile)+strlen(showPoster)+strlen(showName)*2+intSize(i)+1;
|
|
htmlStr=realloc(htmlStr, htmlStrSize);
|
|
if (htmlStr==NULL) {
|
|
fatalError_abort("createShowsHTML error", "could not realloc;\nError: %s;\n", strerror(errno));
|
|
}
|
|
snprintf(htmlStr, htmlStrSize, TV_HTML_FRAME, i, showName, showFile, showPoster, showName, i, i, i);
|
|
|
|
addData(htmlList, htmlStr);
|
|
freeList(threadObj[i].list);
|
|
tryFree(showFile);
|
|
tryFree(showPoster);
|
|
i++;
|
|
}
|
|
addData(htmlList, TV_HTML_BOT);
|
|
fileListToFile(htmlList, conf->TVhtml, "", "");
|
|
|
|
tryFree(threadObj);
|
|
tryFree(threads);
|
|
tryFree(htmlStr);
|
|
freeList(htmlList);
|
|
}
|
|
|
|
void *showHTML(void *threadArg) {
|
|
threadStruct *thisThread=threadArg;
|
|
fileList *this_show=newList();
|
|
cJSON *myJSON=cJSON_Parse(thisThread->data[0]);
|
|
if (myJSON==NULL) {
|
|
printError("showHTML warning", false, HYEL, " myJSON was NULL!\tThis show's JSON is unparsable!\nJSON dump:\n%s\n", thisThread->data[0]);
|
|
return NULL;
|
|
}
|
|
cJSON *showObj=cJSON_GetObjectItem(myJSON, "Show");
|
|
cJSON *posObj=cJSON_GetObjectItem(myJSON, "Poster");
|
|
char *showPoster=NULL;
|
|
char *showName=NULL;
|
|
if (posObj!=NULL && cJSON_GetStringValue(posObj)!=NULL) {
|
|
showPoster=cJSON_GetStringValue(posObj);
|
|
}
|
|
if (showObj!=NULL && cJSON_GetStringValue(showObj)!=NULL) {
|
|
showName=cJSON_GetStringValue(showObj);
|
|
}
|
|
if (showPoster==NULL) {
|
|
showPoster=genImage(thisThread->conf->AutogenImgResizeTVCmd, thisThread->conf->dTVFolder, showName);
|
|
/*
|
|
// useless on genImage? compressed results bigger than original
|
|
if (thisThread->conf->compressImgTV) {
|
|
showPoster=compressImg(thisThread->conf->compressImgTVCmd, showPoster, true);
|
|
}
|
|
*/
|
|
}
|
|
if (showName==NULL) {
|
|
fatalError_abort("showHTML error", "showName==NULL; JSON was:\n%s\n--- END ---\n", cJSON_Print(myJSON));
|
|
}
|
|
|
|
int uuid=thisThread->id;
|
|
cJSON *episodesArray=cJSON_GetObjectItem(myJSON, "Episodes");
|
|
cJSON *extrasArray=cJSON_GetObjectItem(myJSON, "Extras");
|
|
if (episodesArray==NULL || extrasArray==NULL) {
|
|
fatalError_abort("showHTML error", " episodesArray or extrasArray were equal to NULL; JSON was:\n%s\n--- END ---\n ", cJSON_Print(myJSON));
|
|
}
|
|
printInfo("showHTML info", true, "building HTML for \"%s\";\n", showName);
|
|
cJSON *episode=NULL;
|
|
|
|
addData(this_show, SHOW_HTML_TOP);
|
|
int currSeason=0;
|
|
int uuidEpisode=0;
|
|
size_t tempStrSize=strlen(SHOW_HTML_SEL)+intSize(uuid)+1; //'<select>' HTML size+uuid size+NULL
|
|
char *tempStr=NULL;
|
|
mallocMacro(tempStr, tempStrSize, "showHTML error");
|
|
tempStr[0]='\0';
|
|
snprintf(tempStr, tempStrSize, SHOW_HTML_SEL, uuid);
|
|
addData(this_show, tempStr);
|
|
|
|
cJSON_ArrayForEach(episode, episodesArray) {
|
|
int this_seasonNum=0;
|
|
cJSON *jsonSeason=cJSON_GetObjectItem(episode, "Season");
|
|
if (jsonSeason!=NULL) {
|
|
this_seasonNum=parseStrToInt(cJSON_GetStringValue(jsonSeason));
|
|
}
|
|
if (this_seasonNum>currSeason) {
|
|
currSeason=this_seasonNum;
|
|
tempStrSize=strlen(SHOW_HTML_OPT_SEASON)+intSize(currSeason)+intSize(currSeason)+1;
|
|
tempStr=realloc(tempStr, tempStrSize);
|
|
if (tempStr==NULL) {
|
|
fatalError_abort("showHTML error", "could not realloc;\nError: %s;\n", strerror(errno));
|
|
}
|
|
snprintf(tempStr, tempStrSize, SHOW_HTML_OPT_SEASON, currSeason, currSeason);
|
|
addData(this_show, tempStr);
|
|
}
|
|
}
|
|
if (extrasArray!=NULL && cJSON_GetArraySize(extrasArray)>0) {
|
|
currSeason++;
|
|
tempStrSize=strlen(SHOW_HTML_OPT_EXTRAS)+intSize(currSeason)+1;
|
|
tempStr=realloc(tempStr, tempStrSize);
|
|
if (tempStr==NULL) {
|
|
fatalError_abort("showHTML error", "could not realloc;\nError: %s;\n", strerror(errno));
|
|
}
|
|
snprintf(tempStr, tempStrSize, SHOW_HTML_OPT_EXTRAS, currSeason);
|
|
addData(this_show, tempStr);
|
|
}
|
|
addData(this_show, "\n</select>");
|
|
currSeason=0;
|
|
|
|
cJSON_ArrayForEach(episode, episodesArray) {
|
|
episodeHTML(this_show, thisThread->conf, episode, &currSeason, &uuid, &uuidEpisode);
|
|
}
|
|
addData(this_show, "\n</ul>");
|
|
|
|
if (extrasArray!=NULL && cJSON_GetArraySize(extrasArray)>0) {
|
|
currSeason++;
|
|
tempStrSize=intSize(uuid)+intSize(currSeason)+strlen(SHOW_HTML_UL)+1;
|
|
tempStr=realloc(tempStr, tempStrSize);
|
|
if (tempStr==NULL)
|
|
fatalError_abort("showHTML error", "could not realloc;\nError: %s;\n", strerror(errno));
|
|
|
|
snprintf(tempStr, tempStrSize, SHOW_HTML_UL, uuid, currSeason);
|
|
addData(this_show, tempStr);
|
|
|
|
cJSON *extra=NULL;
|
|
cJSON_ArrayForEach(extra, extrasArray) {
|
|
episodeHTML(this_show, thisThread->conf, extra, &currSeason, &uuid, &uuidEpisode);
|
|
}
|
|
addData(this_show, "\n</ul>");
|
|
}
|
|
|
|
tempStrSize=intSize(uuid)+strlen(SHOW_HTML_BOT)+1;
|
|
tempStr=realloc(tempStr, tempStrSize);
|
|
if (tempStr==NULL)
|
|
fatalError_abort("showHTML error", "could not realloc;\nError: %s;\n", strerror(errno));
|
|
|
|
snprintf(tempStr, tempStrSize, SHOW_HTML_BOT, uuid);
|
|
addData(this_show, tempStr);
|
|
|
|
char *fileName=replaceAll(showName, " ", "");
|
|
tempStrSize=strlen(fileName)+strlen(thisThread->conf->showHTMLFolder)+16;
|
|
tempStr=realloc(tempStr, tempStrSize);
|
|
if (tempStr==NULL) {
|
|
fatalError_abort("showHTML error", "could not realloc;\nError: %s;\n", strerror(errno));
|
|
}
|
|
if (thisThread->conf->showHTMLFolder[strlen(thisThread->conf->showHTMLFolder)-1]=='/') {
|
|
snprintf(tempStr, tempStrSize, "%sTV%s.html", thisThread->conf->showHTMLFolder, fileName);
|
|
} else {
|
|
snprintf(tempStr, tempStrSize, "%s/TV%s.html", thisThread->conf->showHTMLFolder, fileName);
|
|
}
|
|
|
|
if (checkFolder(thisThread->conf->showHTMLFolder, true)==0) {
|
|
fileListToFile(this_show, tempStr, NULL, NULL);
|
|
|
|
addData(thisThread->list, tempStr);
|
|
addData(thisThread->list, showPoster);
|
|
addData(thisThread->list, fileName);
|
|
}
|
|
if (posObj==NULL || cJSON_GetStringValue(posObj)==NULL) {
|
|
tryFree(showPoster);
|
|
}
|
|
|
|
tryFree(fileName);
|
|
tryFree(tempStr);
|
|
cJSON_Delete(myJSON);
|
|
freeList(this_show);
|
|
return NULL;
|
|
}
|
|
|
|
void episodeHTML(fileList *this_show, progConfig *conf, cJSON *episode, int *currSeason, int *uuid, int *uuidEpisode) {
|
|
int this_seasonNum=0;
|
|
cJSON *jsonSeason=cJSON_GetObjectItem(episode, "Season");
|
|
if (jsonSeason!=NULL) {
|
|
this_seasonNum=parseStrToInt(cJSON_GetStringValue(jsonSeason));
|
|
}
|
|
char *this_episodeName=cJSON_GetStringValue(cJSON_GetObjectItem(episode, "Title"));
|
|
char *this_file=getRelativePath(conf->TVhtml, cJSON_GetStringValue(cJSON_GetObjectItem(episode, "File")));
|
|
cJSON *this_subs=cJSON_GetObjectItem(episode, "Subs");
|
|
size_t tempStrSize=0;
|
|
char *tempStr=NULL;
|
|
|
|
if (this_seasonNum>*currSeason) {
|
|
if (*currSeason>0) { // new season, so close prev season list
|
|
addData(this_show, "\n</ul>\n");
|
|
}
|
|
(*currSeason)=this_seasonNum;
|
|
tempStrSize=intSize(*uuid)+intSize(*currSeason)+strlen(SHOW_HTML_UL)+1;
|
|
tempStr=realloc(tempStr, tempStrSize);
|
|
if (tempStr==NULL) {
|
|
fatalError_abort("episodeHTML error", "could not realloc;\nError: %s;\n", strerror(errno));
|
|
}
|
|
snprintf(tempStr, tempStrSize, SHOW_HTML_UL, *uuid, *currSeason);
|
|
addData(this_show, tempStr);
|
|
}
|
|
|
|
tempStrSize=intSize(*uuid)+intSize(*uuidEpisode)+strlen(this_episodeName)+strlen(SHOW_HTML_LI)+1;
|
|
tempStr=realloc(tempStr, tempStrSize);
|
|
if (tempStr==NULL) {
|
|
fatalError_abort("episodeHTML error", "could not realloc;\nError: %s;\n", strerror(errno));
|
|
}
|
|
snprintf(tempStr, tempStrSize, SHOW_HTML_LI, *uuid, *uuidEpisode, this_episodeName);
|
|
addData(this_show, tempStr);
|
|
|
|
tempStrSize=intSize(*uuid)+intSize(*uuidEpisode)+strlen(SHOW_HTML_DIV)+1;
|
|
tempStr=realloc(tempStr, tempStrSize);
|
|
if (tempStr==NULL) {
|
|
fatalError_abort("episodeHTML error", "could not realloc;\nError: %s;\n", strerror(errno));
|
|
}
|
|
snprintf(tempStr, tempStrSize, SHOW_HTML_DIV, *uuid, *uuidEpisode);
|
|
addData(this_show, tempStr);
|
|
|
|
tempStrSize=strlen(this_episodeName)+strlen(SHOW_HTML_SPAN)+1;
|
|
tempStr=realloc(tempStr, tempStrSize);
|
|
if (tempStr==NULL) {
|
|
fatalError_abort("episodeHTML error", "could not realloc;\nError: %s;\n", strerror(errno));
|
|
}
|
|
snprintf(tempStr, tempStrSize, SHOW_HTML_SPAN, this_episodeName);
|
|
addData(this_show, tempStr);
|
|
|
|
tempStrSize=intSize(*uuid)+intSize(*uuidEpisode)+strlen(this_file)+strlen(SHOW_HTML_VIDEO)+1;
|
|
tempStr=realloc(tempStr, tempStrSize);
|
|
if (tempStr==NULL) {
|
|
fatalError_abort("episodeHTML error", "could not realloc;\nError: %s;\n", strerror(errno));
|
|
}
|
|
snprintf(tempStr, tempStrSize, SHOW_HTML_VIDEO, *uuid, *uuidEpisode, this_file);
|
|
addData(this_show, tempStr);
|
|
|
|
cJSON *currSub=NULL;
|
|
cJSON_ArrayForEach(currSub, this_subs) {
|
|
char *subLang=cJSON_GetStringValue(cJSON_GetObjectItem(currSub, "lang"));
|
|
char *subPath=getRelativePath(conf->TVhtml, cJSON_GetStringValue(cJSON_GetObjectItem(currSub, "subFile")));
|
|
if (subLang!=NULL && subPath!=NULL) {
|
|
tempStrSize=strlen(SHOW_HTML_SUBS)+strlen(subLang)+strlen(subPath)+1;
|
|
tempStr=realloc(tempStr, tempStrSize);
|
|
if (tempStr==NULL) {
|
|
fatalError_abort("episodeHTML error", "could not realloc;\nError: %s;\n", strerror(errno));
|
|
}
|
|
snprintf(tempStr, tempStrSize, SHOW_HTML_SUBS, subPath, subLang);
|
|
addData(this_show, tempStr);
|
|
}
|
|
tryFree(subPath);
|
|
}
|
|
addData(this_show, SHOW_HTML_CMD);
|
|
(*uuidEpisode)++;
|
|
tryFree(tempStr);
|
|
tryFree(this_file);
|
|
}
|
|
|
|
void *cleanTV(void *threadArg) {
|
|
threadStruct *thisThread=threadArg;
|
|
progConfig *conf=thisThread->conf;
|
|
|
|
if (conf->tvDB_exists==false || conf->JSON_tvDB==NULL) {
|
|
printError("cleanTV warning", false, HYEL, "no TV database to clean!\n");
|
|
} else {
|
|
printInfo("cleanTV info", false, "cleaning \"%s\"...\n", conf->dbNameTV);
|
|
cJSON *tempJSON=cJSON_Duplicate(conf->JSON_tvDB, true);
|
|
int jsonArrSize=cJSON_GetArraySize(tempJSON);
|
|
pthread_t *threads=NULL;
|
|
mallocMacro(threads, sizeof(pthread_t)*jsonArrSize, "cleanTV error");
|
|
threadStruct *threadObj=NULL;
|
|
mallocMacro(threadObj, sizeof(threadStruct)*jsonArrSize, "cleanTV error");
|
|
cJSON *show=NULL;
|
|
|
|
int i=0;
|
|
cJSON_ArrayForEach(show, tempJSON) {
|
|
threadObj[i].conf=conf;
|
|
threadObj[i].oldJSON=cJSON_Duplicate(show, true);
|
|
|
|
pthread_create(&threads[i], NULL, cleanShow, (void *) &threadObj[i]);
|
|
i++;
|
|
}
|
|
cJSON_Delete(tempJSON);
|
|
int numThreads=i;
|
|
cJSON *newJSON=cJSON_CreateArray();
|
|
for (i=0; i<numThreads; i++) {
|
|
pthread_join(threads[i], NULL);
|
|
cJSON_AddItemToArray(newJSON, threadObj[i].oldJSON);
|
|
}
|
|
thisThread->oldJSON=cJSON_Duplicate(newJSON, true);
|
|
cJSON_Delete(newJSON);
|
|
tryFree(threads);
|
|
tryFree(threadObj);
|
|
return NULL;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void *cleanShow(void *threadArg) {
|
|
threadStruct *thisThread=threadArg;
|
|
cJSON *show=thisThread->oldJSON;
|
|
|
|
if (show!=NULL && cJSON_GetObjectItem(show, "Episodes")!=NULL) {
|
|
cJSON *episodesArray=cJSON_Duplicate(cJSON_GetObjectItem(show, "Episodes"), true);
|
|
cJSON *episode=NULL;
|
|
int i=0, numDeleted=0;
|
|
cJSON_ArrayForEach(episode, episodesArray) {
|
|
if (episode!=NULL && cJSON_GetObjectItem(episode, "File")!=NULL) {
|
|
char *tempStr=cJSON_GetStringValue(cJSON_GetObjectItem(episode, "File"));
|
|
if (tempStr!=NULL) {
|
|
if (access(tempStr, F_OK)==0) {
|
|
cJSON *subsArray=cJSON_Duplicate(cJSON_GetObjectItem(episode, "Subs"), true);
|
|
int j=0, subsDeleted=0;
|
|
cJSON *sub=NULL;
|
|
cJSON_ArrayForEach(sub, subsArray) {
|
|
char *tempSubStr=cJSON_GetStringValue(cJSON_GetObjectItem(sub, "subFile"));
|
|
if (tempSubStr!=NULL) {
|
|
if (access(tempSubStr, F_OK)!=0) {
|
|
cJSON *tempSubs=cJSON_GetObjectItem(cJSON_GetArrayItem(cJSON_GetObjectItem(show, "Episodes"), i-numDeleted), "Subs");
|
|
cJSON_DeleteItemFromArray(tempSubs, j-subsDeleted);
|
|
subsDeleted++;
|
|
}
|
|
}
|
|
j++;
|
|
}
|
|
cJSON_Delete(subsArray);
|
|
} else {
|
|
cJSON_DeleteItemFromArray(cJSON_GetObjectItem(show, "Episodes"), i-numDeleted);
|
|
numDeleted++;
|
|
}
|
|
}
|
|
}
|
|
i++;
|
|
}
|
|
cJSON_Delete(episodesArray);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
int getShowID(progConfig *conf, char *tvShowName) {
|
|
int tmdbID=0;
|
|
if (conf->getTVposter || conf->getEpisodeName) { // if poster needed -> find out tmdb_id
|
|
CURL *curl=curl_easy_init();
|
|
|
|
char *escapedTVShowName=curl_easy_escape(curl, tvShowName, 0);
|
|
char *apiOpts="&api_key=";
|
|
size_t tempURLStrSize=strlen(tmdbTV_ID)+strlen(escapedTVShowName)+strlen(apiOpts)+strlen(conf->TMDBapi)+1;
|
|
char *tempURLStr=NULL;
|
|
mallocMacro(tempURLStr, tempURLStrSize, "getShowID error");
|
|
tempURLStr[0]='\0';
|
|
snprintf(tempURLStr, tempURLStrSize, "%s%s%s%s", tmdbTV_ID, escapedTVShowName, apiOpts, conf->TMDBapi);
|
|
printInfo("getShowID info", true, "Searching for TMDB ID for \"%s\", URL: \"%s\";\n", tvShowName, tempURLStr);
|
|
tmdbID=getTmdbID(tempURLStr, conf);
|
|
if (tmdbID==0) {
|
|
printError("getShowID warning", false, HYEL, "beware, could not find any ID for \"%s\";\n", tvShowName);
|
|
tmdbID=-1;
|
|
}
|
|
curl_free(escapedTVShowName);
|
|
curl_easy_cleanup(curl);
|
|
}
|
|
return tmdbID;
|
|
}
|
|
|