Nimbin2git.christianimmanuel.de / Games / dvd / main.c

dvd files

last change 2026-09-04 (2 hours ago)

wget https://git.christianimmanuel.de/games/dvd/archive/dvd.tar.gz
main.c 49.4 KB · 1364 lines raw
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "imdb_search.h"
#include "upcitemdb.h"


// ANSI color codes
#define RESET   "\033[0m"
#define RED     "\033[31m"
#define GREEN   "\033[32m"
#define YELLOW  "\033[33m"
#define BLUE    "\033[34m"
#define MAGENTA "\033[35m"
#define CYAN    "\033[36m"
#define WHITE   "\033[37m"

#define PRINT_HEADER(title)       \
    printf(MAGENTA "\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n" RESET); \
    printf(CYAN "      %s\n" RESET, title);   \
    printf(MAGENTA "┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅\n" RESET);

#define PRINT_HEADER_SMALL(title)       \
    printf(MAGENTA "\n–––––––––––––––––––––––––––––––––––––––––\n" RESET); \
    printf(CYAN "      %s\n" RESET, title);   \



#define DATABASE_FILE "selected_results.db"


typedef struct {
    SearchResult result;
    Websearch_st web_data;
    char file_path[256];
    char search_query[256];
    char barcode[14];
} DataStruct;


void clearInputBuffer() {
    fseek(stdin,0,SEEK_END);
    fflush(stdout);
}

void append_to_database(const char *entry) {
    FILE *db_file = fopen(DATABASE_FILE, "a");
    if (db_file == NULL) {
        fprintf(stderr, "Failed to open database file for writing.\n");
        return;
    }
    fprintf(db_file, "%s\n", entry);
    fclose(db_file);
}


// Helper function to check if a string consists of only digits
int is_numeric(const char *str) {
    if (str == NULL) {
        return 0;
    }
    for (int i = 0; str[i] != '\0'; i++) {
        if (!isdigit((unsigned char)str[i])) {
            return 0; // Return false if a non-digit character is found
        }
    }
    return 1; // Return true if all characters are digits
}

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>

// Ensure directory exists
void ensure_directory_exists(const char *dir) {
    struct stat st = {0};
    if (stat(dir, &st) == -1) {
        mkdir(dir, 0700);
    }
}



// Function implementations
DataStruct createDataStruct(SearchResult *result, Websearch_st *web_data, char search_query[256], char barcode[14]) {
    barcode[13] = '\0';
    DataStruct data;
    snprintf(data.file_path, sizeof(data.file_path), "local/%s.txt", result->tconst);
    data.result = *result;
    data.web_data = *web_data;
    strncpy(data.search_query, search_query, sizeof(data.search_query) - 1);
    strncpy(data.barcode, barcode, 13);
    data.barcode[13] = '\0';
    return data;
}

void writeStructToFile(DataStruct *data) {
    char file_path[512];
    snprintf(file_path, sizeof(file_path), "local/%s.txt", data->result.tconst);
    ensure_directory_exists("local");

    FILE *file = fopen(file_path, "w");
    if (!file) {
        perror("Failed to open file for writing");
        return;
    }

    // Write SearchResult data
    fprintf(file, "tconst=%s\n", data->result.tconst);
    fprintf(file, "primaryTitle=%s\n", data->result.primaryTitle);
    fprintf(file, "selected=%s\n", data->result.selected);
    fprintf(file, "selected_id=%d\n", data->result.selected_id);
    fprintf(file, "score=%.2f\n", data->result.score);
    fprintf(file, "barcode=%s\n", data->barcode);
    fprintf(file, "searchQuery=%s\n", data->search_query);

    // Write associated TitleEntry data
    if (data->result.title) {
        TitleEntry *title = data->result.title;
        fprintf(file, "\n[TitleEntry]\n");
        fprintf(file, "tconst=%s\n", title->tconst);
        fprintf(file, "primaryTitle=%s\n", title->primaryTitle);
        fprintf(file, "originalTitle=%s\n", title->originalTitle);
        fprintf(file, "titleType=%s\n", title->titleType);
        fprintf(file, "startYear=%d\n", title->startYear);
        fprintf(file, "endYear=%d\n", title->endYear);
        fprintf(file, "isAdult=%d\n", title->isAdult);
        fprintf(file, "runtimeMinutesgenres=%s\n", title->runtimeMinutesgenres);

        if (title->ratingInfo) {
            fprintf(file, "\n[RatingInfo]\n");
            fprintf(file, "averageRating=%.1f\n", title->ratingInfo->averageRating);
            fprintf(file, "numVotes=%d\n", title->ratingInfo->numVotes);
        }
    }

    // Write Websearch_st data
    fprintf(file, "\n[WebSearch]\n");
    fprintf(file, "title=%s\n", data->web_data.title);
    fprintf(file, "lowestRecordedPrice=%.2f\n", data->web_data.lowest_recorded_price);
    fprintf(file, "highestRecordedPrice=%.2f\n", data->web_data.highest_recorded_price);
    fprintf(file, "category=%s\n", data->web_data.category);

    fclose(file);
    printf("\nSaved result to " WHITE "%s\n" RESET, file_path);
}
// Function to read data from a file and populate DataStruct
int readStructFromFile(const char *file_path, DataStruct *data) {
    FILE *file = fopen(file_path, "r");
    if (!file) {
        perror("Failed to open file for reading");
        return -1;  // Return -1 to indicate error
    }

    char line[512];
    TitleEntry *title = NULL;
    Websearch_st *web_data = NULL;

    while (fgets(line, sizeof(line), file)) {
        // Remove newline at the end of the line
        line[strcspn(line, "\n")] = '\0';

        // Read the SearchResult fields
        if (strncmp(line, "tconst=", 7) == 0) {
            strncpy(data->result.tconst, line + 7, sizeof(data->result.tconst) - 1);
        } else if (strncmp(line, "primaryTitle=", 13) == 0) {
            strncpy(data->result.primaryTitle, line + 13, sizeof(data->result.primaryTitle) - 1);
        } else if (strncmp(line, "selected=", 9) == 0) {
            strncpy(data->result.selected, line + 9, sizeof(data->result.selected) - 1);
        } else if (strncmp(line, "selected_id=", 12) == 0) {
            data->result.selected_id = atoi(line + 12);
        } else if (strncmp(line, "score=", 6) == 0) {
            data->result.score = atof(line + 6);
        } else if (strncmp(line, "barcode=", 8) == 0) {
            strncpy(data->barcode, line + 8, sizeof(data->barcode) - 1);
        } else if (strncmp(line, "searchQuery=", 12) == 0) {
            strncpy(data->search_query, line + 12, sizeof(data->search_query) - 1);
        }

        // Read the TitleEntry fields (if they exist)
        if (strncmp(line, "[TitleEntry]", 12) == 0) {
            title = malloc(sizeof(TitleEntry));  // Allocate memory for TitleEntry
            memset(title, 0, sizeof(TitleEntry));  // Initialize the TitleEntry struct

        } else if (title) {
            if (strncmp(line, "tconst=", 7) == 0) {
                strncpy(title->tconst, line + 7, sizeof(title->tconst) - 1);
            } else if (strncmp(line, "primaryTitle=", 13) == 0) {
                strncpy(title->primaryTitle, line + 13, sizeof(title->primaryTitle) - 1);
            } else if (strncmp(line, "originalTitle=", 14) == 0) {
                strncpy(title->originalTitle, line + 14, sizeof(title->originalTitle) - 1);
            } else if (strncmp(line, "titleType=", 10) == 0) {
                strncpy(title->titleType, line + 10, sizeof(title->titleType) - 1);
            } else if (strncmp(line, "startYear=", 10) == 0) {
                title->startYear = atoi(line + 10);
            } else if (strncmp(line, "endYear=", 8) == 0) {
                title->endYear = atoi(line + 8);
            } else if (strncmp(line, "isAdult=", 8) == 0) {
                title->isAdult = atoi(line + 8);
            } else if (strncmp(line, "runtimeMinutesgenres=", 21) == 0) {
                strncpy(title->runtimeMinutesgenres, line + 21, sizeof(title->runtimeMinutesgenres) - 1);
            } else if (strncmp(line, "[RatingInfo]", 12) == 0) {
                // Allocate memory for RatingInfo
                title->ratingInfo = malloc(sizeof(RatingInfo));
                memset(title->ratingInfo, 0, sizeof(RatingInfo));
            } else if (title->ratingInfo) {
                if (strncmp(line, "averageRating=", 14) == 0) {
                    title->ratingInfo->averageRating = atof(line + 14);
                } else if (strncmp(line, "numVotes=", 9) == 0) {
                    title->ratingInfo->numVotes = atoi(line + 9);
                }
            }
        }

        // Read the Websearch_st fields
        if (strncmp(line, "[WebSearch]", 11) == 0) {
            web_data = malloc(sizeof(Websearch_st));  // Allocate memory for Websearch_st
            memset(web_data, 0, sizeof(Websearch_st));  // Initialize the Websearch_st struct
        } else if (web_data) {
            if (strncmp(line, "title=", 6) == 0) {
                strncpy(web_data->title, line + 6, sizeof(web_data->title) - 1);
            } else if (strncmp(line, "lowestRecordedPrice=", 20) == 0) {
                web_data->lowest_recorded_price = atof(line + 20);
            } else if (strncmp(line, "highestRecordedPrice=", 21) == 0) {
                web_data->highest_recorded_price = atof(line + 21);
            } else if (strncmp(line, "category=", 9) == 0) {
                strncpy(web_data->category, line + 9, sizeof(web_data->category) - 1);
            }
        }
    }

    // Close the file
    fclose(file);

    // Assign the read values to the DataStruct object
    if (title) {
        data->result.title = title;  // Link the title data
    }
    if (web_data) {
        data->web_data = *web_data;  // Copy the web data into the struct
    }

    return 0;  // Return 0 to indicate success
}


void printDataStruct(DataStruct *data) {
    if (!data || !data->result.title || strlen(data->result.tconst) == 0 || strlen(data->result.primaryTitle) == 0){
        printf("No valid dvd found!\n");
        return;
    }
    printf(MAGENTA "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n");
    printf(MAGENTA "┃ " WHITE "%s\n" RESET, data->result.primaryTitle);
    if (strlen(data->result.selected) > 0 && data->result.title->languageCount > 0 && data->result.selected_id < data->result.title->languageCount)
        printf(MAGENTA "┃ " WHITE "%s: " WHITE "%s\n" RESET, data->result.selected, data->result.title->languages[data->result.selected_id].title);
    printf(MAGENTA "┠────────────────────────────────────────────\n" RESET);


    // Year, ID, Genres
    if (data->result.title) {
        printf(MAGENTA "┃  " YELLOW "Primary title: " WHITE "%s\n",
                data->result.title->primaryTitle);
        
        printf(MAGENTA "┃  " YELLOW "Type: " WHITE "%s" YELLOW ", Genre: " WHITE "%s\n",
            data->result.title->titleType,
            data->result.title->runtimeMinutesgenres);
        printf(MAGENTA "┃  " YELLOW "Year: " WHITE "%d-%d" YELLOW ", Adult: " WHITE "%d" YELLOW " Languages: %d\n",
            data->result.title->startYear, data->result.title->endYear,
            data->result.title->isAdult,
            data->result.title->languageCount);
    }


    // Type, Rank, Selected
    printf(MAGENTA "┃  " YELLOW "tconst: " WHITE "%s" CYAN ", Score: " WHITE "%.2f" YELLOW
           ", Selected: " WHITE "%s" YELLOW " –> " WHITE "%d\n" RESET,
           data->result.tconst,
           data->result.score,
           data->result.selected,
           data->result.selected_id);

    // Rating and Votes
    if (data->result.title && data->result.title->ratingInfo != NULL) {
        printf(MAGENTA "┃  " YELLOW "Rating: " CYAN "%.1f" YELLOW ", Votes: " WHITE "%d\n" RESET,
               data->result.title->ratingInfo->averageRating,
               data->result.title->ratingInfo->numVotes);
    }

    printf(MAGENTA "┠────────────────────────────────────────────\n" RESET);

    // Web Data
    printf(MAGENTA "┃  " CYAN "Web Search:\n" RESET);
    printf(MAGENTA "┃    " YELLOW "Title: " RESET "%s\n", data->web_data.title);
    printf(MAGENTA "┃    " YELLOW "Price: " RESET "%.2f-%.2f\n",
           data->web_data.lowest_recorded_price,
           data->web_data.highest_recorded_price);
    printf(MAGENTA "┃    " YELLOW "Category: " RESET "%s\n", data->web_data.category);

    printf(MAGENTA "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n" RESET);
}



#include <sys/stat.h> // For stat
#include <dirent.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

int loadLocalMovies(DataStruct **movies, const char *directory) {
    struct dirent *entry;
    DIR *dp = opendir(directory);
    if (!dp) {
        perror("Failed to open directory");
        return -1;
    }

    int count = 0;
    size_t capacity = 10; // Initial capacity for dynamic allocation
    *movies = malloc(capacity * sizeof(DataStruct));
    if (!*movies) {
        perror("Failed to allocate memory for movies array");
        closedir(dp);
        return -1;
    }

    while ((entry = readdir(dp)) != NULL) {
        // Skip "." and ".." entries
        if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
            continue;
        }

        char file_path[512];
        snprintf(file_path, sizeof(file_path), "%s/%s", directory, entry->d_name);

        // Use stat to determine if it is a regular file
        struct stat file_stat;
        if (stat(file_path, &file_stat) != 0) {
            perror("Failed to stat file");
            continue;
        }

        if (S_ISREG(file_stat.st_mode)) { // Regular file
            FILE *file = fopen(file_path, "r");
            if (!file) {
                perror("Failed to open file for reading");
                continue;
            }

            DataStruct data;
            memset(&data, 0, sizeof(DataStruct));

            // Parse the file contents into a DataStruct
            char line[512];
            TitleEntry *title = NULL;
            Websearch_st *web_data = NULL;

            while (fgets(line, sizeof(line), file)) {
                // Remove newline at the end of the line
                line[strcspn(line, "\n")] = '\0';

                // Read the SearchResult fields
                if (strncmp(line, "tconst=", 7) == 0) {
                    strncpy(data.result.tconst, line + 7, sizeof(data.result.tconst) - 1);
                } else if (strncmp(line, "primaryTitle=", 13) == 0) {
                    strncpy(data.result.primaryTitle, line + 13, sizeof(data.result.primaryTitle) - 1);
                } else if (strncmp(line, "selected=", 9) == 0) {
                    strncpy(data.result.selected, line + 9, sizeof(data.result.selected) - 1);
                } else if (strncmp(line, "selected_id=", 12) == 0) {
                    data.result.selected_id = atoi(line + 12);
                } else if (strncmp(line, "score=", 6) == 0) {
                    data.result.score = atof(line + 6);
                } else if (strncmp(line, "barcode=", 8) == 0) {
                    strncpy(data.barcode, line + 8, sizeof(data.barcode) - 1);
                } else if (strncmp(line, "searchQuery=", 12) == 0) {
                    strncpy(data.search_query, line + 12, sizeof(data.search_query) - 1);
                }

                // Handle TitleEntry section
                if (strncmp(line, "[TitleEntry]", 12) == 0) {
                    title = malloc(sizeof(TitleEntry));
                    memset(title, 0, sizeof(TitleEntry));
                } else if (title) {
                    if (strncmp(line, "tconst=", 7) == 0) {
                        strncpy(title->tconst, line + 7, sizeof(title->tconst) - 1);
                    } else if (strncmp(line, "primaryTitle=", 13) == 0) {
                        strncpy(title->primaryTitle, line + 13, sizeof(title->primaryTitle) - 1);
                    } else if (strncmp(line, "originalTitle=", 14) == 0) {
                        strncpy(title->originalTitle, line + 14, sizeof(title->originalTitle) - 1);
                    } else if (strncmp(line, "titleType=", 10) == 0) {
                        strncpy(title->titleType, line + 10, sizeof(title->titleType) - 1);
                    } else if (strncmp(line, "startYear=", 10) == 0) {
                        title->startYear = atoi(line + 10);
                    } else if (strncmp(line, "endYear=", 8) == 0) {
                        title->endYear = atoi(line + 8);
                    } else if (strncmp(line, "isAdult=", 8) == 0) {
                        title->isAdult = atoi(line + 8);
                    } else if (strncmp(line, "runtimeMinutesgenres=", 21) == 0) {
                        strncpy(title->runtimeMinutesgenres, line + 21, sizeof(title->runtimeMinutesgenres) - 1);
                    } else if (strncmp(line, "[RatingInfo]", 12) == 0) {
                        title->ratingInfo = malloc(sizeof(RatingInfo));
                        memset(title->ratingInfo, 0, sizeof(RatingInfo));
                    } else if (title->ratingInfo) {
                        if (strncmp(line, "averageRating=", 14) == 0) {
                            title->ratingInfo->averageRating = atof(line + 14);
                        } else if (strncmp(line, "numVotes=", 9) == 0) {
                            title->ratingInfo->numVotes = atoi(line + 9);
                        }
                    }
                }

                // Handle Websearch_st section
                if (strncmp(line, "[WebSearch]", 11) == 0) {
                    web_data = malloc(sizeof(Websearch_st));
                    memset(web_data, 0, sizeof(Websearch_st));
                } else if (web_data) {
                    if (strncmp(line, "title=", 6) == 0) {
                        strncpy(web_data->title, line + 6, sizeof(web_data->title) - 1);
                    } else if (strncmp(line, "lowestRecordedPrice=", 20) == 0) {
                        web_data->lowest_recorded_price = atof(line + 20);
                    } else if (strncmp(line, "highestRecordedPrice=", 21) == 0) {
                        web_data->highest_recorded_price = atof(line + 21);
                    } else if (strncmp(line, "category=", 9) == 0) {
                        strncpy(web_data->category, line + 9, sizeof(web_data->category) - 1);
                    }
                }
            }

            // Close the file
            fclose(file);

            // Link TitleEntry and Websearch_st to the main DataStruct
            if (title) {
                data.result.title = title;
            }
            if (web_data) {
                data.web_data = *web_data;
            }

            // Add DataStruct to the array
            if (count >= capacity) {
                capacity *= 2;
                DataStruct *new_movies = realloc(*movies, capacity * sizeof(DataStruct));
                if (!new_movies) {
                    perror("Failed to reallocate memory for movies array");
                    free(*movies);
                    closedir(dp);
                    return -1;
                }
                *movies = new_movies;
            }

            (*movies)[count++] = data;
        }
    }

    closedir(dp);
    return count;
}

///////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////


#include <stdio.h>
#include <stdlib.h>
#include <string.h>


#define FILENAME "playlists.txt"
#define MAX_ID_LENGTH 14
#define MAX_NAME_LENGTH 256
#define MAX_LINE 512


// Function to check if playlist ID exists
int isValidPlaylistID(const char *playlist_id) {
    FILE *file = fopen(FILENAME, "r");
    if (!file) {
        perror(RED "Error opening playlist file" RESET);
        return 0;  // File not found or cannot be opened
    }

    char line[MAX_LINE];
    while (fgets(line, sizeof(line), file)) {
        char id[14], name[257];  // Buffers for ID and name
        sscanf(line, "%13[^|]|%256[^\n]", id, name);  // Parse ID and name
        if (strcmp(id, playlist_id) == 0) {
            fclose(file);
            return 1;  // ID found in file
        }
    }

    fclose(file);
    return 0;  // ID not found in file
}

// Function to display all playlists
void list_playlists() {
    FILE *file = fopen(FILENAME, "r");
    if (!file) {
        perror(RED "Error opening file" RESET);
        return;
    }

    printf(GREEN "Playlists:\n" RESET);
    printf(BLUE "----------------------------------------\n" RESET);

    char line[MAX_LINE];
    int count = 0;
    while (fgets(line, sizeof(line), file)) {
        char id[MAX_ID_LENGTH], name[257];  // Increase ID buffer size
        if (sscanf(line, "%13[^|]|%256[^\n]", id, name) == 2) {  // Parse ID and name
            printf(CYAN "[%d] " RESET, ++count);
            printf(YELLOW "ID: " RESET "%s\n", id);
            printf(MAGENTA "    Name: " WHITE "%s\n" RESET, name);
            printf(BLUE "----------------------------------------\n" RESET);
        }
    }

    if (count == 0) {
        printf(RED "No playlists found.\n" RESET);
    }

    fclose(file);
}



// Function to add a playlist
void add_playlist(char id[14]) {
    printf("[q] quit\n");
    char name[MAX_NAME_LENGTH] = "\0";

    // Display existing playlists (placeholder)
    printf("Existing Playlists:\n");
    // list_playlists(); // Uncomment this if you have a function to list playlists

    list_playlists();
    // Input Playlist ID
    while (1) {
        printf("Enter new Playlist ID (up to 13 characters): ");
        fgets(id, 14, stdin);  // Read ID (13 + null terminator)
        id[strcspn(id, "\n")] = 0;  // Remove trailing newline

        if (strlen(id) == 0) {
            printf("Error: Playlist ID cannot be empty.\n");
            continue;
        }

        if (id[0] == 'q') return;  // User requested to quit

        if (!isValidPlaylistID(id)) {
            break;  // Valid ID, exit loop
        } else {
            printf("Error: Playlist ID '%s' already exists. Please enter a different ID.\n", id);
        }
    }

    // Input Playlist Name
    while (1) {
        printf("Enter Playlist Name (up to 256 characters): ");
        fgets(name, MAX_NAME_LENGTH, stdin);  // Read name
        name[strcspn(name, "\n")] = 0;  // Remove trailing newline

        if (strlen(name) == 0) {
            printf("Error: Playlist Name cannot be empty.\n");
            continue;
        }

        if (name[0] == 'q') return;  // User requested to quit

        break;  // Valid name, exit loop
    }

    // Write to File
    FILE *file = fopen(FILENAME, "a");  // Open file in append mode
    if (!file) {
        perror("Error opening file");
        return;
    }

    fprintf(file, "%s|%s\n", id, name);  // Write ID and name separated by '|'
    fclose(file);

    printf("Playlist '%s' added with ID '%s'.\n", name, id);

    list_playlists();
}

// Function to remove a playlist by ID
void remove_playlist() {
    char id[64];
    
    list_playlists(); 

    printf("Remove Playlist ID (up to 10 characters): ");
    fgets(id, sizeof(id), stdin);
    id[strcspn(id, "\n")] = 0;  // Remove trailing newline
    if (id[0] == 'q') return;


    FILE *file = fopen(FILENAME, "r");
    if (!file) {
        perror("Error opening file");
        return;
    }

    FILE *temp = fopen("temp.txt", "w");  // Temporary file for updated data
    if (!temp) {
        perror("Error creating temporary file");
        fclose(file);
        return;
    }

    char line[MAX_LINE];
    int found = 0;
    while (fgets(line, sizeof(line), file)) {
        char line_id[11];  // ID buffer (10 + null terminator)
        sscanf(line, "%10[^|]", line_id);  // Extract the ID before the '|'

        if (line_id[0] == 'q') return;
        if (strcmp(line_id, id) != 0) {
            fputs(line, temp);  // Copy line to temp if ID doesn't match
        } else {
            found = 1;
        }
    }

    fclose(file);
    fclose(temp);

    if (found) {
        remove(FILENAME);          // Delete the original file
        rename("temp.txt", FILENAME);  // Rename temp to original
        printf("Playlist with ID '%s' removed.\n", id);
    } else {
        remove("temp.txt");  // Cleanup temp if no match found
        printf("Playlist with ID '%s' not found.\n", id);
    }
}

void listMovies(DataStruct* movies, int count) {
    if (count > 0) {
        printf(GREEN "Loaded %d movies from the local directory:\n" RESET, count);
        for (int i = 0; i < count; i++) {
            printf(CYAN "[%d] " RESET, i + 1);
            printf(YELLOW "Title: " WHITE "%s\n" RESET, movies[i].result.primaryTitle);
            printf(MAGENTA "       ID: " RESET "%s\n", movies[i].result.tconst);
            printf(RED "----------------------------------------\n" RESET);
        }
    } else {
        printf(RED "No movies found in the local directory.\n" RESET);
    }
}

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h> // For unlink()

int removeMovie(DataStruct *movies, int *movie_count) {
    listMovies(movies, *movie_count);
    if (*movie_count <= 0) {
        printf("No movies available to remove.\n");
        return -1;
    }

    char tconst[256];
    printf("Enter the tconst of the movie to remove: ");
    if (!fgets(tconst, sizeof(tconst), stdin)) {
        perror("Failed to read input");
        return -1;
    }
    // Remove trailing newline
    tconst[strcspn(tconst, "\n")] = '\0';

    int index = -1;
    for (int i = 0; i < *movie_count; i++) {
        if (strcmp(movies[i].result.tconst, tconst) == 0) {
            index = i;
            break;
        }
    }

    if (index == -1) {
        printf("No movie found with tconst '%s'.\n", tconst);
        return -1;
    }

    // Delete the associated file
    if (unlink(movies[index].file_path) == 0) {
        printf("File '%s' deleted successfully.\n", movies[index].file_path);
    } else {
        perror("Failed to delete file");
        // Continue removing from memory even if file deletion fails
    }

    // Shift elements in the array to remove the movie
    for (int i = index; i < *movie_count - 1; i++) {
        movies[i] = movies[i + 1];
    }
    (*movie_count)--;

    printf("Movie with tconst '%s' removed from memory and file system.\n", tconst);
    return 0;
}

// Function to get the playlist name from the file based on playlist ID
int getPlaylistName(const char* playlist_id, char playlist_name_p[256]) {
    FILE *file = fopen("playlists.txt", "r");
    if (!file) {
        perror("Failed to open playlists file");
        return 1;  // Return NULL if file can't be opened
    }

    static char playlist_name[256];  // Static variable to hold playlist name

    char line[512];
    while (fgets(line, sizeof(line), file)) {
        char id[128], name[256];

        // Split the line into ID and name using the delimiter '|'
        if (sscanf(line, "%127[^|]|%255[^\n]", id, name) == 2) {
            printf("-- %s %s --\n", id, name);;
            if (strcmp(id, playlist_id) == 0) {
                // Found the matching ID, return the playlist name
                strncpy(playlist_name, name, sizeof(playlist_name) - 1);
                playlist_name[sizeof(playlist_name) - 1] = '\0';  // Null-terminate
                fclose(file);
                strcpy(playlist_name_p, playlist_name);
                return 0;
            }
        }
    }

    fclose(file);
    return 1;  // Return NULL if ID not found
}


void displayPlaylistContent(DataStruct* movies, int movie_count, char playlist_id[11]) {
    // Prompt user for playlist ID
    if(strlen(playlist_id) == 0) {
        list_playlists();
        printf("Enter the " YELLOW "playlist ID" RESET ": ");
        scanf("%s", playlist_id);
        getchar(); // fix..
        playlist_id[strcspn(playlist_id, "\n")] = '\0';  // Remove newline
    }

    // Construct playlist file path
    char playlist_path[512];
    snprintf(playlist_path, sizeof(playlist_path), "playlists/%s.txt", playlist_id);

    // Open playlist file
    FILE *file = fopen(playlist_path, "r");
    if (!file) {
        printf(RED "Error: Playlist with ID '%s' does not exist or could not be opened.\n" RESET, playlist_id);
        return;
    }

    char playlist_name[256] = "\0";
    getPlaylistName(playlist_id, playlist_name);

    printf(CYAN "\n┌──────────────────────────────────────────────\n" RESET); \
    printf(CYAN "│" RESET WHITE "%-24s " RESET "(%s)\n", playlist_name, playlist_id);

    printf(CYAN "│" GREEN "------------------------------" RESET "\n");

    char tconst[256];
    int movie_found = 0;

    // Read tconst entries from playlist file
    while (fgets(tconst, sizeof(tconst), file)) {
        tconst[strcspn(tconst, "\n")] = '\0';  // Remove newline

        // Search for the movie in the provided movies array
        int found = 0;
        for (int i = 0; i < movie_count; i++) {
            if (strcmp(movies[i].result.tconst, tconst) == 0) {
                printf(CYAN "│" RESET "%3d. " WHITE "%20s" RESET " (" CYAN "%s" RESET ")\n",
                       i + 1,
                       movies[i].result.primaryTitle,
                       movies[i].result.tconst);
                found = 1;
                break;
            }
        }

        // If the tconst isn't found in the movies array
        if (!found) {
            printf(CYAN "│" YELLOW "Warning: Movie with tconst '%s' not found in the movies list.\n" RESET, tconst);
        }

        movie_found = 1;
    }

    fclose(file);

    if (!movie_found) {
        printf(CYAN "│" RED "This playlist is empty or contains invalid entries.\n" RESET);
    } else {
        printf(CYAN "│" GREEN "------------------------------" RESET "\n");
    }
    printf(CYAN "└──────────────────────────────────────────────\n" RESET); \
}


void displayRelevantInfo(DataStruct *data) {
    // Display Title Entry info with colors
    printf(MAGENTA  "\n┌──────────────────────────────────────────────\n" RESET);

    if (data->result.title) {
        TitleEntry *title = data->result.title;
        printf(MAGENTA "│ " WHITE "%-28s" MAGENTA "%s %s" "\n" RESET, 
                title->primaryTitle, 
                title->languageCount > 0 && strlen(data->result.selected) > 0 ? " ||" : "",
                title->languageCount > 0 && strlen(data->result.selected) > 0 ? title->languages[data->result.selected_id].title : "");
        printf(MAGENTA "├──────────────────────────────────────────────\n" RESET);
        printf(MAGENTA "│" RESET "  Type: " WHITE "%s, " RESET "Rank: " WHITE "%.2f, " RESET "Rank_c: " WHITE "%d, " RESET "Selected: " WHITE "%s\n",
                title->titleType, data->result.score, data->result.selected_id, data->result.selected);

        // Display Year, ID, and Genres
        printf(MAGENTA "│" RESET "  Year: " WHITE "%d-%d, " RESET "ID: " WHITE "%s, " RESET "Genres: " WHITE "%s\n",
                title->startYear, title->endYear, data->result.tconst, title->runtimeMinutesgenres);

        // Optionally display RatingInfo if it exists
        if (title->ratingInfo) {
            printf(MAGENTA "│" RESET "  Rating: " WHITE "%.1f, " RESET "Votes: " WHITE "%d\n",
                    title->ratingInfo->averageRating, title->ratingInfo->numVotes);
        }
    } else {
        // Display Search Query and Barcode
        printf(MAGENTA "│" RESET "  Search Query: " WHITE "%s, " RESET "Barcode: " WHITE "%s\n", data->search_query, data->barcode);
    }
    printf(MAGENTA "└──────────────────────────────────────────────\n" RESET);
}
// Function to check if a tconst exists in a playlist
int is_movie_in_playlist(const char *playlist_id, const char *tconst) {
    char filepath[256];  // Path to the playlist file
    char line[14];

    // Construct the filepath for the playlist
    snprintf(filepath, sizeof(filepath), "playlists/%s.txt", playlist_id);

    // Open the playlist file for reading
    FILE *file = fopen(filepath, "r");
    if (!file) {
        perror("Error opening playlist file");
        return 0;  // Return 0 if the file doesn't exist
    }

    // Read the file line by line and check for the tconst
    while (fgets(line, sizeof(line), file)) {
        trim_whitespace(line);
        if (strcmp(line, tconst) == 0) {
            fclose(file);
            return 1;  // tconst found in the playlist
        }
    }

    // Close the file and return 0 if tconst not found
    fclose(file);
    return 0;
}

DataStruct* findMovieByBarcode(DataStruct* movies, int movie_count, char barcode[14]) {
    // Validate input and find the corresponding movie
    for (int i = 0; i < movie_count; i++) {
        if (strcmp(movies[i].barcode, barcode) == 0) {
            return &movies[i];
        }
    }
    return NULL;
}

DataStruct* findMovieByTconst(DataStruct* movies, int movie_count, char tconst[13]) {
    // Validate input and find the corresponding movie
    for (int i = 0; i < movie_count; i++) {
        if (strcmp(movies[i].result.tconst, tconst) == 0) {
           return &movies[i];
            break;
        }
    }
    return NULL;
}

void addMovieToPlaylist(DataStruct* movies, int movie_count, char tconst[13]) {
    // List all movies
    listMovies(movies, movie_count);

    if (movie_count == 0) {
        printf(RED "No movies available to add to a playlist.\n" RESET);
        return;
    }

    char input[256] = "\0";
    DataStruct *selected_movie = NULL;
    while (!selected_movie) {
        // Get barcode or tconst
        if (strlen(tconst) == 0) {
            while(strlen(input) == 0) {
                printf("Enter the " YELLOW "barcode or tconst" RESET " of the movie: ");
                fgets(input, sizeof(input), stdin);
                trim_whitespace(input);
                if (input[0] == 'q')
                    return;
            }
        } else {
            strcpy(input, tconst);
        }

        // Validate input and find the corresponding movie
        printf("TCON#%s#\n", input);
        selected_movie = findMovieByTconst(movies, movie_count, input);

        if (!selected_movie) {
            printf(RED "Error: No movie found with barcode or tconst '%s'.\n" RESET, input);
            input[0] = '\0';
        }
    }

    displayRelevantInfo(selected_movie);
    // List playlists
    list_playlists();


    // Ask for playlist ID or create a new one
    static char playlist_id[14] = "\0";
    char playlist_id_new[14] = "\0";
    while (!isValidPlaylistID(playlist_id_new)) {
        printf(YELLOW "[playlist id|new|q]\n" RESET);
        printf(WHITE "(%s): " RESET, playlist_id);
        fgets(playlist_id_new, sizeof(playlist_id_new), stdin);


        trim_whitespace(playlist_id_new);

        if (playlist_id_new[0] == 'q')
            return;


        if (is_movie_in_playlist(playlist_id_new, selected_movie->result.tconst)) {
            playlist_id_new[0] = '\0';
            printf(RED "Movie already in the playlist.\n" RESET);
            int c;
            while ((c = getchar()) != '\n' && c != EOF) { }
            continue;
        }

        if (strlen(playlist_id_new) == 0 && isValidPlaylistID(playlist_id))
            break;

        strcpy(playlist_id, playlist_id_new);
        if (isValidPlaylistID(playlist_id))
            break;
        if (strcmp(playlist_id, "new") == 0) {
            add_playlist(playlist_id);
        }
    }
    if (!isValidPlaylistID(playlist_id)) {
        printf("Invalid Playlist: %s\n", playlist_id);
        addMovieToPlaylist(movies, movie_count, tconst);
        return;
    }


    char playlist_name[257];
    if (strcmp(playlist_id, "new") == 0) {
        printf("Enter the " YELLOW "name of the new playlist" RESET ": ");
        fgets(playlist_name, sizeof(playlist_name), stdin);
        playlist_name[strcspn(playlist_name, "\n")] = '\0';  // Remove newline

        // Create a new playlist
        FILE *file = fopen(FILENAME, "a");
        if (!file) {
            perror(RED "Error opening playlist file" RESET);
            return;
        }

        // Generate new ID
        int new_id = rand() % 10000;  // Generate a random ID (for simplicity)
        snprintf(playlist_id, sizeof(playlist_id), "%04d", new_id);
        fprintf(file, "%s|%s\n", playlist_id, playlist_name);
        fclose(file);

        printf(GREEN "New playlist created with ID: %s\n" RESET, playlist_id);
    }

    // Write the tconst to the playlist file
    char playlist_path[512];
    snprintf(playlist_path, sizeof(playlist_path), "playlists/%s.txt", playlist_id);
    ensure_directory_exists("playlists");

    FILE *playlist_file = fopen(playlist_path, "a");
    if (!playlist_file) {
        perror(RED "Error opening playlist file" RESET);
        return;
    }

    fprintf(playlist_file, "%s\n", selected_movie->result.tconst);
    fclose(playlist_file);

    printf(GREEN "Movie " WHITE "%s" RESET " (tconst: %s) " GREEN "added to playlist %s\n" RESET, 
           selected_movie->result.primaryTitle, 
           selected_movie->result.tconst, 
           playlist_id);

    displayPlaylistContent(movies, movie_count, playlist_id);
    getchar(); // fix..
}


// Function to remove a movie from a playlist
void removeMovieFromPlaylist(DataStruct* movies, int movie_count) {
    list_playlists();
    char playlist_id[14], tconst[256];

    // Ask for the playlist ID to remove movie from
    printf("Enter the " YELLOW "playlist ID" RESET " to remove from: ");
    fgets(playlist_id, sizeof(playlist_id), stdin);
    trim_whitespace(playlist_id);
    int c;
    while ((c = getchar()) != '\n' && c != EOF) { }

    // Validate the playlist ID
    if (!isValidPlaylistID(playlist_id)) {
        printf(RED "Error: Playlist ID '%s' does not exist.\n" RESET, playlist_id);
        clearInputBuffer();
        return;
    }

    displayPlaylistContent(movies, movie_count, playlist_id);
    // Ask for the tconst of the movie to be removed
    printf("Enter the " YELLOW "tconst" RESET " of the movie to remove: ");
    fgets(tconst, sizeof(tconst), stdin);
    tconst[strcspn(tconst, "\n")] = '\0';  // Remove newline

    // File path for the playlist (e.g., "playlists/1234.txt")
    char playlist_file_path[256];
    snprintf(playlist_file_path, sizeof(playlist_file_path), "playlists/%s.txt", playlist_id);

    // Read the existing playlist file
    FILE *file = fopen(playlist_file_path, "r");
    if (!file) {
        perror(RED "Error opening playlist file" RESET);
        return;
    }

    // Create a temporary file to store the updated playlist
    FILE *temp_file = fopen("temp_playlist.txt", "w");
    if (!temp_file) {
        perror(RED "Error creating temporary file" RESET);
        fclose(file);
        return;
    }

    char line[MAX_LINE];
    int found = 0;
    while (fgets(line, sizeof(line), file)) {
        // If the line doesn't match the tconst to be removed, write it to the temporary file
        if (strncmp(line, tconst, strlen(tconst)) != 0) {
            fputs(line, temp_file);
        } else {
            found = 1;
        }
    }

    fclose(file);
    fclose(temp_file);

    // If the movie was found and removed, replace the old playlist file with the updated one
    if (found) {
        remove(playlist_file_path);  // Delete the old playlist file
        rename("temp_playlist.txt", playlist_file_path);  // Rename temp file to original playlist file

        displayPlaylistContent(movies, movie_count, playlist_id);

        printf(GREEN "Movie with tconst '%s' removed from playlist '%s'.\n" RESET, tconst, playlist_id);
    } else {
        printf(RED "Error: Movie with tconst '%s' not found in playlist '%s'.\n" RESET, tconst, playlist_id);
        remove("temp_playlist.txt");  // Clean up temp file if no movie was removed
    }

}



int main() {
    DataStruct* movies = NULL;
    int movie_count = loadLocalMovies(&movies, "local");
    listMovies(movies, movie_count);


    DataStruct* dvd;

    Websearch_st data_web;

    TitleEntry *titles;
    int title_count;


    RatingInfo *ratings = NULL;

    // Load the ratings from the file
    int ratings_count = 0;

    int is_imbd_data_loadad = 0;


    /*
    for (int i = 0; i < 3; i++) {
        if (titles[i].languages == NULL) continue;
        for (int j = 0; j < titles[i].languageCount; j++) {
            if (titles[i].languages[j].isOriginalTitle)
                printf("ORIGINAL: %s\n", titles[i].tconst);
            if (titles[i].languages[j].region == NULL) continue;
            if (strcmp(titles[i].languages[j].region, "DE") == 0) {
                printf("%d %d\n", i, titles[i].languageCount); break; } }
    }
    */





    char barcode[14] = "\0";
    char file_path[512] = "\0";
    SearchResult* res = NULL;
    SearchResult* res_last = NULL;
    int search_locally = 0;
    while (1) {
        char search_query[256] = "\0";
        // If empty, read the search query from stdin

        while (1) {
            clearInputBuffer();
            
            printf(BLUE "\n─────────────────────────────────────────\n" RESET);
            printf(" %s%s" CYAN " DB Action on " YELLOW "%s %s\n" RESET, search_locally ? GREEN : YELLOW ,search_locally ? "Local" : "Global" ,barcode, res_last ? res_last->tconst : "");
            // Prompt for input
            printf("  [list|add|rm|rm last|print|clear|local]\n");
            printf("  [list|add|remove] [from] playlist[s]\n");
            printf("  [search barcode]\n\n");
            printf("  [\"search query\"|\"barcode\"]\n\n");
            printf(WHITE "Enter search query: " RESET);
            fgets(search_query, sizeof(search_query), stdin);
            printf("\n");

            // Remove the trailing newline character if it exists
            trim_whitespace(search_query);

            // Check if input is empty
            int sl = strlen(search_query);
            if (sl == 0) {
                printf("Input is empty, please enter a valid query.\n");
                continue;
            }



            // Check if input is a barcode (14 digits)
            if (strcmp(search_query, "list playlists") == 0 ||
                    strcmp(search_query, "playlists") == 0) {
                PRINT_HEADER("List Playlists");
                list_playlists();
            } else if (strcmp(search_query, "remove from playlist") == 0) {
                PRINT_HEADER("Remove Movie from Playlist");
                removeMovieFromPlaylist(movies, movie_count);
            } else if (strcmp(search_query, "list playlist") == 0 ||
                    strcmp(search_query, "playlist") == 0) {
                PRINT_HEADER("Display Playlist Content");
                char empty_playlist_id[14] = "";
                displayPlaylistContent(movies, movie_count, empty_playlist_id);
            } else if (strcmp(search_query, "add playlist") == 0) {
                PRINT_HEADER("Add Playlist");
                char empty_playlist_id[14] = "";
                add_playlist(empty_playlist_id);
            } else if (strcmp(search_query, "rm playlist") == 0) {
                PRINT_HEADER("Remove Playlist");
                remove_playlist();
            } else if (strcmp(search_query, "rm") == 0) {
                PRINT_HEADER("Remove Movie");
                removeMovie(movies, &movie_count);
            } else if (strcmp(search_query, "local") == 0) {
                search_locally = !search_locally ;
            } else if (strcmp(search_query, "add") == 0) {
                PRINT_HEADER("Add Movie to Playlist");
                char lt[13];
                strcpy(lt,res_last != NULL ? res_last->tconst : "\0");
                addMovieToPlaylist(movies, movie_count, lt);
            } else if (strcmp(search_query, "list") == 0) {
                PRINT_HEADER("List Movies");
                listMovies(movies, movie_count);
            } else if (strcmp(search_query, "rm last") == 0) {
                PRINT_HEADER("Remove last added");
                if (strlen(file_path) == 0) continue;
                if (remove(file_path) == 0) {
                    printf("File deleted successfully.\n");
                } else {
                    perror("Error deleting file");
                }
            } else if (strcmp(search_query, "print") == 0) {
                printDataStruct(dvd);
            } else if (strcmp(search_query, "clear") == 0) {
                Websearch_st data_web_new = {};
                data_web = data_web_new;
                data_web.title[0] = '\0';
                barcode[0] = '\0';
                file_path[0] = '\0';
                res = NULL;
                res_last = NULL;
            } else if (search_locally) {
                search_query[12] = '\0';
                dvd = findMovieByTconst(movies, movie_count, search_query);
                printDataStruct(dvd);
            } else if ((sl == 13 && strspn(search_query, "0123456789") == 13) ||
                    (sl == 12 && strspn(search_query, "0123456789") == 12) ||
                    strcmp(search_query, "search barcode") == 0) {

                Websearch_st data_web_new = { "", 0.0, 0.0, "" };

                if (strcmp(search_query, "search barcode") == 0) {
                    if (!(strlen(dvd->barcode) ==12 || strlen(dvd->barcode) ==13)) {
                        perror("Not a valid barcode\n");
                        search_query[0] = '\0';
                        continue;
                    }
                    printf("Make use of barcode: %s\n", dvd->barcode);
                    strcpy(search_query, dvd->barcode);
                } else {
                    data_web = data_web_new;
                    data_web.title[0] = '\0';
                    barcode[0] = '\0';
                    file_path[0] = '\0';
                    res = NULL;
                    res_last = NULL;
                    strcpy(barcode, search_query);
                    barcode[13] = '\0';

                    DataStruct* res_d = findMovieByBarcode(movies, movie_count, barcode);
                    if (res_d) {
                        res = &res_d->result;
                        res_last = &res_d->result;
                        data_web = res_d->web_data;
                        dvd = res_d;
                        printDataStruct(dvd);
                        continue;
                    }
                }

                printf("Recognized barcode %s...\n", barcode);

                PRINT_HEADER("Search Barcode in web..");
                data_web_new = readUpcitemdb(barcode);
                print_json_response(&data_web_new);
                PRINT_HEADER_SMALL("Search web done: ");
                printf("%s\n", data_web_new.title);
                if (strlen(data_web_new.title) > 0) {
                    data_web = data_web_new;
                    strcpy(search_query, data_web.title);
                    break;
                }
            } else if (sl > 0) {
                break;
            }
        }
        //continue; // !!! <---




        if (!is_imbd_data_loadad) {
            PRINT_HEADER("Source imbd files");
            fflush(stdout);
            PRINT_HEADER_SMALL("source ratings");
            ratings_count = load_ratings(&ratings);
            if (ratings_count < 0) {
                fprintf(stderr, "Failed to load ratings.\n");
                return 1;
            }

            //for (int i = 0; i < 22; i++) printf("%d %s %lf\n", i, ratings[i].tconst, ratings[i].averageRating); exit(1);

            PRINT_HEADER_SMALL("source titles");
            if (load_titles(&titles, &title_count, ratings, ratings_count) != 0) {
                fprintf(stderr, "Failed to load titles.\n");
                return 1;
            }


            PRINT_HEADER_SMALL("source languages");
            for (int i = 0; i < title_count; i++) {
                pthread_mutex_init(&titles[i].lock, NULL);
            }

            if (load_languages_and_regions(titles, title_count) != 0) {
                fprintf(stderr, "Failed to load titles.\n");
                return 1;
            }
            for (int i = 0; i < title_count; i++) {
                pthread_mutex_destroy(&titles[i].lock);
            }


            /*
            for (int i = 0; i < 12; i++) {
                if (titles[i].ratingInfo == NULL) continue;
                if (titles[i].languageCount == 0) continue;
                printf("%d %s %s %lf\n", i, titles[i].tconst, titles[i].languages[0].title, titles[i].ratingInfo->averageRating);
            }
            */

            is_imbd_data_loadad = 1;
            PRINT_HEADER_SMALL("Donne sourcing imbd files");
        }




        PRINT_HEADER("Search query: ");
        printf("Searching for: %s\n\n", search_query);
        fflush(stdout);

        // Call search_and_select function
        res = search_and_select(search_query, titles, title_count);

        if (res != NULL) {
            //saveToFile(res, &data_web, search_query, barcode, file_path);
            DataStruct dvd_ = createDataStruct(res, &data_web, search_query, barcode);
            dvd = &dvd_;
            printDataStruct(dvd);
            writeStructToFile(dvd);
        } else {
            snprintf(file_path, sizeof(file_path), "");
        }

        // If search_and_select produced results, append to database
        PRINT_HEADER_SMALL("Add to DB");
        if (strlen(search_query) > 0) {
            printf("Appending result to database: %s\n", search_query);
            append_to_database(search_query);
            movie_count = loadLocalMovies(&movies, "local");
            res_last = res;
        } else {
            res_last = NULL;
            printf("No results to append.\n");
        }

        printf(RESET);

    }

    printf(RESET);
    free(titles);

    // Free allocated memory
    free(movies);
    return 0;
}