This commit is contained in:
ct
2025-07-17 03:42:15 +08:00
parent 62cefe271e
commit 65dc6cec81
8 changed files with 553 additions and 1 deletions

4
.gitignore vendored
View File

@@ -22,3 +22,7 @@ yarn-error.log
/.nova
/.vscode
/.zed
# Sitemap files (auto-generated)
/public/sitemap.xml
/public/sitemap_*.xml

View File

@@ -0,0 +1,63 @@
<?php
namespace App\Console\Commands;
use App\Services\MemeMediaService;
use Illuminate\Console\Command;
use Spatie\Sitemap\Sitemap;
use Spatie\Sitemap\Tags\Url;
class GenerateMemesSitemap extends Command
{
protected $signature = 'sitemap:generate:memes';
protected $description = 'Generate sitemap for individual meme pages (memes.show)';
public function __construct(
private MemeMediaService $memeMediaService
) {
parent::__construct();
}
public function handle(): int
{
$this->info('Starting memes sitemap generation...');
$sitemap = Sitemap::create();
// Get the base URL from config
$baseUrl = config('app.url');
// Get all enabled memes
$memes = $this->memeMediaService->getAllEnabledMemes();
$this->info("Found {$memes->count()} enabled memes");
// Add a progress bar for large datasets
$progressBar = $this->output->createProgressBar($memes->count());
$progressBar->start();
// Add each meme to the sitemap
foreach ($memes as $meme) {
$url = Url::create($baseUrl . '/meme/' . $meme->slug)
->setPriority(0.8)
->setChangeFrequency(Url::CHANGE_FREQUENCY_MONTHLY)
->setLastModificationDate($meme->updated_at);
$sitemap->add($url);
$progressBar->advance();
}
$progressBar->finish();
$this->newLine();
// Save the sitemap
$sitemapPath = public_path('sitemap_memes.xml');
$sitemap->writeToFile($sitemapPath);
$this->info("Memes sitemap generated successfully!");
$this->info("Sitemap saved to: {$sitemapPath}");
$this->info("Total URLs: {$memes->count()}");
return Command::SUCCESS;
}
}

View File

@@ -0,0 +1,70 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Spatie\Sitemap\SitemapIndex;
class GenerateSitemap extends Command
{
protected $signature = 'sitemap:generate';
protected $description = 'Generate main sitemap index that links to all sub-sitemaps';
public function handle(): int
{
$this->info('Starting main sitemap generation...');
$sitemapIndex = SitemapIndex::create();
// Get the base URL from config
$baseUrl = config('app.url');
// List of sub-sitemaps to include in the main sitemap
$subSitemaps = [
[
'url' => $baseUrl . '/sitemap_static.xml',
'lastModified' => $this->getSitemapLastModified('sitemap_static.xml'),
],
[
'url' => $baseUrl . '/sitemap_memes.xml',
'lastModified' => $this->getSitemapLastModified('sitemap_memes.xml'),
],
// Future sitemaps can be added here:
// [
// 'url' => $baseUrl . '/sitemap_pages.xml',
// 'lastModified' => now(),
// ],
];
// Add each sub-sitemap to the index
foreach ($subSitemaps as $sitemap) {
$sitemapIndex->add($sitemap['url'], $sitemap['lastModified']);
$this->info("Added sub-sitemap: {$sitemap['url']}");
}
// Save the main sitemap index
$sitemapPath = public_path('sitemap.xml');
$sitemapIndex->writeToFile($sitemapPath);
$this->info("Main sitemap index generated successfully!");
$this->info("Sitemap saved to: {$sitemapPath}");
$this->info("Total sub-sitemaps: " . count($subSitemaps));
return Command::SUCCESS;
}
/**
* Get the last modification date of a sitemap file
*/
private function getSitemapLastModified(string $filename): \DateTime
{
$filepath = public_path($filename);
if (file_exists($filepath)) {
return new \DateTime('@' . filemtime($filepath));
}
// If file doesn't exist, return current time
return new \DateTime();
}
}

View File

@@ -0,0 +1,79 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Spatie\Sitemap\Sitemap;
use Spatie\Sitemap\Tags\Url;
class GenerateStaticSitemap extends Command
{
protected $signature = 'sitemap:generate:static';
protected $description = 'Generate sitemap for static pages (home, privacy, terms, dmca, meme library)';
public function handle(): int
{
$this->info('Starting static sitemap generation...');
$sitemap = Sitemap::create();
// Get the base URL from config
$baseUrl = config('app.url');
// Add static pages
$staticPages = [
[
'url' => $baseUrl,
'priority' => 1.0,
'changeFrequency' => Url::CHANGE_FREQUENCY_WEEKLY,
'lastModificationDate' => now(),
],
[
'url' => $baseUrl . '/meme-library',
'priority' => 0.9,
'changeFrequency' => Url::CHANGE_FREQUENCY_DAILY,
'lastModificationDate' => now(),
],
[
'url' => $baseUrl . '/privacy',
'priority' => 0.3,
'changeFrequency' => Url::CHANGE_FREQUENCY_YEARLY,
'lastModificationDate' => now()->subMonths(6), // Adjust based on when you last updated
],
[
'url' => $baseUrl . '/terms',
'priority' => 0.3,
'changeFrequency' => Url::CHANGE_FREQUENCY_YEARLY,
'lastModificationDate' => now()->subMonths(6), // Adjust based on when you last updated
],
[
'url' => $baseUrl . '/dmca-copyright',
'priority' => 0.2,
'changeFrequency' => Url::CHANGE_FREQUENCY_YEARLY,
'lastModificationDate' => now()->subMonths(6), // Adjust based on when you last updated
],
];
// Add each static page to the sitemap
foreach ($staticPages as $page) {
$url = Url::create($page['url'])
->setPriority($page['priority'])
->setChangeFrequency($page['changeFrequency'])
->setLastModificationDate($page['lastModificationDate']);
$sitemap->add($url);
$this->info("Added: {$page['url']}");
}
// Save the sitemap
$sitemapPath = public_path('sitemap_static.xml');
$sitemap->writeToFile($sitemapPath);
$this->info("Static sitemap generated successfully!");
$this->info("Sitemap saved to: {$sitemapPath}");
$this->info("Total URLs: " . count($staticPages));
return Command::SUCCESS;
}
}

View File

@@ -150,6 +150,16 @@ private function buildSearchQuery(?string $search = null): Builder
return $query;
}
/**
* Get all enabled memes for sitemap generation
*/
public function getAllEnabledMemes(): Collection
{
return MemeMedia::where('is_enabled', true)
->orderBy('updated_at', 'desc')
->get();
}
/**
* Get base query for enabled memes
*/

View File

@@ -26,6 +26,7 @@
"pbmedia/laravel-ffmpeg": "^8.7",
"pgvector/pgvector": "^0.2.2",
"spatie/laravel-responsecache": "^7.7",
"spatie/laravel-sitemap": "^7.3",
"spatie/laravel-tags": "^4.10",
"symfony/dom-crawler": "^7.3",
"tightenco/ziggy": "^2.4",

325
composer.lock generated
View File

@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "90bdf51ac5b2a4e868e9bb012981fc26",
"content-hash": "79a02fbcd504e47b61331dad19bd62a0",
"packages": [
{
"name": "artesaos/seotools",
@@ -4327,6 +4327,60 @@
},
"time": "2025-03-30T21:06:30+00:00"
},
{
"name": "nicmart/tree",
"version": "0.9.0",
"source": {
"type": "git",
"url": "https://github.com/nicmart/Tree.git",
"reference": "f5e17bf18d78cfb0666ebb9f956c3acd8d14229d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nicmart/Tree/zipball/f5e17bf18d78cfb0666ebb9f956c3acd8d14229d",
"reference": "f5e17bf18d78cfb0666ebb9f956c3acd8d14229d",
"shasum": ""
},
"require": {
"php": "~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0"
},
"require-dev": {
"ergebnis/composer-normalize": "^2.44.0",
"ergebnis/license": "^2.6.0",
"ergebnis/php-cs-fixer-config": "^6.28.1",
"fakerphp/faker": "^1.24.1",
"infection/infection": "~0.26.19",
"phpunit/phpunit": "^9.6.19",
"psalm/plugin-phpunit": "~0.19.0",
"vimeo/psalm": "^5.26.1"
},
"type": "library",
"autoload": {
"psr-4": {
"Tree\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolò Martini",
"email": "nicmartnic@gmail.com"
},
{
"name": "Andreas Möller",
"email": "am@localheinz.com"
}
],
"description": "A basic but flexible php tree data structure and a fluent tree builder implementation.",
"support": {
"issues": "https://github.com/nicmart/Tree/issues",
"source": "https://github.com/nicmart/Tree/tree/0.9.0"
},
"time": "2024-11-22T15:36:01+00:00"
},
{
"name": "nikic/php-parser",
"version": "v5.4.0",
@@ -5857,6 +5911,142 @@
],
"time": "2024-04-27T21:32:50+00:00"
},
{
"name": "spatie/browsershot",
"version": "5.0.10",
"source": {
"type": "git",
"url": "https://github.com/spatie/browsershot.git",
"reference": "9e5ae15487b3cdc3eb03318c1c8ac38971f60e58"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/spatie/browsershot/zipball/9e5ae15487b3cdc3eb03318c1c8ac38971f60e58",
"reference": "9e5ae15487b3cdc3eb03318c1c8ac38971f60e58",
"shasum": ""
},
"require": {
"ext-fileinfo": "*",
"ext-json": "*",
"php": "^8.2",
"spatie/temporary-directory": "^2.0",
"symfony/process": "^6.0|^7.0"
},
"require-dev": {
"pestphp/pest": "^3.0",
"spatie/image": "^3.6",
"spatie/pdf-to-text": "^1.52",
"spatie/phpunit-snapshot-assertions": "^4.2.3|^5.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Spatie\\Browsershot\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Freek Van der Herten",
"email": "freek@spatie.be",
"homepage": "https://github.com/freekmurze",
"role": "Developer"
}
],
"description": "Convert a webpage to an image or pdf using headless Chrome",
"homepage": "https://github.com/spatie/browsershot",
"keywords": [
"chrome",
"convert",
"headless",
"image",
"pdf",
"puppeteer",
"screenshot",
"webpage"
],
"support": {
"source": "https://github.com/spatie/browsershot/tree/5.0.10"
},
"funding": [
{
"url": "https://github.com/spatie",
"type": "github"
}
],
"time": "2025-05-15T07:10:57+00:00"
},
{
"name": "spatie/crawler",
"version": "8.4.3",
"source": {
"type": "git",
"url": "https://github.com/spatie/crawler.git",
"reference": "4f4c3ead439e7e57085c0b802bc4e5b44fb7d751"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/spatie/crawler/zipball/4f4c3ead439e7e57085c0b802bc4e5b44fb7d751",
"reference": "4f4c3ead439e7e57085c0b802bc4e5b44fb7d751",
"shasum": ""
},
"require": {
"guzzlehttp/guzzle": "^7.3",
"guzzlehttp/psr7": "^2.0",
"illuminate/collections": "^10.0|^11.0|^12.0",
"nicmart/tree": "^0.9",
"php": "^8.2",
"spatie/browsershot": "^5.0.5",
"spatie/robots-txt": "^2.0",
"symfony/dom-crawler": "^6.0|^7.0"
},
"require-dev": {
"pestphp/pest": "^2.0|^3.0",
"spatie/ray": "^1.37"
},
"type": "library",
"autoload": {
"psr-4": {
"Spatie\\Crawler\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Freek Van der Herten",
"email": "freek@spatie.be"
}
],
"description": "Crawl all internal links found on a website",
"homepage": "https://github.com/spatie/crawler",
"keywords": [
"crawler",
"link",
"spatie",
"website"
],
"support": {
"issues": "https://github.com/spatie/crawler/issues",
"source": "https://github.com/spatie/crawler/tree/8.4.3"
},
"funding": [
{
"url": "https://spatie.be/open-source/support-us",
"type": "custom"
},
{
"url": "https://github.com/spatie",
"type": "github"
}
],
"time": "2025-05-20T09:00:51+00:00"
},
{
"name": "spatie/eloquent-sortable",
"version": "4.5.0",
@@ -6075,6 +6265,79 @@
],
"time": "2025-05-20T08:39:19+00:00"
},
{
"name": "spatie/laravel-sitemap",
"version": "7.3.6",
"source": {
"type": "git",
"url": "https://github.com/spatie/laravel-sitemap.git",
"reference": "506b2acdd350c7ff868a7711b4f30e486b20e9b0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/spatie/laravel-sitemap/zipball/506b2acdd350c7ff868a7711b4f30e486b20e9b0",
"reference": "506b2acdd350c7ff868a7711b4f30e486b20e9b0",
"shasum": ""
},
"require": {
"guzzlehttp/guzzle": "^7.8",
"illuminate/support": "^11.0|^12.0",
"nesbot/carbon": "^2.71|^3.0",
"php": "^8.2||^8.3||^8.4",
"spatie/crawler": "^8.0.1",
"spatie/laravel-package-tools": "^1.16.1",
"symfony/dom-crawler": "^6.3.4|^7.0"
},
"require-dev": {
"mockery/mockery": "^1.6.6",
"orchestra/testbench": "^9.0|^10.0",
"pestphp/pest": "^3.7.4",
"spatie/pest-plugin-snapshots": "^2.1",
"spatie/phpunit-snapshot-assertions": "^5.1.2",
"spatie/temporary-directory": "^2.2"
},
"type": "library",
"extra": {
"laravel": {
"providers": [
"Spatie\\Sitemap\\SitemapServiceProvider"
]
}
},
"autoload": {
"psr-4": {
"Spatie\\Sitemap\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Freek Van der Herten",
"email": "freek@spatie.be",
"homepage": "https://spatie.be",
"role": "Developer"
}
],
"description": "Create and generate sitemaps with ease",
"homepage": "https://github.com/spatie/laravel-sitemap",
"keywords": [
"laravel-sitemap",
"spatie"
],
"support": {
"source": "https://github.com/spatie/laravel-sitemap/tree/7.3.6"
},
"funding": [
{
"url": "https://spatie.be/open-source/support-us",
"type": "custom"
}
],
"time": "2025-04-10T12:13:41+00:00"
},
{
"name": "spatie/laravel-tags",
"version": "4.10.0",
@@ -6228,6 +6491,66 @@
],
"time": "2025-02-20T15:51:22+00:00"
},
{
"name": "spatie/robots-txt",
"version": "2.5.1",
"source": {
"type": "git",
"url": "https://github.com/spatie/robots-txt.git",
"reference": "ef85dfaa48372c0a7fdfb144592f95de1a2e9b79"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/spatie/robots-txt/zipball/ef85dfaa48372c0a7fdfb144592f95de1a2e9b79",
"reference": "ef85dfaa48372c0a7fdfb144592f95de1a2e9b79",
"shasum": ""
},
"require": {
"php": "^8.1"
},
"require-dev": {
"phpunit/phpunit": "^11.5.2"
},
"type": "library",
"autoload": {
"psr-4": {
"Spatie\\Robots\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Brent Roose",
"email": "brent@spatie.be",
"homepage": "https://spatie.be",
"role": "Developer"
}
],
"description": "Determine if a page may be crawled from robots.txt and robots meta tags",
"homepage": "https://github.com/spatie/robots-txt",
"keywords": [
"robots-txt",
"spatie"
],
"support": {
"issues": "https://github.com/spatie/robots-txt/issues",
"source": "https://github.com/spatie/robots-txt/tree/2.5.1"
},
"funding": [
{
"url": "https://spatie.be/open-source/support-us",
"type": "custom"
},
{
"url": "https://github.com/spatie",
"type": "github"
}
],
"time": "2025-07-01T07:07:44+00:00"
},
{
"name": "spatie/temporary-directory",
"version": "2.3.0",

View File

@@ -1,2 +1,4 @@
User-agent: *
Disallow:
Sitemap: https://memefast.app/sitemap.xml