#include #include #include #include #include #include #include #define CACHE "/mod/var/tvdb" #define SERIESDB CACHE "/series.db" #define EXEC(xx) if (sqlite3_exec(db, xx, NULL, NULL, &error) != SQLITE_OK) \ do { \ printf("Failed: %s - %s (%s)\n", xx, error, sqlite3_errmsg(db)); \ sqlite3_free(error); \ exit(0); \ } while (0) struct series { unsigned long id; char *imdb; char *name; char *overview; char *banner; }; struct episode { unsigned long id; char *name; char *overview; unsigned long series; unsigned long episode; }; #define HANDLE(str, c, n) \ do { \ if (!memcmp(p, str, (n + 1))) \ { \ *p = c; \ memmove(p + 1, p + (n + 1), l - (p - txt) - (n + 1)); \ l -= n; \ txt[l] = '\0'; \ } \ } while (0) void unescape(char *txt) { char *p = txt; int l = strlen(txt); while ((p = strchr(p, '&'))) { HANDLE(""", '"', 5); HANDLE("&", '&', 4); p++; } p = txt; while ((p = memchr(p, '\xe2', l - (p - txt)))) { HANDLE("\xe2\x80\x99", '\'', 2); HANDLE("\xe2\x80\x93", '-', 2); HANDLE("\xe2\x80\x9c", '"', 2); HANDLE("\xe2\x80\x9d", '"', 2); p++; } if ((p = strpbrk(txt, "\n\r"))) *p = '\0'; } int main(int argc, char **argv) { char buf[0x1000], *p, *q; struct series s; struct episode e; char *error; sqlite3_stmt *stmt; sqlite3 *db; FILE *fp; int epcnt = 0; if (argc != 2) { printf("Syntax: %s \n", argv[0]); return 0; } if (!(fp = fopen(argv[1], "r"))) { perror("open"); return 0; } sqlite3_config(SQLITE_CONFIG_SINGLETHREAD); if (sqlite3_open_v2(SERIESDB, &db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL) != SQLITE_OK) { printf("Failed to open series database: %s\n", sqlite3_errmsg(db)); return 0; } EXEC("pragma journal_mode = off"); EXEC("pragma synchronous = off"); EXEC( "create table if not exists series(" "[series_id] integer primary key, " "[imdb_id] text, " "[name] text, " "[overview] text, " "[banner] text, " "[dat] text" ")" ); if (sqlite3_prepare_v2(db, "insert or replace into series " "values(?,?,?,?,?,date('now'))", -1, &stmt, NULL) != SQLITE_OK) { fprintf(stderr, "Problem preparing series statement %s", sqlite3_errmsg(db)); exit(1); } while (fgets(buf, sizeof(buf), fp)) { p = buf; while ((*p++) != '<') ; if (!strncmp(p, "Series>", 7)) { memset(&s, '\0', sizeof(s)); continue; } if (!strncmp(p, "id>", 3)) { s.id = strtoul(p + 3, (char **)NULL, 10); continue; } if (!strncmp(p, "IMDB_ID>", 8)) { s.imdb = strdup(p + 8); if ((q = strstr(s.imdb, ""))) *q = '\0'; continue; } if (!strncmp(p, "SeriesName>", 11)) { s.name = strdup(p + 11); if ((q = strstr(s.name, ""))) *q = '\0'; unescape(s.name); continue; } if (!strncmp(p, "Overview>", 9)) { s.overview = strdup(p + 9); if ((q = strstr(s.overview, ""))) *q = '\0'; unescape(s.overview); } if (!strncmp(p, "banner>", 7)) { s.banner = strdup(p + 7); if ((q = strstr(s.banner, ""))) *q = '\0'; unescape(s.banner); } if (!strncmp(p, "/Series>", 7)) { if (s.id && s.name && s.overview) { sqlite3_bind_int(stmt, 1, s.id); sqlite3_bind_text(stmt, 2, s.imdb ? s.imdb : "", -1, NULL); sqlite3_bind_text(stmt, 3, s.name, -1, NULL); sqlite3_bind_text(stmt, 4, s.overview, -1, NULL); sqlite3_bind_text(stmt, 5, s.banner, -1, NULL); sqlite3_step(stmt); } break; } } sqlite3_finalize(stmt); if (!s.id) { printf("No series found.\n"); return 0; } /* Attach the Episode database for this series. */ sprintf(buf, "attach '%s/%lu.db' as episode", CACHE, s.id); EXEC(buf); EXEC( "create table if not exists episode.episode(" "[episode_id] integer primary key, " "[series] integer, " "[episode] integer, " "[name] text, " "[overview] text" ")" ); if (sqlite3_prepare_v2(db, "insert or replace into episode.episode " "values(?,?,?,?,?)", -1, &stmt, NULL) != SQLITE_OK) { fprintf(stderr, "Problem preparing statement %s", sqlite3_errmsg(db)); exit(1); } while (fgets(buf, sizeof(buf), fp)) { p = buf; while ((*p++) != '<') ; if (!strncmp(p, "Episode>", 8)) { /* New episode */ memset(&e, '\0', sizeof(e)); } if (!strncmp(p, "id>", 3)) e.id = strtoul(p + 3, (char **)NULL, 10); if (!strncmp(p, "Combined_episodenumber>", 23)) e.episode = strtoul(p + 23, (char **)NULL, 10); if (!strncmp(p, "Combined_season>", 16)) e.series = strtoul(p + 16, (char **)NULL, 10); if (!strncmp(p, "EpisodeName>", 12)) { e.name = strdup(p + 12); if ((q = strstr(e.name, ""))) *q = '\0'; unescape(e.name); } if (!strncmp(p, "Overview>", 9)) { e.overview = strdup(p + 9); if ((q = strstr(e.overview, ""))) *q = '\0'; unescape(e.overview); } if (!strncmp(p, "/Episode>", 8)) { /* End of episode */ if (e.id && e.name && e.overview) { epcnt++; sqlite3_bind_int(stmt, 1, e.id); sqlite3_bind_int(stmt, 2, e.series); sqlite3_bind_int(stmt, 3, e.episode); sqlite3_bind_text(stmt, 4, e.name, -1, NULL); sqlite3_bind_text(stmt, 5, e.overview, -1, NULL); sqlite3_step(stmt); sqlite3_reset(stmt); sqlite3_clear_bindings(stmt); } if (e.name) free(e.name); if (e.overview) free(e.overview); memset(&e, '\0', sizeof(e)); } } fclose(fp); sqlite3_finalize(stmt); sqlite3_close(db); /*printf("Episodes: %d\n", epcnt);*/ return 0; }