no message
3
.gitignore
vendored
@ -1 +1,2 @@
|
||||
.env
|
||||
.env
|
||||
public/fn
|
||||
@ -4,26 +4,19 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Controllers\Api\TG;
|
||||
|
||||
use App\Models\Article;
|
||||
//use App\Models\Article;
|
||||
use App\Services\TomTool\Http;
|
||||
use App\Services\TG\Http as TGHttp;
|
||||
|
||||
final class HookController
|
||||
{
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
// $this->middleware('csrf')->except(['cmd']);
|
||||
// 或者 $this->middleware('csrf')->only(['specificMethod']);
|
||||
}
|
||||
|
||||
|
||||
public function cmd()
|
||||
{
|
||||
|
||||
try {
|
||||
|
||||
|
||||
$oTGHttp = new TGHttp();
|
||||
|
||||
$oTGHttp->sApiToken = env('telegram_token');
|
||||
$oTGHttp->sApiChatId = env('telegram_chatid');
|
||||
|
||||
@ -31,7 +24,7 @@ final class HookController
|
||||
|
||||
$aUpdate = json_decode($sUpdate, true);
|
||||
|
||||
@file_put_contents('/www/_tg/bot_log.txt', json_encode($aUpdate, JSON_PRETTY_PRINT));
|
||||
// @file_put_contents('/www/_tg/bot_log.txt', json_encode($aUpdate, JSON_PRETTY_PRINT));
|
||||
|
||||
$aData['chatId'] = $aUpdate["message"]["chat"]["id"];
|
||||
$aData['fromId'] = $aUpdate["message"]["from"]["id"];
|
||||
|
||||
@ -132,6 +132,7 @@ class ListController extends Controller
|
||||
'sMenu' => $sMenu,
|
||||
'sType' => $sType,
|
||||
'sTypeSub' => $sTypeSub,
|
||||
// 'sSiteCode' => env('site_code'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -303,7 +303,12 @@ class ExecController extends Controller
|
||||
'美国、新加坡、日本、俄罗斯',
|
||||
'香港、台湾、美国、日本、新加坡、德国',
|
||||
'美国、新加坡、加拿大、香港、欧洲、韩国、日本',
|
||||
'美国、日本、新加坡、台湾'
|
||||
'美国、日本、新加坡、台湾',
|
||||
'日本、香港、台湾、越南、土耳其、阿根廷、俄罗斯',
|
||||
'日本、台湾、新加坡,韩国、俄罗斯、法国、美国、德国',
|
||||
'新加坡、日本、台湾、美国、韩国、德国、香港',
|
||||
'香港、台湾、日本、韩国、越南、阿根廷、俄罗斯、加拿大、美国',
|
||||
'上'
|
||||
];
|
||||
$iNodeRegionRandKey = array_rand($aNodeRegionPool);
|
||||
$sNodeZone = $aNodeRegionPool[$iNodeRegionRandKey];
|
||||
@ -398,6 +403,9 @@ class ExecController extends Controller
|
||||
// 直接生成文章
|
||||
public function freenodeDataAll ()
|
||||
{
|
||||
|
||||
ArticleList::where('type', 'node')->delete(); // 先删除节点文章
|
||||
|
||||
$sTimeSet = -env('freenode_keep_day');
|
||||
|
||||
for ($i=$sTimeSet; $i<=0; $i++) {
|
||||
@ -409,6 +417,7 @@ class ExecController extends Controller
|
||||
$sDateCodePrev = date("Ymd", $sTimePrev);
|
||||
|
||||
//// 文章入库 start
|
||||
|
||||
// 图片
|
||||
$iPrevImgId = ArticleList::where("code", $sDateCodePrev)->first()?->img_id;
|
||||
if ($iPrevImgId >= env('article_img_count')) {
|
||||
@ -486,6 +495,7 @@ class ExecController extends Controller
|
||||
dd($sDateCodeStart);
|
||||
}
|
||||
|
||||
// 指定文章静态化
|
||||
public function freenodeHtmlSingle($code)
|
||||
{
|
||||
|
||||
|
||||
@ -7,47 +7,86 @@ use App\Models\ArticleList;
|
||||
use App\Services\Time;
|
||||
use voku\helper\AntiXSS;
|
||||
use App\Models\Tags;
|
||||
use App\Services\TomTool\Http;
|
||||
|
||||
class SakaiController extends Controller
|
||||
{
|
||||
|
||||
public function tool() {
|
||||
|
||||
// $directory = 'feed'; // 替换为你的文件夹路径
|
||||
// $files = glob($directory . '/clash-*'); // 查找以sss开头的文件
|
||||
//
|
||||
// foreach ($files as $file) {
|
||||
// $pathInfo = pathinfo($file); // 获取文件信息
|
||||
// $newFileName = $pathInfo['dirname'] . '/' . $pathInfo['filename'] . '.yaml'; // 新文件名
|
||||
// rename($file, $newFileName); // 重命名文件
|
||||
// }
|
||||
//
|
||||
// echo "文件后缀已更改为 .ccc";
|
||||
//
|
||||
// exit;
|
||||
|
||||
// $k = request('k');
|
||||
//
|
||||
// if ($k != env('k')) {
|
||||
// exit;
|
||||
// }
|
||||
|
||||
$kv = [
|
||||
'节点每日更新 @cron' => '/exec/freenode/up',
|
||||
'静态生成 - 客户端文章' => '/exec/html/client',
|
||||
'模版 - 免费节点文章' => '/fn/single/20241231',
|
||||
'模版 - 客户端文章' => '/client/singe/1001',
|
||||
'静态生成 - 热门标签 @cron' => '/exec/html/toptags',
|
||||
'节点文章 - 批量抓' => '/exec/freenode/craw',
|
||||
'节点文章 - 自动删除 @cron' => '/exec/freenode/del',
|
||||
'点赞 - 初始数据' => '/exec/like/init',
|
||||
'点赞 - 自动增加 @cron' => '/exec/like/auto',
|
||||
'节点文章 - 生成数据' => '/exec/freenode/data/all',
|
||||
'所有文章 - 静态化' => '/exec/freenode/html/all',
|
||||
"/exec/cron" => "cron n合1",
|
||||
"@cron /exec/freenode/up" => "免费节点文章每日更新",
|
||||
"@cron /exec/freenode/del" => "免费节点文章自动删除(超过1年)",
|
||||
"@cron /exec/html/toptags" => "静态生成 - 热门标签",
|
||||
"@cron /exec/like/auto" => "自动点赞",
|
||||
"/exec/html/client" => "静态生成 - 客户端文章",
|
||||
"/exec/html/article" => "静态生成 - 所有文章",
|
||||
"/exec/html/single/{code}" => "静态生成 - 指定文章",
|
||||
"/exec/data/freenode/all" => "数据生成 - 所有免费节点文章(一年)(凭空生成无压力)",
|
||||
"/exec/like/init" => "点赞重新赋值 - 所有文章(无压力刷着玩)",
|
||||
"/exec/freenode/craw/{day}" => "免费节点文章批量抓(循环调用up)",
|
||||
];
|
||||
|
||||
return view('test/tool', [
|
||||
'ky' => $kv
|
||||
]);
|
||||
$str = "\n";
|
||||
foreach ($kv as $k => $v) {
|
||||
$str .= $k." >>> ".$v."\n\n";
|
||||
}
|
||||
$str .= "\n";
|
||||
|
||||
echo $str;
|
||||
exit;
|
||||
|
||||
}
|
||||
|
||||
public function test1()
|
||||
{
|
||||
@$k = $_GET["k"];
|
||||
@$s = $_GET["s"];
|
||||
|
||||
if ($k !== "wocaonide") {
|
||||
exit("?");
|
||||
}
|
||||
|
||||
$s = '/'.$s;
|
||||
|
||||
//test
|
||||
// $s = "\/AticleSet__1115zz__sale_rate 1118.118";
|
||||
// $s = "\/git#LastTime 1";
|
||||
$s= "/cmd#list";
|
||||
|
||||
$oHttp = new Http();
|
||||
$oHttp->sMethod = "post";
|
||||
$oHttp->sToUrl = env("APP_URL")."/api/tg/hook";
|
||||
$oHttp->bIsJson = true;
|
||||
$oHttp->aData = [
|
||||
'update_id' => 123456789,
|
||||
'message' => [
|
||||
'message_id' => 1,
|
||||
'from' => [
|
||||
'id' => 7740568271,
|
||||
'is_bot' => false,
|
||||
'first_name' => 'John',
|
||||
'last_name' => 'Doe',
|
||||
'username' => 'johndoe',
|
||||
'language_code' => 'en'
|
||||
],
|
||||
'chat' => [
|
||||
'id' => -4668400285,
|
||||
'first_name' => 'John',
|
||||
'last_name' => 'Doe',
|
||||
'username' => 'johndoe',
|
||||
'type' => 'private'
|
||||
],
|
||||
'date' => 1610000000,
|
||||
"text" => $s,
|
||||
]
|
||||
];
|
||||
|
||||
$r = $oHttp->send();
|
||||
|
||||
var_dump($r);
|
||||
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,112 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Controllers\Api\TG;
|
||||
|
||||
use App\Models\Article;
|
||||
use App\Services\TomTool\Http;
|
||||
use App\Services\TG\Http as TGHttp;
|
||||
|
||||
final class HookController
|
||||
{
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
// $this->middleware('csrf')->except(['cmd']);
|
||||
// 或者 $this->middleware('csrf')->only(['specificMethod']);
|
||||
}
|
||||
|
||||
|
||||
public function cmd()
|
||||
{
|
||||
|
||||
try {
|
||||
|
||||
$oTGHttp = new TGHttp();
|
||||
$oTGHttp->sApiToken = env('telegram_token');
|
||||
$oTGHttp->sApiChatId = env('telegram_chatid');
|
||||
|
||||
$sUpdate = file_get_contents("php://input");
|
||||
|
||||
$aUpdate = json_decode($sUpdate, true);
|
||||
|
||||
@file_put_contents('/www/_tg/bot_log.txt', json_encode($aUpdate, JSON_PRETTY_PRINT));
|
||||
|
||||
$aData['chatId'] = $aUpdate["message"]["chat"]["id"];
|
||||
$aData['fromId'] = $aUpdate["message"]["from"]["id"];
|
||||
|
||||
if (!isset($aUpdate["message"]["text"])) {
|
||||
throw new \Exception("?");
|
||||
}
|
||||
|
||||
$sText = $aUpdate["message"]["text"];
|
||||
|
||||
// test
|
||||
// $sText = "\\//Article#List ni__aaa__bbb 111 222";
|
||||
// $sText = "///\\\SaleCode#SetRate__zzxx 2";
|
||||
// $sText = "///\\\SaleCode#List";
|
||||
// $sText = "///\\\SaleCode#Find zzxx";
|
||||
// $sText = "/Article#Like__sale_code zzx";
|
||||
// $sText = "////Article#Add jxxjjjj";
|
||||
// $sText = "//\\\//Article#Del 9";
|
||||
// $sText = "/Article#Set__1__user_name xxx";
|
||||
|
||||
@$aArg = explode(" ", $sText);
|
||||
@$aOption = explode("__", $aArg[0]);
|
||||
|
||||
$sCmd = $this->cleanCmd($aOption[0]);
|
||||
|
||||
list($sClass, $sFunc) = explode("#", $sCmd);
|
||||
$sClass = ucfirst($sClass);
|
||||
$sFunc = ucfirst($sFunc);
|
||||
|
||||
unset($aOption[0]);
|
||||
unset($aArg[0]);
|
||||
|
||||
$aParams['aOption'] = $aOption;
|
||||
$aParams['aArg'] = $aArg;
|
||||
|
||||
$sClassPath = "App\\Services\\TG\\Hook\\Mod\\".$sClass;
|
||||
|
||||
if (method_exists($sClassPath, $sFunc)) {
|
||||
$oInstans = new $sClassPath();
|
||||
$r = $oInstans->$sFunc($aParams);
|
||||
|
||||
// 可以不返回,里面直接send
|
||||
if (isset($r)) {
|
||||
if (empty($r)) { $r = 'hook的mod返回空'; }
|
||||
// 返回可以是数组
|
||||
if (is_array($r)) {
|
||||
foreach ($r as $row) {
|
||||
$oTGHttp->sendToTG($row);
|
||||
}
|
||||
} else {
|
||||
$oTGHttp->sendToTG($r);
|
||||
}
|
||||
|
||||
Http::response(200, 'ok');
|
||||
}
|
||||
|
||||
} else {
|
||||
throw new \Exception("没有这个方法:".$sClass.'#'.$sFunc);
|
||||
}
|
||||
|
||||
} catch (\Throwable $e) {
|
||||
$sMessage = "错误(line:".$e->getLine()."): " . $e->getMessage();
|
||||
|
||||
$oTGHttp->sendToTG($sMessage);
|
||||
|
||||
Http::response(200, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
private function cleanCmd($input) {
|
||||
|
||||
$input = str_replace('\\', '', $input);
|
||||
$input = str_replace('/', '', $input);
|
||||
|
||||
return $input;
|
||||
}
|
||||
|
||||
}
|
||||
142
app/Services/TG/Hook/Mod/Article.php
Normal file
@ -0,0 +1,142 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\TG\Hook\Mod;
|
||||
use App\Models\Article as ModelArticle;
|
||||
|
||||
class Article extends Base {
|
||||
|
||||
public function List($aParam)
|
||||
{
|
||||
if (isset($aParam['aOption'][1])) {
|
||||
$sOrderBy = $aParam['aOption'][1];
|
||||
} else {
|
||||
$sOrderBy = "i_in10";
|
||||
}
|
||||
|
||||
$aArticleList = ModelArticle::orderBy($sOrderBy)->get()->toArray();
|
||||
|
||||
foreach ($aArticleList as &$row) { // 使用引用来修改原数组
|
||||
unset($row['updated_at']); // 移除 updated_at 字段
|
||||
unset($row['created_at']); // 移除 created_at 字段
|
||||
$this->oTGHttp->sendToTG(json_encode($row, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT));
|
||||
}
|
||||
|
||||
$this->oHttp::response(200, 'ok');
|
||||
}
|
||||
|
||||
public function Find($aParam)
|
||||
{
|
||||
$iId = $aParam['aArg'][1];
|
||||
|
||||
$aSingle = ModelArticle::find($iId)->toArray();
|
||||
|
||||
unset($aSingle['updated_at']);
|
||||
unset($aSingle['created_at']);
|
||||
|
||||
return json_encode($aSingle, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
|
||||
}
|
||||
|
||||
|
||||
public function Like($aParams)
|
||||
{
|
||||
$aArticleList = ModelArticle::where($this->cmdGood($aParams['aOption'][1]), 'like', '%' . $aParams['aArg'][1] . '%')
|
||||
->orderBy("user_name")
|
||||
->get()
|
||||
->toArray();
|
||||
|
||||
if (empty($aArticleList)) {
|
||||
$this->oTGHttp->sendToTG("没有");
|
||||
} else {
|
||||
foreach ($aArticleList as &$row) { // 使用引用来修改原数组
|
||||
unset($row['updated_at']); // 移除 updated_at 字段
|
||||
unset($row['created_at']); // 移除 created_at 字段
|
||||
$this->oTGHttp->sendToTG(json_encode($row, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT));
|
||||
}
|
||||
}
|
||||
|
||||
$this->oHttp::response(200, 'ok');
|
||||
}
|
||||
|
||||
public function Clone($aParam)
|
||||
{
|
||||
$iId = $aParam['aArg'][1];
|
||||
|
||||
// 查找文章
|
||||
$aArticle = ModelArticle::find($iId);
|
||||
|
||||
if ($aArticle) {
|
||||
// 复制文章
|
||||
$newArticle = $aArticle->replicate();
|
||||
|
||||
// 如果需要,可以修改新文章的某些字段,例如标题或状态
|
||||
// $newArticle->title = $newArticle->title . ' - Copy'; // 修改标题
|
||||
// $newArticle->status = 'draft'; // 例如,将状态设置为草稿
|
||||
|
||||
// 保存新文章
|
||||
$newArticle->save();
|
||||
|
||||
// 发送新文章的 ID 到 Telegram
|
||||
$sMsg = "新文章已创建,ID: " . $newArticle->id;
|
||||
$this->oTGHttp->sendToTG($sMsg);
|
||||
|
||||
// 返回 HTTP 响应
|
||||
$this->oHttp::response(200, 'ok');
|
||||
} else {
|
||||
throw new \Exception("没有这个id");
|
||||
}
|
||||
}
|
||||
|
||||
public function Add($aParams)
|
||||
{
|
||||
|
||||
$newArticle = new ModelArticle();
|
||||
$newArticle->user_name = $aParams['aArg'][1];
|
||||
$r = $newArticle->save();
|
||||
|
||||
$this->oTGHttp->sendToTG(json_encode($r, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT));
|
||||
|
||||
$this->oHttp::response(200, 'ok');
|
||||
|
||||
}
|
||||
|
||||
public function Del($aParams)
|
||||
{
|
||||
|
||||
$article = ModelArticle::find($aParams['aArg'][1]);
|
||||
|
||||
if ($article) {
|
||||
$r = $article->delete();
|
||||
} else {
|
||||
$r = false;
|
||||
}
|
||||
|
||||
$this->oTGHttp->sendToTG(json_encode($r, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT));
|
||||
|
||||
$this->oHttp::response(200, 'ok');
|
||||
|
||||
}
|
||||
|
||||
// /ArticleSet__id__user_name xxx
|
||||
public function Set($aParams)
|
||||
{
|
||||
$sField = $this->cmdGood($aParams['aOption'][2]);
|
||||
|
||||
$article = ModelArticle::find($aParams['aOption'][1]);
|
||||
|
||||
$sSet = $aParams['aArg'][1];
|
||||
|
||||
if ($article) {
|
||||
$article->$sField = $sSet;
|
||||
|
||||
$r = $article->save();
|
||||
} else {
|
||||
// 处理未找到的情况
|
||||
throw new \Exception("Article not found");
|
||||
}
|
||||
|
||||
$this->oTGHttp->sendToTG(json_encode($r, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT));
|
||||
|
||||
$this->oHttp::response(200, 'ok');
|
||||
}
|
||||
|
||||
}
|
||||
43
app/Services/TG/Hook/Mod/Base.php
Normal file
@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\TG\Hook\Mod;
|
||||
//use App\Services\TomTool\Http;
|
||||
//use App\Models\Article as ModelArticle;
|
||||
use App\Services\TomTool\Http;
|
||||
use App\Services\TG\Http as TGHttp;
|
||||
|
||||
class Base {
|
||||
|
||||
public function __construct() {
|
||||
$this->oHttp = new Http();
|
||||
$this->oTGHttp = new TGHttp();
|
||||
// $this->oTGHttp->sApiToken = env("telegram_token");
|
||||
// $this->oTGHttp->sApiChatId = env("telegram_chatid");
|
||||
}
|
||||
|
||||
protected function cmdGood($sCmd) {
|
||||
|
||||
$sCmdNew = "";
|
||||
switch ($sCmd) {
|
||||
case "user":
|
||||
$sCmdNew = "user_name";
|
||||
break;
|
||||
case "project":
|
||||
$sCmdNew = "project_name";
|
||||
break;
|
||||
case "code":
|
||||
$sCmdNew = "sale_code";
|
||||
break;
|
||||
case "condition":
|
||||
$sCmdNew = "cron_condition";
|
||||
break;
|
||||
default:
|
||||
$sCmdNew = $sCmd;
|
||||
break;
|
||||
}
|
||||
|
||||
return $sCmdNew;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
34
app/Services/TG/Hook/Mod/Cmd.php
Normal file
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\TG\Hook\Mod;
|
||||
use App\Models\Article as ModelArticle;
|
||||
|
||||
class Cmd extends Base {
|
||||
|
||||
public function List()
|
||||
{
|
||||
|
||||
$aCmdList = [
|
||||
'优惠码list' => 'SaleCode#List',
|
||||
'优惠码find' => 'SaleCode#Find xxhh',
|
||||
'优惠码rate' => 'SaleCode#SetRate__xxzz 6.7',
|
||||
'文章list' => 'Article#List',
|
||||
'文章like' => 'Article#Like__field like',
|
||||
'文章add' => 'Article#Add__name',
|
||||
'文章del' => 'Article#Del__id',
|
||||
'文章set' => 'Article#Set__id__fild set',
|
||||
// '添加github的sshhost' => "System#AddSshHostGithub",
|
||||
'文章clone' => "article#clone id",
|
||||
'git手动重置' => "git#pullR",
|
||||
'文章find' => "article#find id",
|
||||
'cron暂停' => "option#pause 1",
|
||||
'测试cron' => "test#cron_i 01",
|
||||
];
|
||||
|
||||
$this->oTGHttp->sendToTG(json_encode($aCmdList, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT));
|
||||
|
||||
$this->oHttp::response(200, 'ok');
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
128
app/Services/TG/Hook/Mod/Git.php
Normal file
@ -0,0 +1,128 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\TG\Hook\Mod;
|
||||
use App\Models\Article as ModelArticle;
|
||||
|
||||
class Git extends Base {
|
||||
|
||||
public function UrlList()
|
||||
{
|
||||
$aArticleList = ModelArticle::orderBy('user_name')->get()->toArray();
|
||||
|
||||
$sMsg = '';
|
||||
foreach ($aArticleList as $v) {
|
||||
$sMsg .= "\n\n";
|
||||
$sMsg .= "https://github.com/".$v['user_name']."/".$v['project_name'];
|
||||
}
|
||||
|
||||
return $sMsg;
|
||||
|
||||
}
|
||||
|
||||
public function LastTime($aParam)
|
||||
{
|
||||
$iId = $aParam['aArg'][1];
|
||||
|
||||
$aArticle = ModelArticle::find($iId);
|
||||
|
||||
$sProjectPath = env("BASE_DIR") . "github/" . $aArticle->user_name . "-" . $aArticle->project_name;
|
||||
|
||||
// 进入指定目录
|
||||
if (!chdir($sProjectPath)) {
|
||||
throw new \Exception("无法进入目录" . $sProjectPath);
|
||||
}
|
||||
|
||||
// 获取远程更新
|
||||
$this->runCommand('git fetch origin');
|
||||
|
||||
// 获取最后提交的时间
|
||||
$lastCommitTime = $this->runCommand('git log origin/main -1 --format=%cd');
|
||||
$lastCommitTime = \DateTime::createFromFormat('D M d H:i:s Y O', $lastCommitTime[0]);
|
||||
$lastCommitTime = json_encode($lastCommitTime->format('Y-m-d H:i:s'));
|
||||
|
||||
// 检查是否获取到时间
|
||||
if (empty($lastCommitTime)) {
|
||||
throw new \Exception("无法获取最后提交时间,可能是分支不存在或没有提交。");
|
||||
}
|
||||
|
||||
return $lastCommitTime;
|
||||
|
||||
}
|
||||
|
||||
// 没用
|
||||
public function AddSshHostGithub()
|
||||
{
|
||||
|
||||
// 定义要添加的主机
|
||||
$host = 'github.com';
|
||||
|
||||
// 执行 ssh-keyscan 命令
|
||||
$key = shell_exec("ssh-keyscan -t ed25519 $host");
|
||||
|
||||
// 检查是否成功获取到公钥
|
||||
if ($key) {
|
||||
// 获取 known_hosts 文件的路径
|
||||
$knownHostsFile = '/root/.ssh/known_hosts';
|
||||
|
||||
// 检查 known_hosts 文件中是否已经存在该主机的公钥
|
||||
if (strpos(file_get_contents($knownHostsFile), $host) === false) {
|
||||
// 将公钥写入 known_hosts 文件
|
||||
file_put_contents($knownHostsFile, $key, FILE_APPEND);
|
||||
$sMsg = "公钥已成功添加到 $knownHostsFile\n";
|
||||
} else {
|
||||
$sMsg = "公钥已存在于 $knownHostsFile\n";
|
||||
}
|
||||
} else {
|
||||
$sMsg = "无法获取 $host 的公钥\n";
|
||||
}
|
||||
|
||||
$this->oTGHttp->sendToTG($sMsg);
|
||||
|
||||
$this->oHttp::response(200, 'ok');
|
||||
|
||||
}
|
||||
|
||||
// /Git#PullR 3
|
||||
public function PullR($aParam)
|
||||
{
|
||||
|
||||
$iId = $aParam['aArg'][1];
|
||||
|
||||
$aArticle = ModelArticle::find($iId);
|
||||
|
||||
$sProjectPath = env("BASE_DIR")."github/".$aArticle->user_name."-".$aArticle->project_name;
|
||||
|
||||
// 进入指定目录
|
||||
if (!chdir($sProjectPath)) {
|
||||
throw new \Exception("无法进入目录".$sProjectPath);
|
||||
}
|
||||
|
||||
// 获取远程更新
|
||||
$this->runCommand('git fetch origin');
|
||||
|
||||
// 硬重置到远程主分支
|
||||
$this->runCommand('git reset --hard origin/main');
|
||||
|
||||
$this->oTGHttp->sendToTG("操作完成:已重置到远程主分支");
|
||||
|
||||
$this->oHttp::response(200, 'ok');
|
||||
|
||||
}
|
||||
|
||||
private function runCommand($command) {
|
||||
$output = [];
|
||||
$returnVar = 0;
|
||||
exec($command, $output, $returnVar);
|
||||
|
||||
if ($returnVar !== 0) {
|
||||
$jsonOutput = json_encode($output, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
|
||||
$errorMessage = "命令失败: $command\n" . $jsonOutput . "\n";
|
||||
|
||||
throw new \Exception($errorMessage);
|
||||
} else {
|
||||
return $output;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
34
app/Services/TG/Hook/Mod/Option.php
Normal file
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\TG\Hook\Mod;
|
||||
use App\Models\Option as ModelOption;
|
||||
|
||||
class Option extends Base {
|
||||
|
||||
public function Pause($aParam)
|
||||
{
|
||||
$v = $aParam['aArg'][1];
|
||||
|
||||
// 获取第一个匹配的选项
|
||||
$oOption = ModelOption::where("type", "pause")->first();
|
||||
|
||||
// 检查是否找到了选项
|
||||
if ($oOption) {
|
||||
$oOption->value = $v;
|
||||
|
||||
// 保存并返回结果
|
||||
return json_encode($oOption->save());
|
||||
}
|
||||
|
||||
// 如果没有找到选项,返回一个错误信息
|
||||
return json_encode(['error' => 'Option not found']);
|
||||
}
|
||||
|
||||
public function List()
|
||||
{
|
||||
$aOptionList = ModelOption::all()->toArray();
|
||||
|
||||
return json_encode($aOptionList, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
|
||||
}
|
||||
|
||||
}
|
||||
48
app/Services/TG/Hook/Mod/SaleCode.php
Normal file
@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\TG\Hook\Mod;
|
||||
use App\Models\Article as ModelArticle;
|
||||
|
||||
class SaleCode extends Base {
|
||||
|
||||
public function SetRate($aParams)
|
||||
{
|
||||
$updatedRows = ModelArticle::where('sale_code', $aParams['aOption'][1])
|
||||
->update(['sale_rate' => $aParams['aArg'][1]]);
|
||||
|
||||
$this->oTGHttp->sendToTG(json_encode($updatedRows, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT));
|
||||
|
||||
$this->oHttp::response(200, 'ok');
|
||||
|
||||
}
|
||||
|
||||
public function List()
|
||||
{
|
||||
$aSaleCodeList = ModelArticle::select('sale_code', 'sale_rate')
|
||||
->distinct()
|
||||
->orderBy("sale_code")
|
||||
->get()
|
||||
->toArray();
|
||||
|
||||
$this->oTGHttp->sendToTG(json_encode($aSaleCodeList, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT));
|
||||
|
||||
$this->oHttp::response(200, 'ok');
|
||||
}
|
||||
|
||||
public function Find($aParams)
|
||||
{
|
||||
|
||||
$aSaleCodeList = ModelArticle::select('sale_code', 'sale_rate')
|
||||
->where("sale_code", $aParams['aArg'][1])
|
||||
->distinct()
|
||||
->orderBy("sale_code")
|
||||
->get()
|
||||
->toArray();
|
||||
|
||||
$this->oTGHttp->sendToTG(json_encode($aSaleCodeList, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT));
|
||||
|
||||
$this->oHttp::response(200, 'ok');
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
28
app/Services/TG/Hook/Mod/Test.php
Normal file
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\TG\Hook\Mod;
|
||||
//use App\Services\TomTool\Http;
|
||||
|
||||
class Test extends Base {
|
||||
|
||||
public function Cron($aParam)
|
||||
{
|
||||
$sTimeType = $aParam["aOption"][1];
|
||||
$sValue = $aParam["aArg"][1];
|
||||
|
||||
$this->oHttp->sMethod = "get";
|
||||
$this->oHttp->sToUrl = env("APP_URL")."/cron";
|
||||
$this->oHttp->bIsJson = true;
|
||||
$this->oHttp->aData = [
|
||||
"is_test" => true,
|
||||
"time_type" => $sTimeType,
|
||||
"v" => $sValue
|
||||
];
|
||||
|
||||
$r = $this->oHttp->send();
|
||||
|
||||
return $r;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
29
app/Services/TG/Http.php
Normal file
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\TG;
|
||||
|
||||
class Http {
|
||||
|
||||
public $sApiToken;
|
||||
public $sApiChatId;
|
||||
|
||||
function __construct()
|
||||
{
|
||||
$this->sApiToken = env('telegram_token');
|
||||
$this->sApiChatId = env('telegram_chatid');
|
||||
}
|
||||
|
||||
public function sendToTG($sMsg)
|
||||
{
|
||||
|
||||
if (env('is_loc') == true) {
|
||||
echo "<pre>";
|
||||
echo($sMsg);
|
||||
} else {
|
||||
$url = "https://api.telegram.org/bot$this->sApiToken/sendMessage?chat_id=$this->sApiChatId&text=" . urlencode($sMsg);
|
||||
file_get_contents($url);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -14,6 +14,9 @@ return Application::configure(basePath: dirname(__DIR__))
|
||||
$middleware->alias([
|
||||
'test' => \App\Http\Middleware\Test::class,
|
||||
]);
|
||||
$middleware->validateCsrfTokens(except: [
|
||||
'api/*',
|
||||
]);
|
||||
})
|
||||
->withExceptions(function (Exceptions $exceptions) {
|
||||
//
|
||||
|
||||
|
Before Width: | Height: | Size: 858 KiB |
|
Before Width: | Height: | Size: 569 KiB |
|
Before Width: | Height: | Size: 739 KiB |
|
Before Width: | Height: | Size: 958 KiB |
|
Before Width: | Height: | Size: 768 KiB |
|
Before Width: | Height: | Size: 1.1 MiB |
|
Before Width: | Height: | Size: 569 KiB |
|
Before Width: | Height: | Size: 325 KiB |
|
Before Width: | Height: | Size: 739 KiB |
|
Before Width: | Height: | Size: 870 KiB |
|
Before Width: | Height: | Size: 1.1 MiB |
|
Before Width: | Height: | Size: 9.2 KiB |
|
Before Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 4.7 KiB |
|
Before Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 6.1 KiB |
|
Before Width: | Height: | Size: 6.6 KiB |
|
Before Width: | Height: | Size: 9.0 KiB |
|
Before Width: | Height: | Size: 6.3 KiB |
|
Before Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 22 KiB |
@ -1,16 +1 @@
|
||||
.site-main {
|
||||
min-height:1000px;
|
||||
}
|
||||
|
||||
.menua-checked {
|
||||
color:#A758A5;
|
||||
}
|
||||
|
||||
.menua:hover {
|
||||
color:#A758A5 !important;
|
||||
}
|
||||
|
||||
.menuaSub:hover {
|
||||
color:#A758A5 !important;
|
||||
}
|
||||
|
||||
|
||||
@ -1,29 +1,37 @@
|
||||
:root {
|
||||
--btn-primary:#00A8B1;
|
||||
--color-primary:#00A8B1;
|
||||
}
|
||||
|
||||
.site-main {
|
||||
min-height:1000px;
|
||||
}
|
||||
|
||||
.menua-checked {
|
||||
color:#A758A5;
|
||||
color: var(--color-primary);
|
||||
}
|
||||
|
||||
.menua:hover {
|
||||
color:#A758A5 !important;
|
||||
color:var(--color-primary) !important;
|
||||
}
|
||||
|
||||
.menuaSub:hover {
|
||||
color:#A758A5 !important;
|
||||
color:var(--color-primary) !important;
|
||||
}
|
||||
|
||||
.widget-border {
|
||||
//background-image: linear-gradient(to right,#3858f6,#6e86ff,#8068ff,#3858f6);
|
||||
background-image: linear-gradient(to right,#7E427C,#995097,#A359A1,#7E427C) !important;
|
||||
}
|
||||
|
||||
:root {
|
||||
--btn-primary:#A758A5;
|
||||
--color-primary:#A758A5;
|
||||
background-image: linear-gradient(to right,#00A8B1,#83C4C8,#BAE2DD,#83C4C8);
|
||||
//background-image: linear-gradient(to right,#7E427C,#995097,#A359A1,#7E427C) !important;
|
||||
}
|
||||
|
||||
/*.list-home {*/
|
||||
/* height:500px;*/
|
||||
/*}*/
|
||||
|
||||
.header .navbar-brand img {
|
||||
max-height: 50px;
|
||||
}
|
||||
|
||||
.header .navbar-brand {
|
||||
max-width: 250px;
|
||||
}
|
||||
|
||||
BIN
public/site/clashv2rayfree.com/images/article/1.png
Normal file
|
After Width: | Height: | Size: 1.5 MiB |
BIN
public/site/clashv2rayfree.com/images/article/10.png
Normal file
|
After Width: | Height: | Size: 821 KiB |
BIN
public/site/clashv2rayfree.com/images/article/11.png
Normal file
|
After Width: | Height: | Size: 369 KiB |
BIN
public/site/clashv2rayfree.com/images/article/12.png
Normal file
|
After Width: | Height: | Size: 298 KiB |
BIN
public/site/clashv2rayfree.com/images/article/13.png
Normal file
|
After Width: | Height: | Size: 866 KiB |
|
Before Width: | Height: | Size: 509 KiB After Width: | Height: | Size: 509 KiB |
BIN
public/site/clashv2rayfree.com/images/article/2.png
Normal file
|
After Width: | Height: | Size: 638 KiB |
BIN
public/site/clashv2rayfree.com/images/article/3.png
Normal file
|
After Width: | Height: | Size: 1.4 MiB |
BIN
public/site/clashv2rayfree.com/images/article/4.png
Normal file
|
After Width: | Height: | Size: 326 KiB |
BIN
public/site/clashv2rayfree.com/images/article/5.png
Normal file
|
After Width: | Height: | Size: 360 KiB |
BIN
public/site/clashv2rayfree.com/images/article/6.png
Normal file
|
After Width: | Height: | Size: 503 KiB |
BIN
public/site/clashv2rayfree.com/images/article/7.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
public/site/clashv2rayfree.com/images/article/8.png
Normal file
|
After Width: | Height: | Size: 815 KiB |
|
After Width: | Height: | Size: 653 KiB |
|
After Width: | Height: | Size: 975 KiB |
|
Before Width: | Height: | Size: 13 KiB |
@ -7,7 +7,7 @@
|
||||
class="media-content"
|
||||
href="{{$row['pathBase']}}{{$row['code']}}.html"
|
||||
title="「{{$row['date_str']}}」{{$row['title']}}"
|
||||
style="background-image:url('/images/article/{{$row['img_id']}}.png')"
|
||||
style="background-image:url('/site/{{env('site_code')}}/images/article/{{$row['img_id']}}.png')"
|
||||
></a>
|
||||
</div>
|
||||
<div class="list-content">
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
<meta name="keywords" content="{{$aData['pageKw']}}" />
|
||||
<meta name="description" content="{{$aData['title_sub']}}" />
|
||||
<link rel="stylesheet" href="/sakai/css/single.css">
|
||||
<link rel="icon" href="/images/icon.png" type="image/x-icon">
|
||||
<link rel="icon" href="/site/{{env('site_code')}}/images/logo/icon.png" type="image/x-icon">
|
||||
<link rel="alternate" type="application/rss+xml" title="{{env('APP_NAME')}} » Feed" href="feed" />
|
||||
<link rel="alternate" type="application/rss+xml" title="{{env('APP_NAME')}} » 评论 Feed" href="comments/feed" />
|
||||
<link rel="alternate" type="application/rss+xml" title="{{env('APP_NAME')}} » {{$aData['title']}} 评论 Feed" href="{{$aData['pathBase']}}{{$aData['code']}}.html/feed" />
|
||||
|
||||
@ -1,11 +1,12 @@
|
||||
<script src="/sakai/js/common.js"></script>
|
||||
<link href="/sakai/css/common.css" rel="stylesheet" type="text/css">
|
||||
<link href="/site/{{env('site_code')}}/css/common.css" rel="stylesheet" type="text/css">
|
||||
|
||||
<header class="header">
|
||||
<nav class="navbar navbar-expand-xl shadow">
|
||||
<div class="container">
|
||||
<a href="/" rel="home" class="logo navbar-brand order-2 order-xl-1">
|
||||
<img style="border-radius:8px; " src="/images/logo3.png"
|
||||
<img style="border-radius:8px; " src="/site/{{env('site_code')}}/images/logo/logo.png"
|
||||
class="d-inline-block logo-light nc-no-lazy"
|
||||
alt="{{env('APP_NAME')}}">
|
||||
<img src="/images/logo.png"
|
||||
@ -107,21 +108,3 @@
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<style>
|
||||
|
||||
.widget-border {
|
||||
//background-image: linear-gradient(to right,#3858f6,#6e86ff,#8068ff,#3858f6);
|
||||
background-image: linear-gradient(to right,#7E427C,#995097,#A359A1,#7E427C) !important;
|
||||
}
|
||||
|
||||
:root {
|
||||
--btn-primary:#A758A5;
|
||||
--color-primary:#A758A5;
|
||||
}
|
||||
|
||||
.list-home {
|
||||
// height:500px;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
@ -9,8 +9,17 @@ use App\Http\Controllers\HelperController;
|
||||
use App\Http\Controllers\HtmlController;
|
||||
use App\Http\Controllers\SakaiController;
|
||||
use App\Http\Controllers\Api\GithubController;
|
||||
use App\Http\Controllers\Api\TG\HookController;
|
||||
|
||||
//Route::get('/', [ArticleListController::class, 'fn'])->middleware('test');
|
||||
|
||||
Route::get('/test1', [SakaiController::class, 'test1']);
|
||||
Route::get('/test2', [SakaiController::class, 'test2']);
|
||||
Route::get('/test3', [SakaiController::class, 'test3']);
|
||||
Route::get('/test4', [SakaiController::class, 'test4']);
|
||||
Route::get('/test5', [SakaiController::class, 'test5']);
|
||||
|
||||
Route::any('/api/tg/hook', [HookController::class, 'cmd']);
|
||||
|
||||
Route::get('/', [ArticleListController::class, 'fn']);
|
||||
Route::get('/fn', [ArticleListController::class, 'fn']); // 免费节点list
|
||||
@ -22,14 +31,15 @@ Route::get('/mix', [ArticleListController::class, 'mix']); // 混合 = 搜索 or
|
||||
Route::get('/client/single/{code}', [ArticleSingleController::class, 'client']); // 客户端single
|
||||
Route::get('/fn/single/{code}', [ArticleSingleController::class, 'freenode']); // 免费节点single
|
||||
|
||||
Route::get('/tool', [SakaiController::class, 'tool']);
|
||||
Route::get('/exec/freenode/craw/{day}', [ExecController::class, 'freenodeCraw']); // 免费节点文章批量抓取
|
||||
Route::get('/exec/freenode/up', [ExecController::class, 'freenodeUp']); // 免费节点文章每日更新
|
||||
Route::get('/exec/freenode/del', [ExecController::class, 'freenodeDelAuto']); // 免费节点自动删除
|
||||
Route::get('/exec/html/toptags', [ExecController::class, 'tagCountToHtml']); // 热门标签静态生成
|
||||
Route::get('/exec/html/client', [ExecController::class, 'clientSingleToHtml']); // 客户端文章静态生成
|
||||
Route::get('/exec/freenode/html/all', [ExecController::class, 'freenodeHtmlAll']); // 所有文章静态生成
|
||||
Route::get('/exec/freenode/html/single/{code}', [ExecController::class, 'freenodeHtmlSingle']); // 所有文章静态生成
|
||||
Route::get('/exec/freenode/data/all', [ExecController::class, 'freenodeDataAll']); // 所有文章数据生成
|
||||
Route::get('/exec/html/article', [ExecController::class, 'freenodeHtmlAll']); // 所有文章静态生成
|
||||
Route::get('/exec/html/single/{code}', [ExecController::class, 'freenodeHtmlSingle']); // 所有文章静态生成
|
||||
Route::get('/exec/data/freenode/all', [ExecController::class, 'freenodeDataAll']); // 所有文章数据生成
|
||||
Route::get('/exec/like/auto', [ExecController::class, 'likeAuto']); // 自动点赞
|
||||
Route::get('/exec/like/init', [ExecController::class, 'likeInit']); // 点赞初始
|
||||
Route::get('/exec/cron', [ExecController::class, 'cron']); // cron n合1
|
||||
@ -38,7 +48,5 @@ Route::get('/helper/timelost/{articleTime}', [HelperController::class, 'timeLost
|
||||
Route::get('/helper/like/up/{id}', [HelperController::class, 'likeUp']); // 点赞ajax
|
||||
Route::get('/helper/like/get/{id}', [HelperController::class, 'likeGet']); // 点赞数ajax
|
||||
|
||||
Route::get('/sakai/tool', [SakaiController::class, 'tool']);
|
||||
|
||||
Route::get('/api/github/todayupd', [GithubController::class, 'todayUpd']);
|
||||
Route::get('/api/github/getlast', [GithubController::class, 'getLast']);
|
||||
|
||||