no message

This commit is contained in:
hellcat 2026-09-10 18:25:15 +08:00
parent b96180f732
commit ac86e4e481
10 changed files with 359 additions and 86 deletions

113
README.md
View File

@ -1,59 +1,94 @@
<p align="center"><a href="https://laravel.com" target="_blank"><img src="https://raw.githubusercontent.com/laravel/art/master/logo-lockup/5%20SVG/2%20CMYK/1%20Full%20Color/laravel-logolockup-cmyk-red.svg" width="400" alt="Laravel Logo"></a></p>
key_indexnow = 8f3a9d2b1c4e7f0a8f3a9d2b1c4e7f0a
<p align="center">
<a href="https://github.com/laravel/framework/actions"><img src="https://github.com/laravel/framework/workflows/tests/badge.svg" alt="Build Status"></a>
<a href="https://packagist.org/packages/laravel/framework"><img src="https://img.shields.io/packagist/dt/laravel/framework" alt="Total Downloads"></a>
<a href="https://packagist.org/packages/laravel/framework"><img src="https://img.shields.io/packagist/v/laravel/framework" alt="Latest Stable Version"></a>
<a href="https://packagist.org/packages/laravel/framework"><img src="https://img.shields.io/packagist/l/laravel/framework" alt="License"></a>
</p>
NASA_API_SECRET=wocaonide # 接收端key
## About Laravel
url_ad_fu = fuuu.cloud
Laravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable and creative experience to be truly fulfilling. Laravel takes the pain out of development by easing common tasks used in many web projects, such as:
token_base = wocaonide
is_loc = false
tg_send_enable = true
url_master_base = master.diaodu.us
site_code = clashfreenode.com
site_code_short = cfn
page_limit = 20
app_title = SSR/V2ray/Clash免费节点每天更新
app_desc = "最新免费 Clash、V2ray 及 SSR 节点订阅地址每日更新。提供 Shadowrocket 与 Singbox、Hiddify 高速节点一键复制导入,保障稳定连通与高速体验。"
app_keywords = "Clash免费节点, V2ray订阅链接, SSR节点, 免费节点更新"
url_resource_base = resource.gemcook.net
url_github_href = https://github.com/clashfreenodecom/clashfreenode.com
- [Simple, fast routing engine](https://laravel.com/docs/routing).
- [Powerful dependency injection container](https://laravel.com/docs/container).
- Multiple back-ends for [session](https://laravel.com/docs/session) and [cache](https://laravel.com/docs/cache) storage.
- Expressive, intuitive [database ORM](https://laravel.com/docs/eloquent).
- Database agnostic [schema migrations](https://laravel.com/docs/migrations).
- [Robust background job processing](https://laravel.com/docs/queues).
- [Real-time event broadcasting](https://laravel.com/docs/broadcasting).
MEILISEARCH_KEY=wocaonide
SCOUT_DRIVER=meilisearch
MEILISEARCH_HOST=http://127.0.0.1:7700
SCOUT_QUEUE=false
Laravel is accessible, powerful, and provides tools required for large, robust applications.
VITE_DEV_SERVER_URL=http://127.0.0.1:5173
## Learning Laravel
APP_NAME=clashfreenode
APP_ENV=local
APP_KEY=base64:VkMoebPURG4A1ker22M5nfFV+tcjph+eYvQrJYANq0Y=
APP_DEBUG=true
APP_URL=https://clashfreenode.com
Laravel has the most extensive and thorough [documentation](https://laravel.com/docs) and video tutorial library of all modern web application frameworks, making it a breeze to get started with the framework. You can also check out [Laravel Learn](https://laravel.com/learn), where you will be guided through building a modern Laravel application.
APP_LOCALE=en
APP_FALLBACK_LOCALE=en
APP_FAKER_LOCALE=en_US
If you don't feel like reading, [Laracasts](https://laracasts.com) can help. Laracasts contains thousands of video tutorials on a range of topics including Laravel, modern PHP, unit testing, and JavaScript. Boost your skills by digging into our comprehensive video library.
APP_MAINTENANCE_DRIVER=file
# APP_MAINTENANCE_STORE=database
## Laravel Sponsors
# PHP_CLI_SERVER_WORKERS=4
We would like to extend our thanks to the following sponsors for funding Laravel development. If you are interested in becoming a sponsor, please visit the [Laravel Partners program](https://partners.laravel.com).
BCRYPT_ROUNDS=12
### Premium Partners
LOG_CHANNEL=stack
LOG_STACK=single
LOG_DEPRECATIONS_CHANNEL=null
LOG_LEVEL=debug
- **[Vehikl](https://vehikl.com)**
- **[Tighten Co.](https://tighten.co)**
- **[Kirschbaum Development Group](https://kirschbaumdevelopment.com)**
- **[64 Robots](https://64robots.com)**
- **[Curotec](https://www.curotec.com/services/technologies/laravel)**
- **[DevSquad](https://devsquad.com/hire-laravel-developers)**
- **[Redberry](https://redberry.international/laravel-development)**
- **[Active Logic](https://activelogic.com)**
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=clashfreenode-new-com
DB_USERNAME=hotdog
DB_PASSWORD=hotshotgg
## Contributing
SESSION_DRIVER=database
SESSION_LIFETIME=120
SESSION_ENCRYPT=false
SESSION_PATH=/
SESSION_DOMAIN=null
Thank you for considering contributing to the Laravel framework! The contribution guide can be found in the [Laravel documentation](https://laravel.com/docs/contributions).
BROADCAST_CONNECTION=log
FILESYSTEM_DISK=local
QUEUE_CONNECTION=database
## Code of Conduct
RESPONSE_CACHE_ENABLED=false
CACHE_STORE=file
RESPONSE_CACHE_STORE=file
RESPONSE_CACHE_DRIVER=file
# CACHE_PREFIX=
In order to ensure that the Laravel community is welcoming to all, please review and abide by the [Code of Conduct](https://laravel.com/docs/contributions#code-of-conduct).
MEMCACHED_HOST=127.0.0.1
## Security Vulnerabilities
REDIS_CLIENT=phpredis
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
If you discover a security vulnerability within Laravel, please send an e-mail to Taylor Otwell via [taylor@laravel.com](mailto:taylor@laravel.com). All security vulnerabilities will be promptly addressed.
MAIL_MAILER=log
MAIL_SCHEME=null
MAIL_HOST=127.0.0.1
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_FROM_ADDRESS="hello@example.com"
MAIL_FROM_NAME="${APP_NAME}"
## License
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_DEFAULT_REGION=us-east-1
AWS_BUCKET=
AWS_USE_PATH_STYLE_ENDPOINT=false
The Laravel framework is open-sourced software licensed under the [MIT license](https://opensource.org/licenses/MIT).
VITE_APP_NAME="${APP_NAME}"

View File

@ -12,6 +12,7 @@
use App\Models\ArticleThumbNum;
use App\Services\TomTool\HttpV2;
use App\Services\TagService;
use App\Services\IndexNowService;
class ArticlesController extends Controller
{
@ -83,15 +84,10 @@ public function receive(Request $oRequest)
$oArticle->save();
(new TagService())->syncArticleTagsByName($oArticle, $aOptTag);
// $aArticle = $oArticle->toArray();
// unset($aArticle["sContent"]);
// unset($aArticle["sTitleSub"]);
// $jArticle = json_encode($aArticle, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT);
$sMsg = "文章put成功:{$oArticle->sSlug}";
TeleSlave::notify()->send($sMsg);
return [
"isDone" => true,
];
@ -155,20 +151,6 @@ public function receiveShadowrocketids(Request $oRequest)
['sSlug' => $sSlug],
$aAttributes
);
// $oArticle = Articles::updateOrCreate(
// ['sSlug' => $sSlug],
// [
// 'sThumb' => $sThumbPath,
// 'iCategoryId' => $oCategories->id,
// 'sTitle' => $sTitle,
// 'sTitleSub' => $sTitleSub,
// 'sContent' => $sArticle,
// 'i7like' => $i7like,
// 'iStatus' => 1,
// 'iUserId' => 1,
// ],
// );
(new TagService())->syncArticleTagsByName($oArticle, $aArticleTags);
@ -176,7 +158,10 @@ public function receiveShadowrocketids(Request $oRequest)
$sArticleUrl = config("app.url")."/shadowrocketids/".$sSlug;
TeleSlave::notify()->send($sArticleUrl." 发布成功");
$oIndexNow = new IndexNowService();
$bIndexR = $oIndexNow->pushUrls([$sArticleUrl.".html"]);
TeleSlave::notify()->send($sArticleUrl." 发布成功 | "."indexNow推送:".$bIndexR);
return response()->json($oFlow->done());
}
@ -241,27 +226,16 @@ public function receiveFreenode(Request $oRequest)
$aAttributes
);
// $oArticle = Articles::updateOrCreate(
// ['sSlug' => $sSlug],
// [
// 'sThumb' => $sThumbPath,
// 'iCategoryId' => $oCategories->id,
// 'sTitle' => $sArticleTitle,
// 'sTitleSub' => $sArticleTitleSub,
// 'sContent' => $sArticleContent,
// 'i7like' => $i7like,
// 'iStatus' => 1,
// 'iUserId' => 1,
// ],
// ); // 我希望,如果数据已经有了,i7like就不再更新
(new TagService())->syncArticleTagsByName($oArticle, $aArticleTags);
ArticleFreenodeThumbNum::where("author_code", $sSubKey)->update(["num" => $sThumbNumTrue]);
$sArticleUrl = config("app.url")."/feenode/".$sSlug;
TeleSlave::notify()->send($sArticleUrl." 发布成功");
$oIndexNow = new IndexNowService();
$bIndexR = $oIndexNow->pushUrls([$sArticleUrl.".html"]);
TeleSlave::notify()->send($sArticleUrl." 发布成功 | "."indexNow推送:".$bIndexR);
return response()->json($oFlow->done());
}

View File

@ -3,11 +3,24 @@
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Services\IndexNowService;
class TestController extends Controller
class TestController
{
public function hello()
{
tt("hello");
}
public function test1()
{
$oIndexNow = new IndexNowService();
$a = ["https://clashfreenode.com/a/fn20260910.html"]; // 这个页面实际是存在的,但是跳过了?
$r = $oIndexNow->pushUrls($a);
tt($r);
}
}

View File

@ -14,6 +14,7 @@ class Categories extends Model
public $timestamps = false;
protected $casts = [
'aBanner' => 'array',
'aOpt' => 'array'
];
protected $touches = ['oArticles'];

View File

@ -0,0 +1,226 @@
<?php
namespace App\Services;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use Throwable;
class IndexNowService
{
/**
* 检查 URL 是否真实存在,并将存在的 URL 推送到 IndexNow。
*
* 判断逻辑:
*
* 1. URL 格式正确
* 2. URL 属于当前站点
* 3. URL 实际可以访问(HTTP 2xx)
* 4. 只有通过以上检查的 URL 才推送 IndexNow
* 5. IndexNow 返回 200 / 202,认为提交成功
*
* @param array<int, string> $aUrlList
* @return bool
*/
public function pushUrls(array $aUrlList): bool
{
if (empty($aUrlList)) {
return false;
}
$sIndexNowKey = config('key.indexnow');
$sHostDomain = config('app.site_code', 'clashfreenode.com');
// TEST 时可以写死,但正式环境建议删除这一行
$sHostDomain = 'clashfreenode.com';
if (empty($sIndexNowKey) || empty($sHostDomain)) {
Log::error('IndexNow 配置缺失。');
return false;
}
/**
* ---------------------------------------------------------
* 1. 清理 URL
* ---------------------------------------------------------
*/
$aUrlList = array_values(array_unique(array_filter(
$aUrlList,
static function ($sUrl) {
return is_string($sUrl)
&& filter_var($sUrl, FILTER_VALIDATE_URL);
}
)));
if (empty($aUrlList)) {
return false;
}
/**
* ---------------------------------------------------------
* 2. 检查 URL 是否真实存在
* ---------------------------------------------------------
*/
$aValidUrlList = [];
foreach ($aUrlList as $sUrl) {
// 检查域名
$sUrlHost = parse_url($sUrl, PHP_URL_HOST);
if ($sUrlHost !== $sHostDomain) {
Log::warning('IndexNow URL 域名不匹配', [
'url' => $sUrl,
'host' => $sHostDomain,
]);
continue;
}
// 检查页面是否真实存在
if (!$this->urlExists($sUrl)) {
Log::warning('IndexNow 跳过不存在的 URL', [
'url' => $sUrl,
]);
continue;
}
$aValidUrlList[] = $sUrl;
}
/**
* 一个 URL 都不存在
*/
if (empty($aValidUrlList)) {
Log::warning('IndexNow 没有可推送的有效 URL', [
'count' => count($aUrlList),
]);
return false;
}
/**
* ---------------------------------------------------------
* 3. 构造 IndexNow Payload
* ---------------------------------------------------------
*/
$aPayloadData = [
'host' => $sHostDomain,
'key' => $sIndexNowKey,
'keyLocation' => "https://{$sHostDomain}/{$sIndexNowKey}.txt",
'urlList' => $aValidUrlList,
];
/**
* ---------------------------------------------------------
* 4. 推送 IndexNow
* ---------------------------------------------------------
*/
try {
$oResponse = Http::timeout(10)
->acceptJson()
->withHeaders([
'Content-Type' => 'application/json; charset=utf-8',
])
->post(
'https://api.indexnow.org/indexnow',
$aPayloadData
);
$iStatusCode = $oResponse->status();
/**
* 200 = 成功处理
* 202 = 已接受,等待处理
*/
if (in_array($iStatusCode, [200, 202], true)) {
Log::info('IndexNow 推送成功', [
'status' => $iStatusCode,
'count' => count($aValidUrlList),
'host' => $sHostDomain,
'urls' => $aValidUrlList,
]);
return true;
}
Log::error('IndexNow 推送失败', [
'status' => $iStatusCode,
'body' => $oResponse->body(),
'count' => count($aValidUrlList),
'host' => $sHostDomain,
'urls' => $aValidUrlList,
]);
return false;
} catch (Throwable $e) {
Log::error('IndexNow 请求异常', [
'message' => $e->getMessage(),
'count' => count($aValidUrlList),
'host' => $sHostDomain,
]);
return false;
}
}
/**
* 判断 URL 页面是否真实存在。
*
* 使用 GET 检查,跟搜索引擎实际访问页面的方式更接近。
*
* @param string $sUrl
* @return bool
*/
private function urlExists(string $sUrl): bool
{
try {
$oResponse = Http::timeout(10)
->withOptions([
'allow_redirects' => true,
])
->get($sUrl);
$iStatusCode = $oResponse->status();
Log::info('URL 页面检查', [
'url' => $sUrl,
'status' => $iStatusCode,
]);
/**
* 200 ~ 299
* 认为页面正常存在
*/
if ($oResponse->successful()) {
return true;
}
Log::warning('URL 页面不存在或无法访问', [
'url' => $sUrl,
'status' => $iStatusCode,
]);
return false;
} catch (Throwable $e) {
Log::warning('URL 页面检查异常', [
'url' => $sUrl,
'message' => $e->getMessage(),
]);
return false;
}
}
}

7
config/key.php Executable file
View File

@ -0,0 +1,7 @@
<?php
return [
'indexnow' => env('key_indexnow'),
];

View File

@ -0,0 +1 @@
8f3a9d2b1c4e7f0a8f3a9d2b1c4e7f0a

View File

@ -1,5 +1,3 @@
<!DOCTYPE html>
@props([
'sTitle' => config('app.title').' - '.config('app.name'),
'sDesc' => config('app.desc'),
@ -8,7 +6,7 @@
'sOgType' => 'website',
'sOgImg' => '/sites/'.config("app.site_code_short").'/siteimg.jpg',
])
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
@ -16,11 +14,15 @@
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<meta name="csrf-token" content="{{ csrf_token() }}">
<meta name="slug" content="{{ $sSlug }}">
<meta name="robots" content="index, follow">
<meta name="robots" content="{{ $sRobots ?? 'index, follow' }}">
@php
$sTodayDate = now()->format('Y年m月d日'); //有问题?
@endphp
{{-- SEO 三杰 --}}
<title>{{ $sTitle }}</title>
<meta name="description" content="{{ $sDesc }}">
<meta name="description" content="{{ $sTodayDate.$sDesc }}">
<meta name="keywords" content="{{ $sKeywords }}">
<link rel="canonical" href="{{ url()->current() }}">

View File

@ -1,14 +1,23 @@
@php
$iNoIndexDays = (int) ($oArticle->oCategory->aOpt['noindexday'] ?? 0);
$bIsExpired = $iNoIndexDays > 0 && $oArticle->created_at->addDays($iNoIndexDays)->isPast();
$sRobotsStatus = $bIsExpired ? 'noindex, follow' : 'index, follow';
@endphp
<x-app-layout
:sSlug="$oCategory->sSlug ?? ''"
:sTitle="$oArticle->sTitle . ' - ' . $oArticle->oCategory->sName"
:sDesc="$oArticle->sTitleSub"
sOgType="article"
:sOgImg="$oArticle->sThumb"
:sRobots="$sRobotsStatus"
>
@section('sTitle', $oArticle->sTitle . ' - ' . $oArticle->oCategory->sName)
@section('sDesc', $oArticle->sTitleSub)
@section('sOgType', 'article')
{{--
@section('sTitle', $oArticle->sTitle . ' - ' . ($oArticle->oCategory->sName ?? ''))
@section('sDesc', $oArticle->sTitleSub ?? '')
@section('sOgType', 'article')
--}}
<main class="site-main">
<div class="container">

View File

@ -10,6 +10,11 @@
use App\Http\Controllers\Api\v1\ArticlesController as ApiV1ArticlesController;
use App\Http\Controllers\Api\v1\FreenodeController as ApiV1FreenodeController;
Route::get('/test/hello', [TestController::class, 'hello']); // 找个控制器为什么无效了
Route::get('/test/test1', [TestController::class, 'test1']);
Route::get('/test/test2', [TestController::class, 'test2']);
Route::get('/test/test3', [TestController::class, 'test3']);
Route::post('/api/article/receive/shadowrocketids', [ApiV1ArticlesController::class, 'receiveShadowrocketids']);
Route::post('/api/article/receive/freenode', [ApiV1ArticlesController::class, 'receiveFreenode']);
Route::post('/api/article/receive', [ApiV1ArticlesController::class, 'receive']);
@ -42,7 +47,7 @@
//Route::get('/ajax/{sSlug1}/{sSlug2?}', [ArticlesController::class, 'listText'])
// ->name('articles.list.text');
Route::get('/hello', [TestController::class, 'hello']);
//Route::post('/ajax-handler', function () {
// return response()->json(['sStatus' => 'success']);