cloudflare
tcp/443 tcp/80 tcp/8443
Open service 172.66.44.104:443 · books-dbn.pages.dev
2026-01-08 10:35
HTTP/1.1 200 OK
Date: Thu, 08 Jan 2026 10:35:48 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 6513
Connection: close
Access-Control-Allow-Origin: *
Cache-Control: public, max-age=0, must-revalidate
ETag: "b94260f1d2f80892df36a15072902768"
Link: <https://fonts.googleapis.com>; rel="preconnect"
referrer-policy: strict-origin-when-cross-origin
x-content-type-options: nosniff
Vary: accept-encoding
Report-To: {"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=c99D%2Bopx2iYD58ROzWdIfZGQ9R9mVDtL%2BXV%2FRQZdpiJyunklF9bszICJ56JnzQnNEvn6LuZN4Db94QLlHSfJPZbPLHPw55Ihgb4A03Pu9raziV4%3D"}]}
Nel: {"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}
Server: cloudflare
CF-RAY: 9bab0cda3ea4ce11-SIN
alt-svc: h3=":443"; ma=86400
Page title: FREE DOWNLOAD
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="p:domain_verify" content="3629a4a7120f28c8cabeb21ec828d4c7"/>
<title>FREE DOWNLOAD</title>
<link rel="stylesheet" href="/style.css" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600;700&display=swap"
rel="stylesheet"
/>
</head>
<body>
<header class="site-header">
<h1>FREE DOWNLOAD</h1>
<p>HERE ALL FREE FOR YOU</p>
</header>
<main>
<section id="posts-grid" class="posts-grid">
<p class="loading-state">Loading recent posts...</p>
</section>
<nav id="pagination-container" class="pagination-container"></nav>
</main>
<script>
document.addEventListener("DOMContentLoaded", () => {
const postsGrid = document.getElementById("posts-grid");
const paginationContainer =
document.getElementById("pagination-container");
function setupObserver() {
const hiddenElements = document.querySelectorAll(".hidden-card");
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
entry.target.classList.add("show-card");
observer.unobserve(entry.target);
}
});
},
{ threshold: 0.1 }
);
hiddenElements.forEach((el) => observer.observe(el));
}
/**
* [MODIFIED] Renders pagination buttons
*/
function renderPagination(totalPages, currentPage) {
paginationContainer.innerHTML = "";
if (totalPages <= 1) return; // No pagination if only 1 page
let html = "";
const pageWindow = 2; // How many pages to show around current page
// Previous Button
html += `<button class="page-btn" data-page="${
currentPage - 1
}" ${currentPage === 1 ? "disabled" : ""}>« Prev</button>`;
// Page numbers
for (let i = 1; i <= totalPages; i++) {
// Logic to show "..."
if (
i === 1 ||
i === totalPages ||
(i >= currentPage - pageWindow && i <= currentPage + pageWindow)
) {
html += `<button class="page-btn ${
i === currentPage ? "active" : ""
}" data-page="${i}">${i}</button>`;
} else if (
i === currentPage - pageWindow - 1 ||
i === currentPage + pageWindow + 1
) {
html += `<span class="page-dots">...</span>`;
}
}
// Next Button
html += `<button class="page-btn" data-page="${
currentPage + 1
}" ${currentPage === totalPages ? "disabled" : ""}>Next »</button>`;
paginationContainer.innerHTML = html;
}
/**
* [MODIFIED] loadPosts now accepts a page number
*/
async function loadPosts(page = 1) {
// Show loading state
postsGrid.innerHTML =
'<p class="loading-state">Loading recent posts...</p>';
paginationContainer.innerHTML = ""; // Clear old pagination
try {
// [MODIFIED] Fetch with page query
const response = await fetch(`/api/buku?page=${page}`);
if (!response.ok) {
let errorMessage;
const errorBody = await response.text();
try {
const errJson = JSON.parse(errorBody);
errorMessage = errJson.error || JSON.stringify(errJson);
} catch (e) {
errorMessage = errorBody;
}
throw new Error(errorMessage);
}
// [MOD
Open service 2606:4700:310c::ac42:2c68:80 · books-dbn.pages.dev
2026-01-08 10:35
HTTP/1.1 301 Moved Permanently
Date: Thu, 08 Jan 2026 10:35:47 GMT
Content-Length: 0
Connection: close
Location: https://books-dbn.pages.dev/
Report-To: {"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=HoaaKrHUCLe5dMTREV2o18hJvZ%2FYUm5aY81MGuZ87UsLyKIBmn2peTrkKE5UAhGNIiXUSwpo6stS%2BCzFBQY4FpZ5rrQTGMxLTQh%2BANDjmP5MNygR%2BJ%2FvcSsAWPevw68%3D"}]}
Nel: {"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}
Server: cloudflare
CF-RAY: 9bab0cd5ba00c48a-YYZ
alt-svc: h3=":443"; ma=86400
Open service 172.66.47.152:8443 · books-dbn.pages.dev
2026-01-08 10:35
HTTP/1.1 200 OK
Date: Thu, 08 Jan 2026 10:35:47 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 6513
Connection: close
Access-Control-Allow-Origin: *
Cache-Control: public, max-age=0, must-revalidate
ETag: "b94260f1d2f80892df36a15072902768"
Link: <https://fonts.googleapis.com>; rel="preconnect"
referrer-policy: strict-origin-when-cross-origin
x-content-type-options: nosniff
Vary: accept-encoding
Report-To: {"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=SOvQ7U5HTu5mHEOHapgtM0VRa9wZpOeDFlApTy0X%2FVdITiV4yvFEqGYF1Ir4r%2B1r0nDvOb97WfFHneNJ5dm6zKUHFmaJ7mOkmKmtH98C%2FZXgbdA%3D"}]}
Nel: {"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}
Server: cloudflare
CF-RAY: 9bab0cd5fde86d93-YYZ
alt-svc: h3=":8443"; ma=86400
Page title: FREE DOWNLOAD
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="p:domain_verify" content="3629a4a7120f28c8cabeb21ec828d4c7"/>
<title>FREE DOWNLOAD</title>
<link rel="stylesheet" href="/style.css" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600;700&display=swap"
rel="stylesheet"
/>
</head>
<body>
<header class="site-header">
<h1>FREE DOWNLOAD</h1>
<p>HERE ALL FREE FOR YOU</p>
</header>
<main>
<section id="posts-grid" class="posts-grid">
<p class="loading-state">Loading recent posts...</p>
</section>
<nav id="pagination-container" class="pagination-container"></nav>
</main>
<script>
document.addEventListener("DOMContentLoaded", () => {
const postsGrid = document.getElementById("posts-grid");
const paginationContainer =
document.getElementById("pagination-container");
function setupObserver() {
const hiddenElements = document.querySelectorAll(".hidden-card");
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
entry.target.classList.add("show-card");
observer.unobserve(entry.target);
}
});
},
{ threshold: 0.1 }
);
hiddenElements.forEach((el) => observer.observe(el));
}
/**
* [MODIFIED] Renders pagination buttons
*/
function renderPagination(totalPages, currentPage) {
paginationContainer.innerHTML = "";
if (totalPages <= 1) return; // No pagination if only 1 page
let html = "";
const pageWindow = 2; // How many pages to show around current page
// Previous Button
html += `<button class="page-btn" data-page="${
currentPage - 1
}" ${currentPage === 1 ? "disabled" : ""}>« Prev</button>`;
// Page numbers
for (let i = 1; i <= totalPages; i++) {
// Logic to show "..."
if (
i === 1 ||
i === totalPages ||
(i >= currentPage - pageWindow && i <= currentPage + pageWindow)
) {
html += `<button class="page-btn ${
i === currentPage ? "active" : ""
}" data-page="${i}">${i}</button>`;
} else if (
i === currentPage - pageWindow - 1 ||
i === currentPage + pageWindow + 1
) {
html += `<span class="page-dots">...</span>`;
}
}
// Next Button
html += `<button class="page-btn" data-page="${
currentPage + 1
}" ${currentPage === totalPages ? "disabled" : ""}>Next »</button>`;
paginationContainer.innerHTML = html;
}
/**
* [MODIFIED] loadPosts now accepts a page number
*/
async function loadPosts(page = 1) {
// Show loading state
postsGrid.innerHTML =
'<p class="loading-state">Loading recent posts...</p>';
paginationContainer.innerHTML = ""; // Clear old pagination
try {
// [MODIFIED] Fetch with page query
const response = await fetch(`/api/buku?page=${page}`);
if (!response.ok) {
let errorMessage;
const errorBody = await response.text();
try {
const errJson = JSON.parse(errorBody);
errorMessage = errJson.error || JSON.stringify(errJson);
} catch (e) {
errorMessage = errorBody;
}
throw new Error(errorMessage);
}
// [MOD
Open service 2606:4700:310c::ac42:2f98:80 · books-dbn.pages.dev
2026-01-08 10:35
HTTP/1.1 301 Moved Permanently
Date: Thu, 08 Jan 2026 10:35:47 GMT
Content-Length: 0
Connection: close
Location: https://books-dbn.pages.dev/
Report-To: {"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=%2B56reFkAV6uh9%2FaAm%2BvaJgwV543xjDLNGzG1WoHOGqcINVk0agcUPfpvqNGAxkPMgW%2F8yEEUkfsPxmoGPRJfcCW0EoKPEKCajGiw5FVrDe1OAlzQhEq4khmcbAG5VNU%3D"}]}
Nel: {"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}
Server: cloudflare
CF-RAY: 9bab0cd4ff159763-FRA
alt-svc: h3=":443"; ma=86400
Open service 2606:4700:310c::ac42:2f98:443 · books-dbn.pages.dev
2026-01-08 10:35
HTTP/1.1 200 OK
Date: Thu, 08 Jan 2026 10:35:47 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 6513
Connection: close
Access-Control-Allow-Origin: *
Cache-Control: public, max-age=0, must-revalidate
ETag: "b94260f1d2f80892df36a15072902768"
Link: <https://fonts.googleapis.com>; rel="preconnect"
referrer-policy: strict-origin-when-cross-origin
x-content-type-options: nosniff
Vary: accept-encoding
Report-To: {"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=NURDOvcjuUAK71AGrkG5QNrXwyT4XvWYJfRqTNZoUlj763cnXxraENEyfspLL2ioELr93cleti%2BKzWsJR430FFX8E7gUG6Oex5q5j5Vde%2BdONLCtriUOINy7OSXV3JY%3D"}]}
Nel: {"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}
Server: cloudflare
CF-RAY: 9bab0cd56c2e3837-FRA
alt-svc: h3=":443"; ma=86400
Page title: FREE DOWNLOAD
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="p:domain_verify" content="3629a4a7120f28c8cabeb21ec828d4c7"/>
<title>FREE DOWNLOAD</title>
<link rel="stylesheet" href="/style.css" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600;700&display=swap"
rel="stylesheet"
/>
</head>
<body>
<header class="site-header">
<h1>FREE DOWNLOAD</h1>
<p>HERE ALL FREE FOR YOU</p>
</header>
<main>
<section id="posts-grid" class="posts-grid">
<p class="loading-state">Loading recent posts...</p>
</section>
<nav id="pagination-container" class="pagination-container"></nav>
</main>
<script>
document.addEventListener("DOMContentLoaded", () => {
const postsGrid = document.getElementById("posts-grid");
const paginationContainer =
document.getElementById("pagination-container");
function setupObserver() {
const hiddenElements = document.querySelectorAll(".hidden-card");
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
entry.target.classList.add("show-card");
observer.unobserve(entry.target);
}
});
},
{ threshold: 0.1 }
);
hiddenElements.forEach((el) => observer.observe(el));
}
/**
* [MODIFIED] Renders pagination buttons
*/
function renderPagination(totalPages, currentPage) {
paginationContainer.innerHTML = "";
if (totalPages <= 1) return; // No pagination if only 1 page
let html = "";
const pageWindow = 2; // How many pages to show around current page
// Previous Button
html += `<button class="page-btn" data-page="${
currentPage - 1
}" ${currentPage === 1 ? "disabled" : ""}>« Prev</button>`;
// Page numbers
for (let i = 1; i <= totalPages; i++) {
// Logic to show "..."
if (
i === 1 ||
i === totalPages ||
(i >= currentPage - pageWindow && i <= currentPage + pageWindow)
) {
html += `<button class="page-btn ${
i === currentPage ? "active" : ""
}" data-page="${i}">${i}</button>`;
} else if (
i === currentPage - pageWindow - 1 ||
i === currentPage + pageWindow + 1
) {
html += `<span class="page-dots">...</span>`;
}
}
// Next Button
html += `<button class="page-btn" data-page="${
currentPage + 1
}" ${currentPage === totalPages ? "disabled" : ""}>Next »</button>`;
paginationContainer.innerHTML = html;
}
/**
* [MODIFIED] loadPosts now accepts a page number
*/
async function loadPosts(page = 1) {
// Show loading state
postsGrid.innerHTML =
'<p class="loading-state">Loading recent posts...</p>';
paginationContainer.innerHTML = ""; // Clear old pagination
try {
// [MODIFIED] Fetch with page query
const response = await fetch(`/api/buku?page=${page}`);
if (!response.ok) {
let errorMessage;
const errorBody = await response.text();
try {
const errJson = JSON.parse(errorBody);
errorMessage = errJson.error || JSON.stringify(errJson);
} catch (e) {
errorMessage = errorBody;
}
throw new Error(errorMessage);
}
// [MOD
Open service 2606:4700:310c::ac42:2f98:8443 · books-dbn.pages.dev
2026-01-08 10:35
HTTP/1.1 200 OK
Date: Thu, 08 Jan 2026 10:35:47 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 6513
Connection: close
Access-Control-Allow-Origin: *
Cache-Control: public, max-age=0, must-revalidate
ETag: "b94260f1d2f80892df36a15072902768"
Link: <https://fonts.googleapis.com>; rel="preconnect"
referrer-policy: strict-origin-when-cross-origin
x-content-type-options: nosniff
Vary: accept-encoding
Report-To: {"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=v3l%2BVkIuVMInKJSujTiCgA3Ecxk7Vje3PHimMUQ79qX64w5gphKbK7CqTLEBfwpA8ImDzFQUCZlHm5N0xcJg8WA%2BJV7KW5kkJessob28F8LQ208rFghMTVnSDb%2BM4e4%3D"}]}
Nel: {"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}
Server: cloudflare
CF-RAY: 9bab0cd5ce4b77b7-LHR
alt-svc: h3=":8443"; ma=86400
Page title: FREE DOWNLOAD
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="p:domain_verify" content="3629a4a7120f28c8cabeb21ec828d4c7"/>
<title>FREE DOWNLOAD</title>
<link rel="stylesheet" href="/style.css" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600;700&display=swap"
rel="stylesheet"
/>
</head>
<body>
<header class="site-header">
<h1>FREE DOWNLOAD</h1>
<p>HERE ALL FREE FOR YOU</p>
</header>
<main>
<section id="posts-grid" class="posts-grid">
<p class="loading-state">Loading recent posts...</p>
</section>
<nav id="pagination-container" class="pagination-container"></nav>
</main>
<script>
document.addEventListener("DOMContentLoaded", () => {
const postsGrid = document.getElementById("posts-grid");
const paginationContainer =
document.getElementById("pagination-container");
function setupObserver() {
const hiddenElements = document.querySelectorAll(".hidden-card");
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
entry.target.classList.add("show-card");
observer.unobserve(entry.target);
}
});
},
{ threshold: 0.1 }
);
hiddenElements.forEach((el) => observer.observe(el));
}
/**
* [MODIFIED] Renders pagination buttons
*/
function renderPagination(totalPages, currentPage) {
paginationContainer.innerHTML = "";
if (totalPages <= 1) return; // No pagination if only 1 page
let html = "";
const pageWindow = 2; // How many pages to show around current page
// Previous Button
html += `<button class="page-btn" data-page="${
currentPage - 1
}" ${currentPage === 1 ? "disabled" : ""}>« Prev</button>`;
// Page numbers
for (let i = 1; i <= totalPages; i++) {
// Logic to show "..."
if (
i === 1 ||
i === totalPages ||
(i >= currentPage - pageWindow && i <= currentPage + pageWindow)
) {
html += `<button class="page-btn ${
i === currentPage ? "active" : ""
}" data-page="${i}">${i}</button>`;
} else if (
i === currentPage - pageWindow - 1 ||
i === currentPage + pageWindow + 1
) {
html += `<span class="page-dots">...</span>`;
}
}
// Next Button
html += `<button class="page-btn" data-page="${
currentPage + 1
}" ${currentPage === totalPages ? "disabled" : ""}>Next »</button>`;
paginationContainer.innerHTML = html;
}
/**
* [MODIFIED] loadPosts now accepts a page number
*/
async function loadPosts(page = 1) {
// Show loading state
postsGrid.innerHTML =
'<p class="loading-state">Loading recent posts...</p>';
paginationContainer.innerHTML = ""; // Clear old pagination
try {
// [MODIFIED] Fetch with page query
const response = await fetch(`/api/buku?page=${page}`);
if (!response.ok) {
let errorMessage;
const errorBody = await response.text();
try {
const errJson = JSON.parse(errorBody);
errorMessage = errJson.error || JSON.stringify(errJson);
} catch (e) {
errorMessage = errorBody;
}
throw new Error(errorMessage);
}
// [MOD
Open service 172.66.44.104:80 · books-dbn.pages.dev
2026-01-08 10:35
HTTP/1.1 301 Moved Permanently
Date: Thu, 08 Jan 2026 10:35:47 GMT
Content-Length: 0
Connection: close
Location: https://books-dbn.pages.dev/
Report-To: {"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=Smb0y64R%2FMD%2F424TGfUwyIZv9n2pOXdWelYLcVb0sjdt4b9IeiaDSZuDs%2BnkUTFVzmGdU9XhRRWwFW%2FsBAilPaZ8wv6zvAyY49Y9ek7jOLr55DY%3D"}]}
Nel: {"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}
Server: cloudflare
CF-RAY: 9bab0cd51f6fb785-EWR
alt-svc: h3=":443"; ma=86400
Open service 172.66.47.152:443 · books-dbn.pages.dev
2026-01-08 10:35
HTTP/1.1 200 OK
Date: Thu, 08 Jan 2026 10:35:47 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 6513
Connection: close
Access-Control-Allow-Origin: *
Cache-Control: public, max-age=0, must-revalidate
ETag: "b94260f1d2f80892df36a15072902768"
Link: <https://fonts.googleapis.com>; rel="preconnect"
referrer-policy: strict-origin-when-cross-origin
x-content-type-options: nosniff
Vary: accept-encoding
Report-To: {"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=2SadCcgBFO4idDOQ9%2FiWrMKbueftUnkT%2B1Yz9TkkBAsAJNOYVL4OxYXEjMYzkk%2BS%2FnzdHe4w1GCjQAZl1hIIKXmWdQd40m5E3khvPD3IXrOwd3s%3D"}]}
Nel: {"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}
Server: cloudflare
CF-RAY: 9bab0cd50a93970a-AMS
alt-svc: h3=":443"; ma=86400
Page title: FREE DOWNLOAD
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="p:domain_verify" content="3629a4a7120f28c8cabeb21ec828d4c7"/>
<title>FREE DOWNLOAD</title>
<link rel="stylesheet" href="/style.css" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600;700&display=swap"
rel="stylesheet"
/>
</head>
<body>
<header class="site-header">
<h1>FREE DOWNLOAD</h1>
<p>HERE ALL FREE FOR YOU</p>
</header>
<main>
<section id="posts-grid" class="posts-grid">
<p class="loading-state">Loading recent posts...</p>
</section>
<nav id="pagination-container" class="pagination-container"></nav>
</main>
<script>
document.addEventListener("DOMContentLoaded", () => {
const postsGrid = document.getElementById("posts-grid");
const paginationContainer =
document.getElementById("pagination-container");
function setupObserver() {
const hiddenElements = document.querySelectorAll(".hidden-card");
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
entry.target.classList.add("show-card");
observer.unobserve(entry.target);
}
});
},
{ threshold: 0.1 }
);
hiddenElements.forEach((el) => observer.observe(el));
}
/**
* [MODIFIED] Renders pagination buttons
*/
function renderPagination(totalPages, currentPage) {
paginationContainer.innerHTML = "";
if (totalPages <= 1) return; // No pagination if only 1 page
let html = "";
const pageWindow = 2; // How many pages to show around current page
// Previous Button
html += `<button class="page-btn" data-page="${
currentPage - 1
}" ${currentPage === 1 ? "disabled" : ""}>« Prev</button>`;
// Page numbers
for (let i = 1; i <= totalPages; i++) {
// Logic to show "..."
if (
i === 1 ||
i === totalPages ||
(i >= currentPage - pageWindow && i <= currentPage + pageWindow)
) {
html += `<button class="page-btn ${
i === currentPage ? "active" : ""
}" data-page="${i}">${i}</button>`;
} else if (
i === currentPage - pageWindow - 1 ||
i === currentPage + pageWindow + 1
) {
html += `<span class="page-dots">...</span>`;
}
}
// Next Button
html += `<button class="page-btn" data-page="${
currentPage + 1
}" ${currentPage === totalPages ? "disabled" : ""}>Next »</button>`;
paginationContainer.innerHTML = html;
}
/**
* [MODIFIED] loadPosts now accepts a page number
*/
async function loadPosts(page = 1) {
// Show loading state
postsGrid.innerHTML =
'<p class="loading-state">Loading recent posts...</p>';
paginationContainer.innerHTML = ""; // Clear old pagination
try {
// [MODIFIED] Fetch with page query
const response = await fetch(`/api/buku?page=${page}`);
if (!response.ok) {
let errorMessage;
const errorBody = await response.text();
try {
const errJson = JSON.parse(errorBody);
errorMessage = errJson.error || JSON.stringify(errJson);
} catch (e) {
errorMessage = errorBody;
}
throw new Error(errorMessage);
}
// [MOD
Open service 172.66.47.152:80 · books-dbn.pages.dev
2026-01-08 10:35
HTTP/1.1 301 Moved Permanently
Date: Thu, 08 Jan 2026 10:35:47 GMT
Content-Length: 0
Connection: close
Location: https://books-dbn.pages.dev/
Report-To: {"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=M6ak%2BuLIIPEd16fgsrAwWrxSwuWFUDaOks3sTylAdS%2Fw8mJljKuL0dybgnh5uuPJcC%2FQ4Su801TPNN9GxlwJoq%2FSIA4gD%2FZRTUeYQESRfzJkyM0%3D"}]}
Nel: {"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}
Server: cloudflare
CF-RAY: 9bab0cd4cb7f41ff-EWR
alt-svc: h3=":443"; ma=86400
Open service 172.66.44.104:8443 · books-dbn.pages.dev
2026-01-08 10:35
HTTP/1.1 200 OK
Date: Thu, 08 Jan 2026 10:35:47 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 6513
Connection: close
Access-Control-Allow-Origin: *
Cache-Control: public, max-age=0, must-revalidate
ETag: "b94260f1d2f80892df36a15072902768"
Link: <https://fonts.googleapis.com>; rel="preconnect"
referrer-policy: strict-origin-when-cross-origin
x-content-type-options: nosniff
Vary: accept-encoding
Report-To: {"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=e%2FTIo6DRNOeQdy7rQClViUbg7VioGsW58%2FKQ9KgeJXtS1JsCfCn4Rmiiuo69DUvxsBEx1bhRI0HfNcYnlVJC19eny%2F67N5CRLtW%2Bt1QB%2FEnGLsU%3D"}]}
Nel: {"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}
Server: cloudflare
CF-RAY: 9bab0cd4a8757fa0-FRA
alt-svc: h3=":8443"; ma=86400
Page title: FREE DOWNLOAD
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="p:domain_verify" content="3629a4a7120f28c8cabeb21ec828d4c7"/>
<title>FREE DOWNLOAD</title>
<link rel="stylesheet" href="/style.css" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600;700&display=swap"
rel="stylesheet"
/>
</head>
<body>
<header class="site-header">
<h1>FREE DOWNLOAD</h1>
<p>HERE ALL FREE FOR YOU</p>
</header>
<main>
<section id="posts-grid" class="posts-grid">
<p class="loading-state">Loading recent posts...</p>
</section>
<nav id="pagination-container" class="pagination-container"></nav>
</main>
<script>
document.addEventListener("DOMContentLoaded", () => {
const postsGrid = document.getElementById("posts-grid");
const paginationContainer =
document.getElementById("pagination-container");
function setupObserver() {
const hiddenElements = document.querySelectorAll(".hidden-card");
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
entry.target.classList.add("show-card");
observer.unobserve(entry.target);
}
});
},
{ threshold: 0.1 }
);
hiddenElements.forEach((el) => observer.observe(el));
}
/**
* [MODIFIED] Renders pagination buttons
*/
function renderPagination(totalPages, currentPage) {
paginationContainer.innerHTML = "";
if (totalPages <= 1) return; // No pagination if only 1 page
let html = "";
const pageWindow = 2; // How many pages to show around current page
// Previous Button
html += `<button class="page-btn" data-page="${
currentPage - 1
}" ${currentPage === 1 ? "disabled" : ""}>« Prev</button>`;
// Page numbers
for (let i = 1; i <= totalPages; i++) {
// Logic to show "..."
if (
i === 1 ||
i === totalPages ||
(i >= currentPage - pageWindow && i <= currentPage + pageWindow)
) {
html += `<button class="page-btn ${
i === currentPage ? "active" : ""
}" data-page="${i}">${i}</button>`;
} else if (
i === currentPage - pageWindow - 1 ||
i === currentPage + pageWindow + 1
) {
html += `<span class="page-dots">...</span>`;
}
}
// Next Button
html += `<button class="page-btn" data-page="${
currentPage + 1
}" ${currentPage === totalPages ? "disabled" : ""}>Next »</button>`;
paginationContainer.innerHTML = html;
}
/**
* [MODIFIED] loadPosts now accepts a page number
*/
async function loadPosts(page = 1) {
// Show loading state
postsGrid.innerHTML =
'<p class="loading-state">Loading recent posts...</p>';
paginationContainer.innerHTML = ""; // Clear old pagination
try {
// [MODIFIED] Fetch with page query
const response = await fetch(`/api/buku?page=${page}`);
if (!response.ok) {
let errorMessage;
const errorBody = await response.text();
try {
const errJson = JSON.parse(errorBody);
errorMessage = errJson.error || JSON.stringify(errJson);
} catch (e) {
errorMessage = errorBody;
}
throw new Error(errorMessage);
}
// [MOD
Open service 2606:4700:310c::ac42:2c68:8443 · books-dbn.pages.dev
2026-01-08 10:35
HTTP/1.1 200 OK
Date: Thu, 08 Jan 2026 10:35:48 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 6513
Connection: close
Access-Control-Allow-Origin: *
Cache-Control: public, max-age=0, must-revalidate
ETag: "b94260f1d2f80892df36a15072902768"
Link: <https://fonts.googleapis.com>; rel="preconnect"
referrer-policy: strict-origin-when-cross-origin
x-content-type-options: nosniff
Vary: accept-encoding
Report-To: {"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=UubLf6PwTXvBi%2BpQLX786JTGUMH8cqeDkE5tfACBYlBNSTyt6eqbFO02nbGNiDrKcEaeXBkFcqkBtWqdipm0tK%2BpeOwMry82JBheab7%2FUYE3Zkz0bazUw2z6RpHoffc%3D"}]}
Nel: {"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}
Server: cloudflare
CF-RAY: 9bab0cd8e9181712-BLR
alt-svc: h3=":8443"; ma=86400
Page title: FREE DOWNLOAD
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="p:domain_verify" content="3629a4a7120f28c8cabeb21ec828d4c7"/>
<title>FREE DOWNLOAD</title>
<link rel="stylesheet" href="/style.css" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600;700&display=swap"
rel="stylesheet"
/>
</head>
<body>
<header class="site-header">
<h1>FREE DOWNLOAD</h1>
<p>HERE ALL FREE FOR YOU</p>
</header>
<main>
<section id="posts-grid" class="posts-grid">
<p class="loading-state">Loading recent posts...</p>
</section>
<nav id="pagination-container" class="pagination-container"></nav>
</main>
<script>
document.addEventListener("DOMContentLoaded", () => {
const postsGrid = document.getElementById("posts-grid");
const paginationContainer =
document.getElementById("pagination-container");
function setupObserver() {
const hiddenElements = document.querySelectorAll(".hidden-card");
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
entry.target.classList.add("show-card");
observer.unobserve(entry.target);
}
});
},
{ threshold: 0.1 }
);
hiddenElements.forEach((el) => observer.observe(el));
}
/**
* [MODIFIED] Renders pagination buttons
*/
function renderPagination(totalPages, currentPage) {
paginationContainer.innerHTML = "";
if (totalPages <= 1) return; // No pagination if only 1 page
let html = "";
const pageWindow = 2; // How many pages to show around current page
// Previous Button
html += `<button class="page-btn" data-page="${
currentPage - 1
}" ${currentPage === 1 ? "disabled" : ""}>« Prev</button>`;
// Page numbers
for (let i = 1; i <= totalPages; i++) {
// Logic to show "..."
if (
i === 1 ||
i === totalPages ||
(i >= currentPage - pageWindow && i <= currentPage + pageWindow)
) {
html += `<button class="page-btn ${
i === currentPage ? "active" : ""
}" data-page="${i}">${i}</button>`;
} else if (
i === currentPage - pageWindow - 1 ||
i === currentPage + pageWindow + 1
) {
html += `<span class="page-dots">...</span>`;
}
}
// Next Button
html += `<button class="page-btn" data-page="${
currentPage + 1
}" ${currentPage === totalPages ? "disabled" : ""}>Next »</button>`;
paginationContainer.innerHTML = html;
}
/**
* [MODIFIED] loadPosts now accepts a page number
*/
async function loadPosts(page = 1) {
// Show loading state
postsGrid.innerHTML =
'<p class="loading-state">Loading recent posts...</p>';
paginationContainer.innerHTML = ""; // Clear old pagination
try {
// [MODIFIED] Fetch with page query
const response = await fetch(`/api/buku?page=${page}`);
if (!response.ok) {
let errorMessage;
const errorBody = await response.text();
try {
const errJson = JSON.parse(errorBody);
errorMessage = errJson.error || JSON.stringify(errJson);
} catch (e) {
errorMessage = errorBody;
}
throw new Error(errorMessage);
}
// [MOD
Open service 2606:4700:310c::ac42:2c68:443 · books-dbn.pages.dev
2026-01-08 10:35
HTTP/1.1 200 OK
Date: Thu, 08 Jan 2026 10:35:48 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 6513
Connection: close
Access-Control-Allow-Origin: *
Cache-Control: public, max-age=0, must-revalidate
ETag: "b94260f1d2f80892df36a15072902768"
Link: <https://fonts.googleapis.com>; rel="preconnect"
referrer-policy: strict-origin-when-cross-origin
x-content-type-options: nosniff
Vary: accept-encoding
Report-To: {"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=uRZUbqzEO7%2BTEZ%2FGSloyplJRB7O%2FWs%2BLOZ8sNxEZ3WsR0P85DvjmD3JIVcmyNjyDeyIxRRvW7ytB54fZ8YqCYFYTtckNaC%2F5ygd48j0hwBFAWfMnDJz2LJ40DhmNk5o%3D"}]}
Nel: {"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}
Server: cloudflare
CF-RAY: 9bab0cd8d93d3585-BLR
alt-svc: h3=":443"; ma=86400
Page title: FREE DOWNLOAD
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="p:domain_verify" content="3629a4a7120f28c8cabeb21ec828d4c7"/>
<title>FREE DOWNLOAD</title>
<link rel="stylesheet" href="/style.css" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600;700&display=swap"
rel="stylesheet"
/>
</head>
<body>
<header class="site-header">
<h1>FREE DOWNLOAD</h1>
<p>HERE ALL FREE FOR YOU</p>
</header>
<main>
<section id="posts-grid" class="posts-grid">
<p class="loading-state">Loading recent posts...</p>
</section>
<nav id="pagination-container" class="pagination-container"></nav>
</main>
<script>
document.addEventListener("DOMContentLoaded", () => {
const postsGrid = document.getElementById("posts-grid");
const paginationContainer =
document.getElementById("pagination-container");
function setupObserver() {
const hiddenElements = document.querySelectorAll(".hidden-card");
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
entry.target.classList.add("show-card");
observer.unobserve(entry.target);
}
});
},
{ threshold: 0.1 }
);
hiddenElements.forEach((el) => observer.observe(el));
}
/**
* [MODIFIED] Renders pagination buttons
*/
function renderPagination(totalPages, currentPage) {
paginationContainer.innerHTML = "";
if (totalPages <= 1) return; // No pagination if only 1 page
let html = "";
const pageWindow = 2; // How many pages to show around current page
// Previous Button
html += `<button class="page-btn" data-page="${
currentPage - 1
}" ${currentPage === 1 ? "disabled" : ""}>« Prev</button>`;
// Page numbers
for (let i = 1; i <= totalPages; i++) {
// Logic to show "..."
if (
i === 1 ||
i === totalPages ||
(i >= currentPage - pageWindow && i <= currentPage + pageWindow)
) {
html += `<button class="page-btn ${
i === currentPage ? "active" : ""
}" data-page="${i}">${i}</button>`;
} else if (
i === currentPage - pageWindow - 1 ||
i === currentPage + pageWindow + 1
) {
html += `<span class="page-dots">...</span>`;
}
}
// Next Button
html += `<button class="page-btn" data-page="${
currentPage + 1
}" ${currentPage === totalPages ? "disabled" : ""}>Next »</button>`;
paginationContainer.innerHTML = html;
}
/**
* [MODIFIED] loadPosts now accepts a page number
*/
async function loadPosts(page = 1) {
// Show loading state
postsGrid.innerHTML =
'<p class="loading-state">Loading recent posts...</p>';
paginationContainer.innerHTML = ""; // Clear old pagination
try {
// [MODIFIED] Fetch with page query
const response = await fetch(`/api/buku?page=${page}`);
if (!response.ok) {
let errorMessage;
const errorBody = await response.text();
try {
const errJson = JSON.parse(errorBody);
errorMessage = errJson.error || JSON.stringify(errJson);
} catch (e) {
errorMessage = errorBody;
}
throw new Error(errorMessage);
}
// [MOD