mirror of
https://github.com/selfboot/ai_gallery.git
synced 2026-06-04 21:06:53 +08:00
SEO: add bing index-now
This commit is contained in:
parent
25cbbc20cd
commit
5334d4b142
31
.github/workflows/submit-to-bing.yml
vendored
Normal file
31
.github/workflows/submit-to-bing.yml
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
name: Submit New URLs to Bing
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
submit-urls:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20'
|
||||
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v2
|
||||
with:
|
||||
version: 8
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
|
||||
- name: Submit new URLs to Bing
|
||||
run: node scripts/submit-to-bing.mjs
|
||||
@ -37,6 +37,7 @@
|
||||
"lodash.debounce": "^4.0.8",
|
||||
"lucide-react": "^0.416.0",
|
||||
"next": "14.2.12",
|
||||
"node-fetch": "^3.3.2",
|
||||
"papaparse": "^5.4.1",
|
||||
"pizzip": "^3.1.7",
|
||||
"react": "^18.3.1",
|
||||
|
||||
@ -86,6 +86,9 @@ importers:
|
||||
next:
|
||||
specifier: 14.2.12
|
||||
version: 14.2.12(@babel/core@7.25.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
node-fetch:
|
||||
specifier: ^3.3.2
|
||||
version: 3.3.2
|
||||
papaparse:
|
||||
specifier: ^5.4.1
|
||||
version: 5.4.1
|
||||
@ -1614,6 +1617,10 @@ packages:
|
||||
damerau-levenshtein@1.0.8:
|
||||
resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==}
|
||||
|
||||
data-uri-to-buffer@4.0.1:
|
||||
resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==}
|
||||
engines: {node: '>= 12'}
|
||||
|
||||
data-urls@3.0.2:
|
||||
resolution: {integrity: sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ==}
|
||||
engines: {node: '>=12'}
|
||||
@ -2001,6 +2008,10 @@ packages:
|
||||
fb-watchman@2.0.2:
|
||||
resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==}
|
||||
|
||||
fetch-blob@3.2.0:
|
||||
resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==}
|
||||
engines: {node: ^12.20 || >= 14.13}
|
||||
|
||||
fflate@0.3.11:
|
||||
resolution: {integrity: sha512-Rr5QlUeGN1mbOHlaqcSYMKVpPbgLy0AWT/W0EHxA6NGI12yO1jpoui2zBBvU2G824ltM6Ut8BFgfHSBGfkmS0A==}
|
||||
|
||||
@ -2047,6 +2058,10 @@ packages:
|
||||
resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==}
|
||||
engines: {node: '>= 6'}
|
||||
|
||||
formdata-polyfill@4.0.10:
|
||||
resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==}
|
||||
engines: {node: '>=12.20.0'}
|
||||
|
||||
frac@1.1.2:
|
||||
resolution: {integrity: sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==}
|
||||
engines: {node: '>=0.8'}
|
||||
@ -3065,6 +3080,14 @@ packages:
|
||||
sass:
|
||||
optional: true
|
||||
|
||||
node-domexception@1.0.0:
|
||||
resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==}
|
||||
engines: {node: '>=10.5.0'}
|
||||
|
||||
node-fetch@3.3.2:
|
||||
resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==}
|
||||
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
|
||||
|
||||
node-int64@0.4.0:
|
||||
resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==}
|
||||
|
||||
@ -3972,6 +3995,10 @@ packages:
|
||||
web-namespaces@2.0.1:
|
||||
resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==}
|
||||
|
||||
web-streams-polyfill@3.3.3:
|
||||
resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==}
|
||||
engines: {node: '>= 8'}
|
||||
|
||||
web-vitals@4.2.2:
|
||||
resolution: {integrity: sha512-nYfoOqb4EmElljyXU2qdeE76KsvoHdftQKY4DzA9Aw8DervCg2bG634pHLrJ/d6+B4mE3nWTSJv8Mo7B2mbZkw==}
|
||||
|
||||
@ -5899,6 +5926,8 @@ snapshots:
|
||||
|
||||
damerau-levenshtein@1.0.8: {}
|
||||
|
||||
data-uri-to-buffer@4.0.1: {}
|
||||
|
||||
data-urls@3.0.2:
|
||||
dependencies:
|
||||
abab: 2.0.6
|
||||
@ -6455,6 +6484,11 @@ snapshots:
|
||||
dependencies:
|
||||
bser: 2.1.1
|
||||
|
||||
fetch-blob@3.2.0:
|
||||
dependencies:
|
||||
node-domexception: 1.0.0
|
||||
web-streams-polyfill: 3.3.3
|
||||
|
||||
fflate@0.3.11: {}
|
||||
|
||||
fflate@0.6.10: {}
|
||||
@ -6504,6 +6538,10 @@ snapshots:
|
||||
combined-stream: 1.0.8
|
||||
mime-types: 2.1.13
|
||||
|
||||
formdata-polyfill@4.0.10:
|
||||
dependencies:
|
||||
fetch-blob: 3.2.0
|
||||
|
||||
frac@1.1.2: {}
|
||||
|
||||
fs-constants@1.0.0: {}
|
||||
@ -7938,6 +7976,14 @@ snapshots:
|
||||
- '@babel/core'
|
||||
- babel-plugin-macros
|
||||
|
||||
node-domexception@1.0.0: {}
|
||||
|
||||
node-fetch@3.3.2:
|
||||
dependencies:
|
||||
data-uri-to-buffer: 4.0.1
|
||||
fetch-blob: 3.2.0
|
||||
formdata-polyfill: 4.0.10
|
||||
|
||||
node-int64@0.4.0: {}
|
||||
|
||||
node-releases@2.0.18: {}
|
||||
@ -8954,6 +9000,8 @@ snapshots:
|
||||
|
||||
web-namespaces@2.0.1: {}
|
||||
|
||||
web-streams-polyfill@3.3.3: {}
|
||||
|
||||
web-vitals@4.2.2: {}
|
||||
|
||||
webgl-constants@1.1.1: {}
|
||||
|
||||
1
public/90d513c720ec40e3a57f488239db260c.txt
Normal file
1
public/90d513c720ec40e3a57f488239db260c.txt
Normal file
@ -0,0 +1 @@
|
||||
90d513c720ec40e3a57f488239db260c
|
||||
@ -37,7 +37,7 @@ async function generateSitemapAndRss() {
|
||||
`!src/app/[lang]/blog/[slug]`,
|
||||
]);
|
||||
|
||||
console.log(`Found pages for ${lang}:`, pages);
|
||||
// console.log(`Found pages for ${lang}:`, pages);
|
||||
|
||||
let sitemapItems = [];
|
||||
let rssItems = [];
|
||||
@ -45,14 +45,14 @@ async function generateSitemapAndRss() {
|
||||
const dict = getDictionary(lang);
|
||||
|
||||
for (const page of pages) {
|
||||
console.log(`Processing page: ${page}`);
|
||||
// console.log(`Processing page: ${page}`);
|
||||
|
||||
const route = page
|
||||
.replace("src/app/[lang]", "")
|
||||
.replace("/page.js", "")
|
||||
.replace("/index", "");
|
||||
|
||||
console.log(`Route: ${route}`);
|
||||
// console.log(`Route: ${route}`);
|
||||
|
||||
try {
|
||||
const content = fs.readFileSync(page, "utf8");
|
||||
@ -182,7 +182,7 @@ async function generateSitemapAndRss() {
|
||||
}
|
||||
|
||||
function addToSitemapAndRss(sitemapItems, rssItems, metadata) {
|
||||
console.log("Metadata:", metadata);
|
||||
// console.log("Metadata:", metadata);
|
||||
|
||||
const url = metadata.canonicalUrl;
|
||||
|
||||
|
||||
80
scripts/submit-to-bing.mjs
Normal file
80
scripts/submit-to-bing.mjs
Normal file
@ -0,0 +1,80 @@
|
||||
import fetch from 'node-fetch';
|
||||
|
||||
const DOMAIN = 'gallery.selfboot.cn';
|
||||
const BING_KEY = '90d513c720ec40e3a57f488239db260c';
|
||||
const KEY_LOCATION = `https://${DOMAIN}/${BING_KEY}.txt`;
|
||||
|
||||
async function submitToBing(urls) {
|
||||
if (!urls || urls.length === 0) {
|
||||
console.log('没有URL需要提交');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('准备提交以下URL到Bing:', urls);
|
||||
|
||||
const payload = {
|
||||
host: DOMAIN,
|
||||
key: BING_KEY,
|
||||
keyLocation: KEY_LOCATION,
|
||||
urlList: urls
|
||||
};
|
||||
|
||||
try {
|
||||
console.log('提交payload:', payload);
|
||||
|
||||
const response = await fetch('https://api.indexnow.org/IndexNow', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json; charset=utf-8'
|
||||
},
|
||||
body: JSON.stringify(payload)
|
||||
});
|
||||
|
||||
const status = response.status;
|
||||
console.log(`提交状态码: ${status}`);
|
||||
|
||||
switch (status) {
|
||||
case 200:
|
||||
console.log('URL提交成功!');
|
||||
break;
|
||||
case 400:
|
||||
console.error('提交格式错误');
|
||||
break;
|
||||
case 403:
|
||||
console.error('API密钥无效');
|
||||
break;
|
||||
case 422:
|
||||
console.error('URL不属于指定域名或密钥格式不匹配');
|
||||
break;
|
||||
case 429:
|
||||
console.error('请求过于频繁,可能被视为垃圾请求');
|
||||
break;
|
||||
default:
|
||||
console.error(`未知错误: ${status}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('提交过程中发生错误:', error);
|
||||
}
|
||||
}
|
||||
|
||||
async function submitNewUrlsToBing() {
|
||||
console.log('开始获取今天更新的页面URL...');
|
||||
|
||||
const { getRecentPageUrls } = await import('./track-page-changes.mjs');
|
||||
const urls = await getRecentPageUrls();
|
||||
|
||||
if (urls.length > 0) {
|
||||
await submitToBing(urls);
|
||||
} else {
|
||||
console.log('今天没有更新的页面,不需要提交');
|
||||
}
|
||||
}
|
||||
|
||||
// 直接执行主函数
|
||||
console.log('开始执行 bing index now脚本...');
|
||||
submitNewUrlsToBing().catch((error) => {
|
||||
console.error('执行过程中发生错误:', error);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
export { submitToBing };
|
||||
74
scripts/track-page-changes.mjs
Normal file
74
scripts/track-page-changes.mjs
Normal file
@ -0,0 +1,74 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import matter from 'gray-matter';
|
||||
|
||||
const DOMAIN = "https://gallery.selfboot.cn";
|
||||
const LANGUAGES = ["en", "zh"];
|
||||
|
||||
async function getRecentPageUrls() {
|
||||
const { globby } = await import("globby");
|
||||
let urls = new Set();
|
||||
const today = new Date().toISOString().split('T')[0]; // 获取今天的日期 YYYY-MM-DD
|
||||
|
||||
for (const lang of LANGUAGES) {
|
||||
// 获取基础页面
|
||||
const pages = await globby([
|
||||
`src/app/[lang]/**/page.js`,
|
||||
`!src/app/[lang]/api`,
|
||||
`!src/app/[lang]/blog/[slug]`,
|
||||
]);
|
||||
|
||||
// 处理基础页面
|
||||
for (const page of pages) {
|
||||
const content = fs.readFileSync(page, "utf8");
|
||||
const updatedDateMatch = content.match(/updatedDate:\s*"([^"]+)"/);
|
||||
const updatedDate = updatedDateMatch ? updatedDateMatch[1].split('T')[0] : null;
|
||||
|
||||
// 只处理今天更新的页面
|
||||
if (updatedDate === today) {
|
||||
const route = page
|
||||
.replace("src/app/[lang]", "")
|
||||
.replace("/page.js", "")
|
||||
.replace("/index", "");
|
||||
|
||||
if (route.includes('[chartId]')) {
|
||||
// 处理动态图表路由
|
||||
const { dynamicChartConfigs } = await import('../src/app/[lang]/tools/chartrace/dynamicChartConfigs.js');
|
||||
for (const config of dynamicChartConfigs) {
|
||||
if (config.updatedDate?.split('T')[0] === today) {
|
||||
const dynamicRoute = route.replace('[chartId]', config.id);
|
||||
urls.add(`${DOMAIN}/${lang}${dynamicRoute}`);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
urls.add(`${DOMAIN}/${lang}${route}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 获取博客文章
|
||||
const blogPosts = await globby([`src/posts/*/${lang}.md`]);
|
||||
for (const post of blogPosts) {
|
||||
const content = fs.readFileSync(post, "utf8");
|
||||
const { data } = matter(content);
|
||||
const postDate = new Date(data.date).toISOString().split('T')[0];
|
||||
|
||||
// 只处理今天发布的文章
|
||||
if (postDate === today) {
|
||||
const slug = path.basename(path.dirname(post));
|
||||
urls.add(`${DOMAIN}/${lang}/blog/${slug}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const recentUrls = Array.from(urls);
|
||||
if (recentUrls.length > 0) {
|
||||
console.log('今天有更新的页面');
|
||||
} else {
|
||||
console.log('今天没有更新的页面');
|
||||
}
|
||||
|
||||
return recentUrls;
|
||||
}
|
||||
|
||||
export { getRecentPageUrls };
|
||||
@ -1,38 +1,51 @@
|
||||
// middleware.js
|
||||
import { NextResponse } from "next/server";
|
||||
import { NextResponse } from 'next/server';
|
||||
|
||||
const LOCALES = ["en", "zh"];
|
||||
const LOCALES = ['en', 'zh'];
|
||||
|
||||
function getPreferredLocale(request) {
|
||||
// 检查 cookie
|
||||
const localeCookie = request.cookies.get("NEXT_LOCALE")?.value;
|
||||
const localeCookie = request.cookies.get('NEXT_LOCALE')?.value;
|
||||
if (localeCookie && LOCALES.includes(localeCookie)) {
|
||||
return localeCookie;
|
||||
}
|
||||
|
||||
// 检查 Accept-Language 头
|
||||
const acceptLanguage = request.headers.get("Accept-Language");
|
||||
const acceptLanguage = request.headers.get('Accept-Language');
|
||||
if (acceptLanguage) {
|
||||
const preferredLocale = acceptLanguage.split(",")[0].split("-")[0];
|
||||
const preferredLocale = acceptLanguage.split(',')[0].split('-')[0];
|
||||
if (LOCALES.includes(preferredLocale)) {
|
||||
return preferredLocale;
|
||||
}
|
||||
}
|
||||
|
||||
// 默认语言
|
||||
return "en";
|
||||
return 'en';
|
||||
}
|
||||
|
||||
export function middleware(request) {
|
||||
const pathname = request.nextUrl.pathname;
|
||||
let response;
|
||||
|
||||
// 首先检查是否为静态文件
|
||||
if (
|
||||
pathname.endsWith('.xml') ||
|
||||
pathname.endsWith('.js') ||
|
||||
pathname.endsWith('.json') ||
|
||||
pathname.endsWith('.csv') ||
|
||||
pathname.endsWith('.xlsx') ||
|
||||
pathname.endsWith('.docx') ||
|
||||
pathname.endsWith('.txt') ||
|
||||
pathname.endsWith('.ico')
|
||||
) {
|
||||
// 对于静态文件,直接返回,不做任何处理
|
||||
return NextResponse.next();
|
||||
}
|
||||
|
||||
let response;
|
||||
// 处理根路径
|
||||
if (pathname === "/") {
|
||||
if (pathname === '/') {
|
||||
const preferredLocale = getPreferredLocale(request);
|
||||
response = NextResponse.redirect(new URL(`/${preferredLocale}/games`, request.url));
|
||||
} else if (pathname.endsWith(".xml") || pathname.endsWith(".js") || pathname.endsWith(".json") || pathname.endsWith(".csv") || pathname.endsWith(".xlsx") || pathname.endsWith(".docx")) {
|
||||
response = NextResponse.next();
|
||||
} else {
|
||||
// 处理缺少语言前缀的路径
|
||||
const pathnameIsMissingLocale = LOCALES.every(
|
||||
@ -48,13 +61,13 @@ export function middleware(request) {
|
||||
|
||||
// 添加自定义 header
|
||||
if (response) {
|
||||
response.headers.set("x-pathname", pathname);
|
||||
response.headers.set('x-pathname', pathname);
|
||||
} else {
|
||||
response = NextResponse.next();
|
||||
response.headers.set("x-pathname", pathname);
|
||||
response.headers.set('x-pathname', pathname);
|
||||
}
|
||||
|
||||
response.headers.set("X-Robots-Tag", "index,follow");
|
||||
response.headers.set('X-Robots-Tag', 'index,follow');
|
||||
return response;
|
||||
}
|
||||
|
||||
@ -65,8 +78,7 @@ export const config = {
|
||||
* - api (API routes)
|
||||
* - _next/static (static files)
|
||||
* - _next/image (image optimization files)
|
||||
* - favicon.ico (favicon file)
|
||||
*/
|
||||
"/((?!api|_next/static|_next/image|favicon.ico|robots.txt).*)",
|
||||
'/((?!api|_next/static|_next/image|robots.txt).*)',
|
||||
],
|
||||
};
|
||||
|
||||
Loading…
Reference in New Issue
Block a user