-
-
Notifications
You must be signed in to change notification settings - Fork 39
Homepage AJAX quick-search, shared header/footer, and sitemap automation (SEO + UX improvements) #41
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Homepage AJAX quick-search, shared header/footer, and sitemap automation (SEO + UX improvements) #41
Changes from 4 commits
1cb0814
e7c3f81
775fec2
a60117f
c333b62
d27ea4e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,71 @@ | ||
| (function () { | ||
| const headerTarget = document.getElementById('shared-header'); | ||
| const footerTarget = document.getElementById('shared-footer'); | ||
|
|
||
| const headerHtml = ` | ||
| <header class="bg-gray-800 p-4 shadow-md"> | ||
| <div class="container mx-auto flex flex-row justify-between items-center"> | ||
| <nav class="flex items-center space-x-4"> | ||
| <a href="/" class="hover:text-gray-300 p-4" aria-label="خانه"><i class="fas fa-home"></i></a> | ||
| <a href="/watchlist" class="hover:text-gray-300" aria-label="واچلیست"><i class="fas fa-bookmark"></i></a> | ||
| <a href="/search" class="hover:text-gray-300" aria-label="جستجو"><i class="fas fa-search"></i></a> | ||
| <a href="/settings/index.html" class="hover:text-gray-300" aria-label="تنظیمات"><i class="fas fa-cog"></i></a> | ||
| </nav> | ||
| <div> | ||
| <a href="/"> | ||
| <img src="/logo.png" alt="لوگوی فیری مووی" class="h-10"> | ||
| </a> | ||
| </div> | ||
| </div> | ||
| </header> | ||
| `; | ||
|
|
||
| const footerHtml = ` | ||
| <footer class="bg-gray-800 p-4 mt-auto"> | ||
| <div class="container mx-auto text-center"> | ||
| <p> | ||
| فیری مووی - ساخته شده با 🤍 | ||
| <br> | ||
| استفاده از فونت <a href="https://rastikerdar.github.io/vazir-font/" class="hover:text-gray-300">وزیرمتن</a> به یاد صابر راستی کردار | ||
| </p> | ||
| <a href="/developer/">توسعهدهندگان</a> | <a href="/about-freemovie/">درباره فیری مووی</a> | ||
| <br> | ||
| <a href="/disclaimer/">سلب مسئولیت</a> | <a href="/disclaimer/index-en.html">DMCA</a> | ||
| <div class="social-icons mb-2"> | ||
| <a class="github-button" | ||
| href="https://github.com/FreeMovieIR/web" | ||
| data-icon="octicon-star" | ||
| data-show-count="true" | ||
| aria-label="ستاره دادن به FreeMovieIR/web در گیتهاب"></a> | ||
| </div> | ||
| <div class="social-icons mb-2"> | ||
| <a href="https://twitter.com/freemovie_ir" target="_blank" class="mx-2 hover:text-gray-300" aria-label="ما را در توییتر دنبال کنید"> | ||
| <i class="fab fa-twitter"></i> | ||
| </a> | ||
| <a href="https://instagram.com/freemovie_ir" target="_blank" class="mx-2 hover:text-gray-300" aria-label="ما را در اینستاگرام دنبال کنید"> | ||
| <i class="fab fa-instagram"></i> | ||
| </a> | ||
| </div> | ||
| </div> | ||
| </footer> | ||
| `; | ||
|
|
||
| function ensureGithubButtonScript() { | ||
| if (document.querySelector('script[data-github-buttons]')) return; | ||
| const script = document.createElement('script'); | ||
| script.src = 'https://buttons.github.io/buttons.js'; | ||
| script.async = true; | ||
| script.defer = true; | ||
| script.setAttribute('data-github-buttons', 'true'); | ||
| document.body.appendChild(script); | ||
| } | ||
|
|
||
| if (headerTarget) { | ||
| headerTarget.innerHTML = headerHtml; | ||
| } | ||
|
|
||
| if (footerTarget) { | ||
| footerTarget.innerHTML = footerHtml; | ||
| ensureGithubButtonScript(); | ||
| } | ||
| })(); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -24,14 +24,7 @@ | |
| </style> | ||
| </head> | ||
| <body class="bg-gray-900 text-white min-h-screen flex flex-col"> | ||
| <header class="bg-gray-800 p-4 shadow-md"> | ||
| <div class="container mx-auto flex justify-between items-center"> | ||
| <h1 class="text-xl font-bold">پلیشو - تماشای گروهی</h1> | ||
| <button onclick="showInputSection()" class="bg-indigo-600 hover:bg-indigo-700 text-white py-2 px-4 rounded-lg"> | ||
| <i class="fas fa-plus ml-2"></i> فیلم جدید | ||
| </button> | ||
| </div> | ||
| </header> | ||
| <div id="shared-header"></div> | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
This header replacement removes the previous “film new” control that called Useful? React with 👍 / 👎. |
||
|
|
||
| <main class="container mx-auto flex-1 py-8 px-4"> | ||
| <div class="flex flex-col items-center gap-6"> | ||
|
|
@@ -71,11 +64,8 @@ <h2 class="text-lg font-semibold mb-4 text-center">لینک اشتراکگذ | |
| </div> | ||
| </main> | ||
|
|
||
| <footer class="bg-gray-800 p-4 mt-auto"> | ||
| <div class="container mx-auto text-center text-gray-400"> | ||
| پلیشو - تماشای همزمان ویدیو با دوستان | ||
| </div> | ||
| </footer> | ||
| <div id="shared-footer"></div> | ||
| <script src="script.js"></script> | ||
| <script src="/js/layout-shared.js" defer></script> | ||
| </body> | ||
| </html> | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| User-agent: * | ||
| Allow: / | ||
|
|
||
| Sitemap: https://freemovieir.github.io/sitemap.xml |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,78 @@ | ||
| import fs from 'node:fs/promises'; | ||
|
|
||
| const BASE_URL = 'https://freemovieir.github.io'; | ||
| const TMDB_KEY = process.env.TMDB_API_KEY || '1dc4cbf81f0accf4fa108820d551dafc'; | ||
|
|
||
| const staticPaths = [ | ||
| '/', | ||
| '/search/index.html', | ||
| '/watchlist/index.html', | ||
| '/settings/index.html', | ||
| '/about-freemovie/', | ||
| '/developer/', | ||
| '/disclaimer/', | ||
| '/disclaimer/index-en.html', | ||
| '/changelog/', | ||
| '/genres/index.html', | ||
| '/upcoming/index.html', | ||
| '/airing-today-tv-show/index.html', | ||
| '/series-top-rated/index.html' | ||
| ]; | ||
|
|
||
| async function fetchTmdb(path) { | ||
| const url = `https://api.themoviedb.org/3${path}${path.includes('?') ? '&' : '?'}api_key=${TMDB_KEY}&language=fa`; | ||
| const res = await fetch(url); | ||
| if (!res.ok) throw new Error(`TMDB request failed: ${res.status} ${path}`); | ||
| return res.json(); | ||
| } | ||
|
|
||
| async function loadDynamicUrls() { | ||
| const [trendingMovie, trendingTv, upcomingMovie, topTv] = await Promise.all([ | ||
| fetchTmdb('/trending/movie/week'), | ||
| fetchTmdb('/trending/tv/week'), | ||
| fetchTmdb('/movie/upcoming?page=1'), | ||
| fetchTmdb('/tv/top_rated?page=1') | ||
| ]); | ||
|
|
||
| const movieIds = new Set([ | ||
| ...(trendingMovie.results || []).map((i) => i.id), | ||
| ...(upcomingMovie.results || []).map((i) => i.id) | ||
| ]); | ||
| const tvIds = new Set([ | ||
| ...(trendingTv.results || []).map((i) => i.id), | ||
| ...(topTv.results || []).map((i) => i.id) | ||
| ]); | ||
|
|
||
| return [ | ||
| ...[...movieIds].map((id) => `/movie/index.html?id=${id}`), | ||
| ...[...tvIds].map((id) => `/series/index.html?id=${id}`) | ||
| ]; | ||
| } | ||
|
|
||
| function xmlUrl(loc, priority = '0.70') { | ||
| const now = new Date().toISOString(); | ||
| return `<url><loc>${loc}</loc><lastmod>${now}</lastmod><priority>${priority}</priority></url>`; | ||
| } | ||
|
|
||
| async function main() { | ||
| let dynamicPaths = []; | ||
| try { | ||
| dynamicPaths = await loadDynamicUrls(); | ||
| } catch (error) { | ||
| console.warn('Could not fetch TMDB dynamic URLs, generating sitemap with static paths only.'); | ||
| } | ||
| const allPaths = [...new Set([...staticPaths, ...dynamicPaths])]; | ||
|
|
||
| const xml = `<?xml version="1.0" encoding="UTF-8"?>\n` + | ||
| `<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n` + | ||
| allPaths.map((path) => xmlUrl(`${BASE_URL}${path}`, path === '/' ? '1.00' : '0.70')).join('\n') + | ||
| `\n</urlset>\n`; | ||
|
|
||
| await fs.writeFile('sitemap.xml', xml, 'utf8'); | ||
| console.log(`sitemap.xml generated with ${allPaths.length} URLs`); | ||
| } | ||
|
|
||
| main().catch((err) => { | ||
| console.error(err); | ||
| process.exit(1); | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
player/index.htmlnow swaps the static header for#shared-header, but the inline script still immediately executesdocument.getElementById('theme-toggle').addEventListener(...). Because the header is injected later by deferred/js/layout-shared.js,#theme-toggleisnullon every page load, which throws and stops the remaining setup code (including paste auto-detect, keyboard shortcuts, and theme initialization).Useful? React with 👍 / 👎.