diff --git a/.gitignore b/.gitignore index 73cd475..267cf1a 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,5 @@ /public_html/_images/HB /public_html/_images/TEST /public_html/.htaccess -/public_html/.user.ini \ No newline at end of file +/public_html/.user.ini +.idea \ No newline at end of file diff --git a/backend/src/images.rs b/backend/src/images.rs index 88e34f7..edd1f75 100644 --- a/backend/src/images.rs +++ b/backend/src/images.rs @@ -93,8 +93,8 @@ fn crop_image(image_data: ImgVec) -> anyhow::Result> { let mut cropped_image = Image::new( - 128, - 128, + 256, + 256, PixelType::U8x4, // RGBA8 ); @@ -113,6 +113,7 @@ pub fn get_converted_image_data(issue: &mut Issue, images_path: &str, homebrew_d let path = format!("{}/game/{}.avif", images_path, issue.code); if Path::new(&path).exists() { + issue.image = true; return Ok(()); } @@ -133,6 +134,7 @@ pub fn get_converted_image_data(issue: &mut Issue, images_path: &str, homebrew_d let path = format!("{}/homebrew/{}.avif", images_path, issue.title); if Path::new(&path).exists() { + issue.image = true; return Ok(()); } diff --git a/backend/src/main.rs b/backend/src/main.rs index 510fad1..b6e085f 100644 --- a/backend/src/main.rs +++ b/backend/src/main.rs @@ -30,7 +30,7 @@ fn main() { // update the homebrew database and get a connection homebrew_database_updater(HB_DATABASE, &homebrew_token).polar_unwrap("", true); let homebrew_db = Connection::open(HB_DATABASE).polar_unwrap("Failed to open SQLite connection to homebrew database!", true); - let homebrew_db = Arc::new( Mutex::new(homebrew_db)); + let homebrew_db = Arc::new( Mutex::new(homebrew_db) ); let (page_count, issues_count): (u64, u64) = networking::github_get_repo_info(&github_token); @@ -44,11 +44,7 @@ fn main() { let old_game_skips: Arc< Vec > = { match fs::read_to_string(GAME_SKIPS_DATABASE) { - Ok(string) => { - - Arc::new(serde_json::from_str(&string).unwrap_or_default()) - - } + Ok(string) => Arc::new(serde_json::from_str(&string).unwrap_or_default()), Err(_) => Arc::new(vec![]) } }; @@ -125,11 +121,11 @@ fn main() { // saves databases - let temp_string = serde_json::to_string_pretty(&issues).polar_unwrap("error making issues into a json!", true); + let temp_string = serde_json::to_string(&issues).polar_unwrap("error making issues into a json!", true); let temp_path = format!("{database_path}/database.json"); fs::write(temp_path, temp_string).polar_unwrap("Error saving the \"database\" file!", true); - let temp_string = serde_json::to_string_pretty(&game_skips).polar_unwrap("error making game_skips into a json!", true); + let temp_string = serde_json::to_string(&game_skips).polar_unwrap("error making game_skips into a json!", true); fs::write(GAME_SKIPS_DATABASE, temp_string).polar_unwrap("Error saving the \"game_skips\" file!", true); println_green!("dun! {} issues processed", issues.len()); diff --git a/public_html/_parts/navbar.html b/public_html/_parts/navbar.html index de6746c..699bd06 100644 --- a/public_html/_parts/navbar.html +++ b/public_html/_parts/navbar.html @@ -23,7 +23,7 @@ text-decoration: none; font-size: 1.5rem; color: var(--text); - line-height: 0%; + line-height: 0; filter: invert(1); } .logo span {filter: invert(1);} /* fix text color */ @@ -32,7 +32,7 @@ display: flex; justify-content: flex-end; align-items: center; - line-height: 0%; + line-height: 0; margin: 0 3.5vw; gap: 0.5vw; filter: invert(1); diff --git a/public_html/_parts/required.js b/public_html/_parts/required.js index 0f00cd1..9cd0632 100644 --- a/public_html/_parts/required.js +++ b/public_html/_parts/required.js @@ -101,4 +101,24 @@ function adjustScreenSize() { document.documentElement.style.zoom = "1"; document.documentElement.style.fontSize = fontSize + 'px'; } +} + +// Fetch html for footer and header +async function fetchHtml(path, target){ + return new Promise((resolve, reject) => { + fetch(path).then(response => response.text()).then(data => { + document.querySelector(target).innerHTML = data; + resolve("done!") + }).catch(() => { + reject("error occurred while fetching html!") + }); + }) +} + +async function init() { + // Header & Footer Load + await fetchHtml("/_parts/navbar.html", "#header"); + await fetchHtml("/_parts/footer.html", "#footer"); + + LightModeIconChange(); } \ No newline at end of file diff --git a/public_html/_scripts/api.php b/public_html/_scripts/api.php deleted file mode 100644 index aab7eb8..0000000 --- a/public_html/_scripts/api.php +++ /dev/null @@ -1,88 +0,0 @@ -prepare($query); - $stmt->bindParam(':cusacode', $code, PDO::PARAM_STR); - $stmt->execute(); - $result = $stmt->fetchAll(PDO::FETCH_ASSOC); - - if ($result) { - $tag = $result["0"]["tags"]; - } else { - $tag = "N/A"; - } - - $cusacodeArray[] = array( - "id" => $code, - "tag" => $tag - ); - } - } - if ($homebrews) { - foreach ($homebrew as $code) { - $query = "SELECT tags FROM issues WHERE title = :homebrew"; - $stmt = $conn->prepare($query); - $stmt->bindParam(':homebrew', $code, PDO::PARAM_STR); - $stmt->execute(); - $HBresult = $stmt->fetchAll(PDO::FETCH_ASSOC); - - if ($HBresult) { - $tag = $HBresult["0"]["tags"]; - } else { - $tag = "N/A"; - } - $homebrewArray[] = array( - "title" => $code, - "tag" => $tag - ); - } - } - $data = array( - "cusacode" => $cusacodeArray, - "homebrew" => $homebrewArray - ); - /// end - header('Content-Type: application/json'); - $jsonData = json_encode($data); - //$jsonData = json_encode($data, JSON_PRETTY_PRINT); - - echo $jsonData; - $conn = null; //exit connection -} -} else { - http_response_code(404); - include("/home/{$serverUsername}/domains/fpps4.net/public_html/404.php"); -}?> \ No newline at end of file diff --git a/public_html/_scripts/search.php b/public_html/_scripts/search.php deleted file mode 100644 index 5f6da34..0000000 --- a/public_html/_scripts/search.php +++ /dev/null @@ -1,189 +0,0 @@ -"; - } - -/// processing user input - $searchQuery = htmlspecialchars(isset($_GET['q']) ? $_GET['q'] : ""); - $tags = htmlspecialchars(isset($_GET['tag']) ? $_GET['tag'] : ""); - $page = filter_var(isset($_GET['page']) ? $_GET['page'] : 1, FILTER_VALIDATE_INT); - $oldest = filter_var(isset($_GET['oldest']) ? $_GET['oldest'] : false, FILTER_VALIDATE_BOOLEAN); - $giveStats = filter_var(isset($_GET['stats']) ? true : false, FILTER_VALIDATE_BOOLEAN); - - if ($page < 0 || $page === 0) { - $page = 1; - } - -/// defining stuff lmao - $maxResults = (!empty($searchQuery)) ? 10 : 20; - $pageNumber = ($page - 1) * $maxResults; - $sqlQuery = "SELECT * FROM issues"; - $params = array(); - $conditions = array(); - - -/// if there is an search query in the request - if (!empty($searchQuery)) { - $searchQuery = strtolower($searchQuery); - if (strpos($searchQuery, 'cusa') !== false) { - $conditions[] = "code LIKE :searchQuery"; - } else { - $conditions[] = "title LIKE :searchQuery"; - } - $params[':searchQuery'] = $searchQuery . '%'; - } - - -/// if there are tags in the request - if (!empty($tags)) { - $tagFilters = explode(',', $tags); - $tagConditions = []; - $tagParams = []; - - foreach ($tagFilters as $index => $tag) { - $tagParam = ":tagFilter{$index}"; - $tagConditions[] = "(CONCAT(',', tags, ',') LIKE CONCAT('%,', {$tagParam}, ',%'))"; - $tagParams[$tagParam] = "{$tag}"; - } - - if (!empty($tagConditions)) { - $conditions[] = "(" . implode(" OR ", $tagConditions) . ")"; - $params = array_merge($params, $tagParams); - } - } - - if (!empty($conditions)) { - $sqlQuery .= " WHERE " . implode(" AND ", $conditions); - } - - -/// gets the total amount of issues based on the search query - $sqlQueryForTotal = "SELECT COUNT(*) AS total FROM ($sqlQuery) AS totalIssues"; - $stmtTotal = $conn->prepare($sqlQueryForTotal); - - foreach ($params as $param => &$value) { - $stmtTotal->bindParam($param, $value, PDO::PARAM_STR); - } - - $stmtTotal->execute(); - $totalIssuesAmount = $stmtTotal->fetch(PDO::FETCH_ASSOC)['total']; - $totalPages = ceil($totalIssuesAmount / $maxResults); - - -/// forming and executing sql query - $sqlQuery .= " ORDER BY id " . ($oldest ? "ASC" : "DESC"); - $sqlQuery .= " LIMIT :offset, :limit"; - $params[':offset'] = $pageNumber; - $params[':limit'] = $maxResults; - - $stmt = $conn->prepare($sqlQuery); - - foreach ($params as $param => &$value) { - if (is_int($value)) { - $stmt->bindParam($param, $value, PDO::PARAM_INT); - } else { - $stmt->bindParam($param, $value, PDO::PARAM_STR); - } - } - - $stmt->execute(); - $result = $stmt->fetchAll(PDO::FETCH_ASSOC); - - -/// Outputing results -header('Content-Type: application/json'); - -$games = array(); -$stats = array(); - - foreach ($result as $game) { - $cusaCode = $game['code']; - $image = $game['type'] === "HB" ? (file_exists("$dir/public_html/_images/HB/{$game['title']}.avif") ? true : false) : (file_exists("$dir/public_html/_images/CUSA/{$cusaCode}.avif") ? true : false); - $games[] = array( - "id" => $game['id'], - "title" => $game['title'], - "code" => $game['code'], - "type" => $game['type'], - "tag" => $game['tags'], - "upDate" => $game['updatedDate'], - "image" => $image - ); - } - - /// stats on the compatibility list - if ($giveStats === true) { - $availableTags = ['Nothing', 'Boots', 'Menus', 'Ingame', 'Playable']; - $tagPercentages = []; - - $naTag = "N/A"; - $stmt = $conn->prepare("SELECT COUNT(*) AS count FROM issues WHERE tags = :tag"); - $stmt->bindParam(':tag', $naTag, PDO::PARAM_STR); - $stmt->execute(); - $naCount = $stmt->fetch(PDO::FETCH_ASSOC)['count']; - - $result = $conn->query("SELECT COUNT(*) FROM issues"); - $total = $result->fetchColumn(); - - $totalIssuesWithoutNA = $total - $naCount; - - foreach ($availableTags as $tag) { - $stmt = $conn->prepare("SELECT COUNT(*) AS count FROM issues WHERE tags = :tag"); - $stmt->bindParam(':tag', $tag, PDO::PARAM_STR); - $stmt->execute(); - - $count = $stmt->fetch(PDO::FETCH_ASSOC)['count']; - $percentage = ($total > 0) ? ($count / $total) * 100 : 0; - $tagPercentages[$tag] = $percentage; - $tagCount[$tag] = $count; - } - - $amount = (100 - array_sum($tagPercentages)) / count($tagPercentages); - - foreach ($availableTags as $tag) { - $percentage = $tagPercentages[$tag]; - $count = $tagCount[$tag]; - $percentage += $amount; - $percentage = round($percentage, 2); - $stats[] = array( - "tag" => $tag, - "percent" => $percentage, - "count" => $count - ); - } - } - - $executionTime = round((microtime(true) - $startTime) * 1000, 2); // Convert to milliseconds - - $info = array( - "issues" => $totalIssuesAmount, - "pages" => $totalPages, - "time" => $executionTime - ); - - $data = array( - "info" => $info, - "games" => $games, - "stats" => $stats, - ); - - - /// end - $jsonData = json_encode($data); - // $jsonData = json_encode($data, JSON_PRETTY_PRINT); - echo $jsonData; - $conn = null; //exit connection -?> diff --git a/public_html/_scripts/updater.php b/public_html/_scripts/updater.php deleted file mode 100644 index 2058e22..0000000 --- a/public_html/_scripts/updater.php +++ /dev/null @@ -1,336 +0,0 @@ -
"; - $dir = dirname(__DIR__, 2); - require_once "$dir/_config/config.php"; // import config file - - if ((isset($_GET[ARGUMENT_SECRET]) && $_GET[ARGUMENT_SECRET] === ACCESS_SECRET) || (isset($argv[1]) && $argv[1] === ARGUMENT_SECRET)) { - // echo""; - function ErrorHandler($errLvl, $errMesg, $errFile, $errLine) { - $position = strpos($errMesg, "/"); - $errMesg = $position !== false ? substr($errMesg,0, $position) : $errMesg; // check for an "/" and remove stuff - - switch ($errLvl) { - case E_ERROR || E_USER_ERROR: - $error = "Error: $errMesg [line: $errLine]"; - break; - case E_WARNING || E_USER_WARNING: - $error = "Warning: $errMesg [line: $errLine]"; - break; - case E_NOTICE || E_USER_NOTICE: - $error = "Notice: $errMesg [line: $errLine]"; - break; - default: - $error = "Unknown error: $errMesg [line: $errLine]"; - break; - } - $fullError = "Something went wrong => $error
"; - throw new Exception("$fullError"); - } - set_error_handler("ErrorHandler"); - - $host = DATABASE_HOST; - $database = DATABASE_NAME; - $username = DATABASE_USERNAME; - $password = DATABASE_PASSWORD; - - $githubToken = GITHUB_TOKEN; - $tmdbHash = TMDB_HASH; - $HBheader = stream_context_create(["http" => ["header" => "User-Agent: " . HB_USERAGENT ."\r\n"]]); - - // get homebrew db for images - try { - if (date("i") > 58 || date("i") < 3) { - $response = file_get_contents("https://api.pkg-zone.com/api.php?db_check_hash=true", false, $HBheader); - $hash = json_decode($response)->hash; //get hash from json - $md5Hash = file_exists("$dir/_config/HBstore.db") ? md5_file("$dir/_config/HBstore.db") : "0"; - - if ($hash !== $md5Hash) { - $fileContent = file_get_contents("https://api.pkg-zone.com/store.db", false, $HBheader); - file_put_contents("$dir/_config/HBstore.db", $fileContent); - } - } - } catch (Exception $e) { - print($e); - file_exists("$dir/_config/HBstore.db") ? print("Ignoring for now
") : die("Critical error, stopping
"); - - } finally {print("Homebrew database download task "); date("i") > 58 || date("i") < 3 ? print("completed!
") : print("skipped!
");} - - - // database connection and table creation - try { - $homebrewDB = new PDO("sqlite:$dir/_config/HBstore.db"); - $conn = new PDO("mysql:host=$host;dbname=$database", $username, $password); - $conn->query("DROP TABLE IF EXISTS newIssues"); - - // creating tables - $sqlQuerys = [ - "CREATE TABLE IF NOT EXISTS issues ( - id INT(5) PRIMARY KEY, - code VARCHAR(10), - title VARCHAR(130), - tags VARCHAR(200), - type VARCHAR(6), - updatedDate VARCHAR(12), - createdDate VARCHAR(12) - )", - "CREATE TABLE IF NOT EXISTS newIssues ( - id INT(5) PRIMARY KEY, - code VARCHAR(10), - title VARCHAR(130), - tags VARCHAR(200), - type VARCHAR(6), - updatedDate VARCHAR(12), - createdDate VARCHAR(12) - )", - "CREATE TABLE IF NOT EXISTS GameSkips ( - code VARCHAR(130) PRIMARY KEY - )" - ]; - - foreach ($sqlQuerys as $sql) { - $conn->exec($sql); - } - - } catch (Exception $e) { - print($e); - die("Critical error, stopping
"); - } finally {echo"Database connection and table creation task completed!
";} - - - function githubRequest(string $token, int $count, string $url) { - $curl_handle = curl_init(); - curl_setopt($curl_handle, CURLOPT_URL, $url); - curl_setopt($curl_handle, CURLOPT_HTTPHEADER, array('Accept: application/vnd.github+json', 'Authorization: Bearer '.$token)); - curl_setopt($curl_handle, CURLOPT_USERAGENT, "fpPS4.net"); - curl_setopt($curl_handle, CURLOPT_RETURNTRANSFER, 1); - $data = curl_exec($curl_handle); - curl_close($curl_handle); - - $count++; - return json_decode($data, true); - } - - function imageDownloader(string $url, $header, string $location) { - $httpsUrl = str_replace('http://', 'https://', $url); - $imageData = file_get_contents($httpsUrl, false, $header); - - $imagick = new Imagick(); - if ($imagick->readImageBlob($imageData)) { - $imageFormat = $imagick->getImageFormat(); - if ($imageFormat == 'JPEG' || $imageFormat == 'PNG') { - $imagick->setImageFormat('avif'); - $imagick->setCompressionQuality(75); - $imagick->setImageProperty('avif:effort', '10'); - $imagick->setImageProperty('avif:speed', '1'); - $imagick->thumbnailImage(256, 256, true); - $imagick->stripImage(); - $imagick->writeImage($location); // save the image - } - } - $imagick->clear(); - $imagick->destroy(); - } - - try { - $ghRequests = 0; - $issueCount = githubRequest($githubToken, $ghRequests, "https://api.github.com/repos/red-prig/fpps4-game-compatibility")['open_issues_count']; - $pageCount = ceil($issueCount / 100); - echo "Total Issues: " . $issueCount . "
"; - echo "Total Pages: " . $pageCount . "

"; - $issuesProcessed = 0; - $noImage = 0; - - for ($page = 1; $page <= $pageCount; $page++) { - $issues = githubRequest($githubToken, $ghRequests, "https://api.github.com/repos/red-prig/fpps4-game-compatibility/issues?page=$page&per_page=100&state=open&direction=ASC"); - - foreach ($issues as $issue) { - $id = filter_var($issue['number'], FILTER_VALIDATE_INT); - $title = htmlspecialchars($issue['title']); - $tags = htmlspecialchars(implode(', ', array_column($issue['labels'], 'name'))); - $createdDate = htmlspecialchars(date('d/m/Y', strtotime($issue['created_at']))); - $updatedDate = htmlspecialchars(date('d/m/Y', strtotime($issue['updated_at']))); - $code = ""; - $type = ""; - - // skip invalid issues - if (str_contains($tags,"question") || str_contains($tags,"invalid")) { - continue; - } - - // look for an code in the title, for example: CUSA12345 or NPXS00000 and do some processing - preg_match('/[a-zA-Z]{4}[0-9]{5}/', $title, $matches); - if ($matches) { - str_starts_with($matches[0], "CUSA") ? ($code = $matches[0]) && ($type = "CUSA") : ""; - str_contains($tags, "app-homebrew") ? ($code = $matches[0]) && ($type = "HB") : ""; - str_contains($tags, "app-system-fw505") ? ($code = $matches[0]) && ($type = "SYS") : ""; - str_contains($tags, "app-ps2game") ? ($code = "PS2 GAME") : ""; - $title = str_replace(["- " . $matches[0], "-" . $matches[0], $matches[0]], "", $title); - } else { - str_contains($tags, "app-homebrew") ? ($code = "HOMEBREW") && ($type = "HB") : ""; - } - - $title = str_ireplace(["(Homebrew)", "- HOMEBREW", "Homebrew", "[]"], "", $title); - $title = rtrim($title, " -"); - - // if (empty($code)) { - // echo "skipping: $title
"; - // continue; - // } - $issuesProcessed++; - - // Now put it into a database :3 - try { - - // tag bullshit AHHHHH - if ($tags) { - $tags = str_ireplace(["status-", "app-homebrew", "app-system-fw505", "app-ps2game"], '', $tags); - - $priority = [ - 'playable', - 'ingame', - 'menus', - 'boots', - 'nothing' - ]; - - $tagArray = array_map('trim', explode(', ', $tags)); - - // headache, prioritizes tags - usort($tagArray, function ($a, $b) use ($priority) { - $priorityA = array_search($a, $priority); - $priorityB = array_search($b, $priority); - - $priorityA = ($priorityA === false) ? 0 : $priorityA; - $priorityB = ($priorityB === false) ? 0 : $priorityB; - - return $priorityB <=> $priorityA; - }); - - // Take the best tag and capitalize it - // $highestPriority = ucfirst($tagArray[0]); - $tagArray = array_slice($tagArray, 0, 1); - - // // Remove tags that are in the priority array - // $tagArray = array_filter($tagArray, function ($tag) use ($priority) { - // return !in_array($tag, $priority); - // }); - - // // Add the best tag to the beginning of the array - // array_unshift($tagArray, $highestPriority); - - $tags = ucfirst(implode(', ', $tagArray)); - - } else {$tags = "N/A";} - - - $insertQuery = "INSERT INTO newIssues (id, code, title, tags, type, updatedDate, createdDate) VALUES (?, ?, ?, ?, ?, ?, ?)"; - $stmt = $conn->prepare($insertQuery); - - $stmt->execute([$id, $code, $title, $tags, $type, $updatedDate, $createdDate]); - } catch (Exception $e) { - echo("Error inserting issue: $e"); - } - - - // Now download images :3 - try { - $cusaDir = "$dir/public_html/_images/CUSA/$code.avif"; - $hbDir = "$dir/public_html/_images/HB/$title.avif"; - - if ($type === "CUSA" && !file_exists($cusaDir)) { - $stmt = $conn->prepare('SELECT * FROM GameSkips WHERE code = :code COLLATE utf8mb4_general_ci'); // check if it needs to be skipped - $stmt->execute(['code' => $code]); - $result = $stmt->fetch(PDO::FETCH_ASSOC); - - if(!$result) - { - $key = hex2bin($tmdbHash); - $hash = strtoupper(hash_hmac("sha1", "{$code}_00", $key)); - $url = "https://tmdb.np.dl.playstation.net/tmdb2/{$code}_00_{$hash}/{$code}_00.json"; - $userAgent = "Mozilla/5.0 (PlayStation; PlayStation 4/11.00) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.4 Safari/605.1.15"; - $PS4header = stream_context_create(["http" => ["header" => "User-Agent: $userAgent\r\n"]]); // ps4 useragent cuz im silly - $response = file_get_contents($url, false, $PS4header); - $data = json_decode($response, true); - $url = $data['icons'][0]['icon']; - - usleep(rand(200000, 500000)); // delay between 200 - 500 ms - imageDownloader($url, $PS4header, $cusaDir); - } - } else if ($type === "HB" && !file_exists($hbDir)) { - $stmt = $conn->prepare('SELECT * FROM GameSkips WHERE code = :title COLLATE utf8mb4_general_ci'); // check if it needs to be skipped - $stmt->execute(['title' => $title]); - $result = $stmt->fetch(PDO::FETCH_ASSOC); - - if(!$result) { - $stmt = $homebrewDB->prepare('SELECT image FROM homebrews WHERE name = :title COLLATE NOCASE'); - $stmt->execute(['title' => $title]); - $url = $stmt->fetch()[0]; - - usleep(rand(200000, 500000)); // delay between 200 - 500 ms - imageDownloader($url, $HBheader, $hbDir); - } - } - } catch (Exception $e) { - $noImage++; - echo "No image found for: $title
"; - - // insert issue in database to be skipped. - $insertQuery = "INSERT INTO GameSkips (code) VALUES (:value1)"; - $stmt = $conn->prepare($insertQuery); - - if ($type === "CUSA") { - $stmt->execute(['value1' => $code]); - } else if ($type === "HB") { - $stmt->execute(['value1' => $title]); - } - } - } - } - } catch (Exception $e) { - echo $e; - } finally { - print("
$issuesProcessed issues processed!
"); - print("$noImage images not found!
"); - print("Issue processing, Image downloading and Database insertion task completed!
"); - } - - // Move newIssues table to normal issues table - try { - // Check the newIssues table - $result = $conn->query("SELECT COUNT(*) FROM newIssues"); - $newTotal = $result->fetchColumn(); - - $result2 = $conn->query("SELECT COUNT(*) FROM issues"); - $oldTotal = $result2->fetchColumn(); - - // remove 5% from old issue cound - $minNumber = $oldTotal - (0.05 * $oldTotal); - - if ($newTotal > $minNumber) { - // empty issues table - $conn->query("DELETE FROM issues"); - - // copy newIssues to issues table - $conn->query("INSERT INTO issues (id, code, title, tags, type, updatedDate, createdDate) SELECT id, code, title, tags, type, updatedDate, createdDate FROM newIssues"); - - // drop newIssues table - $conn->query("DROP TABLE IF EXISTS newIssues"); - } else { - print "
Something is wrong with newIssues, skipping update."; - } - - } catch (Exception $e) { - echo $e; - } finally {print("Database transfer task completed!
");} - - - $conn = null; - $homebrewDB = null; - echo "
" . round((microtime(true) - $startTime) * 1000, 2) . "ms"; - - } else { - http_response_code(404); - include("$dir/document_errors/404.html"); - } -?> \ No newline at end of file diff --git a/public_html/compatibility/app.js b/public_html/compatibility/app.js old mode 100644 new mode 100755 index de7f321..708006a --- a/public_html/compatibility/app.js +++ b/public_html/compatibility/app.js @@ -3,24 +3,17 @@ let avifSupport = false; let imageLoading = true; let oldestFilter = false; let datesButton = false; -let tagFilter = []; -let pageNumber = 1; +let statusFilter = []; +let currentPage = 1; + +let issuesPerPage = 20; +const codeRegex = /[a-zA-Z]{4}[0-9]{5}/; let Timer; let totalPages; -let totalTime; let totalIssues; let fancyJsonData; // :3 - -// Fetch html for footer and header -async function fetchHtml(path, target){ - fetch(path).then(response => response.text()).then(data => { - document.querySelector(target).innerHTML = data; - }).catch(console.error); -} - - // Check Avif Support console.log(`Hey there! I've implemented an avif support check to spare browsers like Edge from having a stroke :D!`); const avif = new Image(); @@ -32,7 +25,7 @@ avif.onload = function() { avif.onerror = function() { console.log('AVIF IS NOT SUPPORTED D:'); avifSupport = false; - // window.alert("Hey! Your browser doesnt support avif, avif is an image format that has low file sizes while having high quality images. You won't get any game images"); + // window.alert("Hey! Your browser doesn't support avif, avif is an image format that has low file sizes while having high quality images. You won't get any game images"); const iButton = document.getElementById('imageButton'); console.log(iButton); iButton.classList.add('selected'); @@ -42,10 +35,12 @@ avif.onerror = function() { -// game cards and stats handler and other onload stuff -document.addEventListener('DOMContentLoaded', function() { +// game cards and stats handler and other on-load stuff +document.addEventListener('DOMContentLoaded', async function () { + await init() + // + check cookies - const imageLoadingCookie = checkCookies("imageLoadingSetting", "true"); + const imageLoadingCookie = checkCookies("imageLoadingSetting", "true"); const datesSetting = checkCookies("datesSetting", "false"); if (imageLoadingCookie === "false") { @@ -62,124 +57,193 @@ document.addEventListener('DOMContentLoaded', function() { window.addEventListener('load', adjustScreenSize); window.addEventListener('resize', adjustScreenSize); - - // + fetch issues and set the tag bars - fetch('/_scripts/search.php?q=&stats') - .then(response => response.json()) - .then(jsonData => { - gameCardHandler(jsonData); - fancyJsonData = jsonData; - pageButtonHandler(); - totalPages = jsonData.info.pages; - totalTime = jsonData.info.time; - totalIssues = jsonData.info.issues; - console.log("\nCOMPATIBILITY STATS"); - - // stats & tag filter - jsonData.stats.forEach(stat => { - var tag = stat.tag; - var percent = stat.percent; - var element = document.getElementById(tag + 'Bar'); - var textElement = document.getElementById(tag + 'Info') - var parentElement = element.parentElement; - console.log(`${tag} = ${percent}% [${stat.count}]`); - element.style.width = percent + '%'; - textElement.textContent = percent + '% - ' + stat.count; - - parentElement.addEventListener('click', function() { - parentElement.classList.toggle('selected'); - tagFilter.includes(tag) ? tagFilter.splice(tagFilter.indexOf(tag), 1) : tagFilter.push(tag); - pageNumber = 1; - updateSearchResults(); - }); - }); - console.log("\n"); - }) - .catch(console.error); + // + fetch issues and set the tag bars + fetch('https://api.fpps4.net/database.json') + .then(response => response.json()) + .then(jsonData => { + fancyJsonData = jsonData; + + totalIssues = jsonData.length; + totalPages = Math.ceil(totalIssues / issuesPerPage); + + console.log("\nCOMPATIBILITY STATS"); + + let availableStatus = ['Nothing', 'Boots', 'Menus', 'Ingame', 'Playable']; + let totalPercentage = 0; + + let statusPercentages = []; + let statusCount = []; + + availableStatus.forEach(status => { + statusCount[status] = 0; // init tag count + + jsonData.forEach(issue => { + if (issue.status === status) { + statusCount[status]++; + } + }); + + let rawPercentage = parseFloat((statusCount[status] / totalIssues * 100).toFixed(2)); + + statusPercentages[status] = rawPercentage; + totalPercentage += rawPercentage; + }); + + // stats & tag filter + availableStatus.forEach(status => { + let percent = statusPercentages[status]; + let count = statusCount[status]; + let element = document.getElementById(status + 'Bar'); + let textElement = document.getElementById(status + 'Info') + let parentElement = element.parentElement; + console.log(`${status} = ${percent}% [${count}]`); + element.style.width = percent + '%'; + textElement.textContent = percent + '% - ' + count; + + parentElement.addEventListener('click', function () { + parentElement.classList.toggle('selected'); + statusFilter.includes(status) ? statusFilter.splice(statusFilter.indexOf(status), 1) : statusFilter.push(status); + currentPage = 1; + updateSearchResults(); + }); + }); + console.log("\n"); + + gameCardHandler(jsonData.slice(0, issuesPerPage)); //first 20 + pageButtonHandler(); + + }) + .catch(console.error); }); -// Header & Footer Load -fetchHtml("/_parts/navbar.html", "#header"); -fetchHtml("/_parts/footer.html", "#footer"); - - // Searching document.querySelector('#search').addEventListener('input', function() { - pageNumber = 1; + currentPage = 1; updateSearchResults(); }); -async function updateSearchResults() { +function updateSearchResults() { clearTimeout(Timer); const gameWrapper = document.querySelector('#gameWrapper'); - const searchQuery = document.querySelector('#search').value; - pageButtonHandler(); + const searchQuery = document.querySelector('#search').value.toLowerCase(); gameWrapper.querySelectorAll('.gameContainer').forEach(container => { const skeletonDiv = document.createElement('div'); skeletonDiv.classList.add('gameContainer', 'skeletonAnimation'); gameWrapper.replaceChild(skeletonDiv, container); }); - + Timer = setTimeout(() => { - fetch('/_scripts/search.php?q=' + searchQuery + '&tag=' + tagFilter + '&page=' + pageNumber + '&oldest=' + oldestFilter) - .then(response => response.json()) - .then(jsonData => { - fancyJsonData = jsonData; - gameCardHandler(jsonData); - }) - .catch(console.error); + let jsonData = []; + let isCodeSearch = codeRegex.test(searchQuery); + + fancyJsonData.forEach(issue => { + // id based searching + if (isCodeSearch && (issue.code.toLowerCase() !== searchQuery)) { + return; + + // title based searching + } else if (!isCodeSearch && !issue.title.toLowerCase().includes(searchQuery)) { + return; + } + + // filter tags + if (statusFilter.length > 0) { + let isGood = false; + + for (const status of statusFilter) { + if (status === issue.status) { + isGood = true; + break; + } + } + + if (isGood === false) { + return; + } + } + + jsonData.push(issue); + }); + + + let startSlice = (currentPage - 1) * issuesPerPage; // makes it start on 0 + let endSlice = startSlice + issuesPerPage; + + totalPages = Math.ceil(jsonData.length / issuesPerPage); + totalIssues = jsonData.length; + + let tempJsonData; + + if (oldestFilter === true) { + tempJsonData = jsonData.reverse(); + } else { + tempJsonData = jsonData; + } + + gameCardHandler(tempJsonData.slice(startSlice, endSlice)); + pageButtonHandler(); + }, 300); } // Game Card handler -async function gameCardHandler(jsonData) { +function gameCardHandler(jsonData) { const gameWrapper = document.getElementById("gameWrapper"); gameWrapper.innerHTML = ""; - jsonData.games.forEach(game => { + jsonData.forEach(issue => { // game image URL let imageSource = ""; - let imageText = "N/A"; - let imageTextSize = 1.38; + let imageText = "GAME"; + let imageTextSize = 1.25; + if (issue.title === "Sonic Time Twisted") { + console.log(issue.issue_type) + } + switch(true) { - case game.image && imageLoading && avifSupport && game.type === "HB": - imageSource = "/_images/HB/" + game.title + ".avif"; + case issue.image && imageLoading && avifSupport && issue.issue_type === "Homebrew": + imageSource = "https://api.fpps4.net/images/homebrew/" + issue.title + ".avif"; break; - case game.image && imageLoading && avifSupport: - imageSource = "/_images/CUSA/" + game.code +".avif"; + case issue.image && imageLoading && avifSupport: + imageSource = "https://api.fpps4.net/images/game/" + issue.code +".avif"; break; - case game.type === "SYS": + case issue.issue_type === "SystemFwUnknown" || issue.issue_type === "SystemFw505": imageText = "SYSTEM"; imageTextSize = 1.13; break } - if (game.type === "HB") { // needs to be applied to all homebrews + if (issue.issue_type === "Homebrew") { // needs to be applied to all homebrews imageText = "HOME
BREW"; imageTextSize = 1.25; + if (issue.code === "") { + issue.code = "HOMEBREW"; + } } - let imageTextEnabled = game.image && imageLoading && avifSupport ? "none" : "flex"; - + let imageTextEnabled = issue.image && imageLoading && avifSupport ? "none" : "flex"; + let updated = new Date(issue.updated).toLocaleDateString() + + // game cards const gameElementHTML = `
- +

${imageText}

- ${imageSource ? `${game.title} - ${game.code} game image` : "" } + ${imageSource ? `${issue.title} - ${issue.code} game image` : "" }
-
+
-

${game.title}

-

${game.code}

-

${game.tag}

+

${issue.title}

+

${issue.code}

+

${issue.status}

`; - + const tempContainer = document.createElement('div'); tempContainer.innerHTML = gameElementHTML; const gameContainer = tempContainer.querySelector('.gameContainer'); @@ -187,9 +251,9 @@ async function gameCardHandler(jsonData) { }); const statContainer = document.createElement('h4'); - const stat = `

${jsonData.info.issues} results in ${jsonData.info.time}ms

`; - statContainer.innerHTML = stat; + statContainer.innerHTML = `

${totalIssues} results

`; gameWrapper.appendChild(statContainer); + if (datesButton) { dateButtonHandler(); } @@ -207,9 +271,9 @@ async function gameCardHandler(jsonData) { image.style.transform = 'scale(1)'; }); }); + // functions in required.js updateFooter(); - LightModeIconChange(); } @@ -239,18 +303,18 @@ function sortButton(button) { } -async function imageButtonHandler() { +function imageButtonHandler() { if (imageLoading === false) { document.querySelectorAll(".gameImageText").forEach(imageText => { imageText.style.display = "flex"; }); } else { - gameCardHandler(fancyJsonData); + updateSearchResults(); } } -async function dateButtonHandler() { +function dateButtonHandler() { document.querySelectorAll(".gameCusa").forEach(element => { if (datesButton === true) { element.textContent = element.dataset.date; @@ -262,89 +326,81 @@ async function dateButtonHandler() { function pageButtonHandler(type) { // maybe make it handle everything in once? - const maxNumber = fancyJsonData.info.pages; + const maxNumber = totalPages; const searchBar = document.getElementById("search3"); const minButton = document.getElementById("pageBarMin"); const maxButton = document.getElementById("pageBarMax"); - if (pageNumber != maxNumber) { + maxButton.textContent = maxNumber; + + if (currentPage != maxNumber) { if (type === "forward") { - pageNumber += 1; + currentPage += 1; updateSearchResults(); } else if (type === "max") { - pageNumber = maxNumber; + currentPage = maxNumber; updateSearchResults(); } } - if (pageNumber != 1) { + if (currentPage != 1) { if (type === "back") { - pageNumber -= 1; + currentPage -= 1; updateSearchResults(); } else if (type === "min") { - pageNumber = 1; + currentPage = 1; updateSearchResults(); } } if (type === "input") { clearTimeout(Timer); - inputValue = parseInt(search3.value, 10); + Timer = setTimeout(() => { - + inputValue = parseInt(searchBar.value); console.log(inputValue); - pageNumber = inputValue; - updateSearchResults(); - searchBar.value = ""; - // if (inputValue > maxNumber) { - // pageNumber = inputValue; - // updateSearchResults(); - // searchBar.value = ""; - // } else { - // pageNumber = maxNumber; - // updateSearchResults(); - // searchBar.value = ""; - // } - }, 600); + + if (inputValue > maxNumber) { + inputValue = maxNumber; + } else if (inputValue < 1) { + inputValue = 1; + } + + currentPage = inputValue; + searchBar.placeholder = currentPage; + searchBar.value = ""; + updateSearchResults(); + }, 400); } - maxButton.textContent = maxNumber; - // searchBar.value = ""; - if (pageNumber != 1 && pageNumber != maxNumber) { - searchBar.placeholder = pageNumber; + + if (currentPage !== 1 && currentPage !== maxNumber) { + searchBar.placeholder = currentPage; searchBar.classList.add("selected"); maxButton.classList.remove("selected"); minButton.classList.remove("selected"); - } else if (pageNumber === 1) { + } else if (currentPage === 1) { minButton.classList.add("selected"); maxButton.classList.remove("selected"); searchBar.classList.remove("selected"); searchBar.placeholder = "..."; - searchBar.value = ""; - } else if (pageNumber === maxNumber) { + } else if (currentPage === maxNumber) { minButton.classList.remove("selected"); maxButton.classList.add("selected"); searchBar.classList.remove("selected"); searchBar.placeholder = "..."; - searchBar.value = ""; } } -search3.addEventListener("click", async function() { +search3.addEventListener("click", function() { if (search3.placeholder == '...') { - search3.placeholder = ''; + search3.placeholder = ''; } }); -search3.addEventListener("blur", async function() { +search3.addEventListener("blur", function() { if (search3.placeholder == '') { - search3.placeholder = '...'; + search3.placeholder = '...'; } -}); - -// search3.addEventListener('input', async function() { -// clearTimeout(Timer); -// inputValue = parseInt(search3.value, 10); -// console.log(inputValue); -// }); \ No newline at end of file +}); \ No newline at end of file diff --git a/public_html/compatibility/index.html b/public_html/compatibility/index.html old mode 100644 new mode 100755 index 40c816f..faa93e3 --- a/public_html/compatibility/index.html +++ b/public_html/compatibility/index.html @@ -8,7 +8,7 @@ - + @@ -16,25 +16,29 @@ - - - - - -