"🇺🇸", "日本" => "🇯🇵", "台湾" => "🇹🇼", "香港" => "🇭🇰", "新加坡" => "🇸🇬", "越南" => "🇻🇳", "俄罗斯" => "🇷🇺", "韩国" => "🇰🇷", ]; // public static function buildSogan($aNode) // { // // todo 广告位,这样就固定了 // } private static function isSlogan($s) { if ($s == "{{slogan_siteUrl}}" || $s == "{{slogan_telegram}}" || $s == "{{slogan_date}}") { return true; } return false; } public static function save() { echo "\nFreenodeFile::save - 开始 \n"; //// test // $a = ["a", "b", "c"]; // $b = ["b", "c", "d"]; // $c = array_merge($a, $b); // $c = array_unique($c); // $c = array_values($c); // tomd($c, 1); //// test end $sDirBase = $_ENV["dir_base"]; $sDate = date("Y-m-d"); // $sDate = "2025-12-12"; // *test $oPool = ModelFreenodePool::whereDate("date", $sDate)->first(); $aPoolContentList = json_decode($oPool->content, true); foreach ($aPoolContentList as $sPoolClient => $aPoolContent) { $aNodeGroupCountry = []; $aLastNode = []; $aLastNodeMy = []; foreach ($aPoolContent as $sMd5 => $aNode) { $sFromName = $aNode["fromName"]; $sCountry = $aNode["country"]; $sProtocolType = $aNode["protocolType"]; $sConfig = $aNode["config"]; $sCountryClear = self::strReplace($sCountry, $sFromName); $aNodeGroupCountry[$sCountryClear][] = $aNode; if ($sFromName == "_my") { $aLastNodeMy = $aNode; } $aLastNode = $aNode; } $aSloganNode = $aLastNode; if ($aLastNodeMy) { $aSloganNode = $aLastNodeMy; } $aNodeGroupCountry["{{slogan_siteUrl}}"][] = $aSloganNode; $aNodeGroupCountry["{{slogan_telegram}}"][] = $aSloganNode; $aNodeGroupCountry["{{slogan_date}}"][] = $aSloganNode; $aNodeSortCountry = []; foreach (self::$aCountryOrder as $sCountryOrder) { if (array_key_exists($sCountryOrder, $aNodeGroupCountry)) { if (self::isSlogan($sCountryOrder)) { $aNodeSortCountry[$sCountryOrder] = [ $aNodeGroupCountry[$sCountryOrder][0] // 得到多个slogan只要第一个,按理不用处理,保险 ]; } else { $aNodeSortCountry[$sCountryOrder] = $aNodeGroupCountry[$sCountryOrder]; } } } foreach ($aNodeGroupCountry as $sCountry => $aNode) { if (!array_key_exists($sCountry, self::$aCountryOrder)) { $aNodeSortCountry[$sCountry] = $aNode; } } $aNodeMerge = []; $aNodeCountryList = []; foreach ($aNodeSortCountry as $sCountry => $aNodeList) { $i = 1; foreach ($aNodeList as $aNode) { if (self::isSlogan($sCountry)) { $aNode["country"] = $sCountry; } else { $aNode["country"] = $sCountry." ".sprintf('%02d', $i); } $aNode["country"] = $aNode["country"]." :[".$aNode["fromName"]."]:"; if ($sPoolClient == "v2ray") { $sNodeNameWei = "#".urlencode($aNode["country"]); $sConfig = $aNode["config"]; if (is_array($sConfig)) { if ($aNode["protocolType"] == "vmess") { $sConfig["ps"] = urlencode($aNode["country"]); $sNodeNameWei = ""; } $sConfig = json_encode($sConfig); } $sNode = $aNode["protocolType"]."://".$sConfig.$sNodeNameWei; $aNodeMerge[] = $sNode; } else if ($sPoolClient == "clash") { $sFlagCountry = self::countryJoinFlag($aNode["country"]); $aNode["config"]["name"] = $sFlagCountry; $aNodeMerge[] = $aNode["config"]; $aNodeCountryList[] = $sFlagCountry; } else if ($sPoolClient == "singbox") { $sFlagCountry = self::countryJoinFlag($aNode["country"]); $aNode["config"]["tag"] = $sFlagCountry; $aNodeMerge[] = $aNode["config"]; $aNodeCountryList[] = $sFlagCountry; } else { $aNodeMerge[] = json_encode($aNode); } $i++; } } if ($sPoolClient == "v2ray") { $sMerge = implode("\n", $aNodeMerge); $sMerge = base64_encode($sMerge); } else if ($sPoolClient == "clash") { $sFile = $sDirBase."public/freenode/template/clash.txt"; if (file_exists($sFile) && is_readable($sFile)) { $sClashTemplate = file_get_contents($sFile); // data } else { $sMsg = "clash的template不存在,这不应该 \n"; TeleSlave::warn()->send($sMsg); echo $sMsg; continue; } $aClashTemplate = Yaml::parse($sClashTemplate); $aClashTemplate["proxies"] = $aNodeMerge; $aProxyGroupList = &$aClashTemplate["proxy-groups"]; foreach ($aProxyGroupList as &$aProxyGroup) { if (!isset($aProxyGroup["proxies"])) { $aProxyGroup["proxies"] = []; } if ($aProxyGroup["name"] == "🍃 应用净化") { continue; } if ($aProxyGroup["name"] == "🛑 全球拦截") { continue; } if ($aProxyGroup["name"] == "🎯 全球直连") { continue; } $aProxyGroup["proxies"] = self::arrMerge($aProxyGroup["proxies"], $aNodeCountryList); } $sMerge = Yaml::dump($aClashTemplate, 4, 2); $sPattern = '/(?<=^|\s)(cipher|name|type):\s+((?!\'|")[^\s"\'\n]+)/m'; $sMerge = preg_replace($sPattern, '$1: "$2"', $sMerge); // 什么作用 } else if ($sPoolClient == "singbox") { $sFile = $sDirBase."public/freenode/template/singbox.txt"; if (file_exists($sFile) && is_readable($sFile)) { $sSingboxTemplate = file_get_contents($sFile); // data } else { $sMsg = "singbox的template不存在,这不应该 \n"; TeleSlave::warn()->send($sMsg); echo $sMsg; continue; } $aSingboxConfig = json_decode($sSingboxTemplate, true); // tt($aNodeMerge); foreach ($aSingboxConfig["outbounds"] as &$aOutbounds) { if ($aOutbounds["type"] == "selector") { $aOutbounds["outbounds"] = $aNodeCountryList; continue; } } // $aSingboxConfig["outbounds"] = $aSingboxConfig["outbounds"] + $aNodeMerge; $aSingboxConfig["outbounds"] = array_merge($aSingboxConfig["outbounds"], $aNodeMerge); // tt($aSingboxConfig["outbounds"]); $sMerge = json_encode($aSingboxConfig); // $s = json_encode($aNodeMerge); // $s = json_decode($sMerge, true); // tt($s); } else { $sMerge = "?"; } $sFileDir = $sDirBase."public/freenode/merge/base/".$sPoolClient; if (!is_dir($sFileDir)) { mkdir($sFileDir, 0777, true); } $sFilePath = $sFileDir."/".$sDate.".txt"; // 都是txt,解析的时候另处理 file_put_contents($sFilePath, $sMerge); @chmod($sFilePath, 0777); echo " - base::".$sFilePath." 已保存 \n"; } } public static function baseToSite($sSiteGroupCodeTom) { echo "\nFreenodeMerge::baseToSite - 开始 \n"; $sDate = date("Y-m-d"); // $sDateCode = date("Ymd"); // $sDate = "2025-12-12"; // *test $sDirBase = $_ENV["dir_base"]; $sFnClientList = ModelOption::_hit("freenode_client-".$sSiteGroupCodeTom); if (!$sFnClientList) { throw new \Exception("未设置option的freenode_client?"); } $aFnClientList = explode(",", $sFnClientList); $aMerge = []; foreach ($aFnClientList as $sFnClient) { $sMergeFilePath = $sDirBase."public/freenode/merge/base/".$sFnClient."/".$sDate.".txt"; if (file_exists($sMergeFilePath)) { $aMerge[$sFnClient] = file_get_contents($sMergeFilePath); } else { throw new \Exception("baseToSite里没找到merge文件? - $sMergeFilePath"); } } $oSiteMap = ModelSiteMap::whereIn("group_code", [$sSiteGroupCodeTom])->get(); if ($oSiteMap->isEmpty()) { throw new \Exception("没找到siteMap的fn_a组?"); } $aSiteMap = $oSiteMap->toArray(); $aSiteMap[] = [ "code" => "_admin", "url" => "_admin.loc", "name" => "_admin", ]; $iH4Rand = rand(1, 21600); // 6小时 $iH4Time = time() - $iH4Rand; $sSloganDate = date("Y-m-d H:i:s", $iH4Time); foreach ($aSiteMap as $aSiteMapRow) { $aSiteConfig = json_decode($aSiteMapRow["config"] ?? "", true); $sSiteConfigTelegram = $aSiteConfig["telegram"] ?? ""; $sSiteConfigSloganUrl = $aSiteConfig["freenode_slogan"]["siteUrl"] ?? ""; $sSiteConfigSloganTelegram = $aSiteConfig["freenode_slogan"]["telegram"] ?? ""; if ($sSiteConfigSloganUrl) { $sSlogan_siteUrl = str_replace('{{siteUrl}}', $aSiteMapRow["url"], $sSiteConfigSloganUrl); } else { $sSlogan_siteUrl = "美国".uniqid(); } if ($sSiteConfigSloganTelegram) { $sSlogan_telegram = str_replace('{{telegram}}', '@'.$sSiteConfigTelegram, $sSiteConfigSloganTelegram); } else { $sSlogan_telegram = "美国".uniqid(); } foreach ($aMerge as $sClient => $sFeedContent) { $sFileSaveDir = $sDirBase."public/freenode/merge/".$aSiteMapRow["code"]."/".$sClient; if (!is_dir($sFileSaveDir)) { mkdir($sFileSaveDir, 0777, true); } $sFileSavePath = $sFileSaveDir."/".$sDate.".txt"; if ($sClient == "v2ray") { $sFeedContent = self::v2rayFeedToStr($sFeedContent); } $sFeedContent = str_replace('{{slogan_siteUrl}}', $sSlogan_siteUrl, $sFeedContent); $sFeedContent = str_replace('{{slogan_telegram}}', $sSlogan_telegram, $sFeedContent); $sFeedContent = str_replace('{{slogan_date}}', "更新于:".$sSloganDate, $sFeedContent); // if ($aSiteMapRow["code"] == "vfnfull" && $sClient == "singbox") { // echo $sFeedContent;exit; // echo "
";
//                    $sFeedContent = json_decode($sFeedContent, true);
//                    var_dump($sFeedContent);
//                }
                
                if ($aSiteMapRow["code"] !== "_admin") {
                    $sFeedContent = preg_replace('/ :\[.*?\]:/su', '', $sFeedContent);
                }
                
                if ($sClient == "v2ray") {
                    $sFeedContent = self::v2rayFeedByStr($sFeedContent);
                }
                
                file_put_contents($sFileSavePath, $sFeedContent);
                
                @chmod($sFileSavePath, 0777);
                
                echo " - fn的".$aSiteMapRow["code"]."的{$sClient}的{$sDate} 保存成功 \n";
            }
        }
        
        return true;
    }
    
    public static function v2rayFeedByStr($s)
    {
        $a = explode("\n", $s);
        
        $aFeed = [];
        foreach ($a as $sConfig) {
            if (!$sConfig) {continue;}
            $aTmp = CronFreenodePool::v2ray_chai($sConfig);
            $sConfig = $aTmp[0];
            $sName = $aTmp[1];
            $sName = rawurlencode($sName);
            $aFeed[] = $sConfig."#".$sName;
        }
        
        $sFeed = implode("\n", $aFeed);
        $sFeed = base64_encode($sFeed);
        
        return $sFeed;
    }
    
    public static function v2rayFeedToStr($sV2rayFeed)
    {
        $sV2rayFeed = base64_decode($sV2rayFeed);
        $aV2rayFeed = explode("\n", $sV2rayFeed);

        $aFeed = [];
        foreach ($aV2rayFeed as $sConfig) {
            if (!$sConfig) {continue;}
            $aTmp = CronFreenodePool::v2ray_chai($sConfig);
            $sConfig = $aTmp[0];
            $sName = $aTmp[1] ?? "美国"; // 没得到名字默认美国
            $sName = urldecode($sName);
            
            $aFeed[] = $sConfig."#".$sName;
        }

        $sFeed = implode("\n", $aFeed);

        return $sFeed;
    }
    
    private static function arrMerge($aBase, $aNew)
    {
        $aMerge = array_merge($aBase, $aNew);
        $aMerge = array_unique($aMerge);
        $aMerge = array_values($aMerge);
        return $aMerge;
    }// 这是做了什么
    
    public static function strReplace($sStr, $sFromName)
    {
        if (preg_match('/机场/u', $sStr)) {
            tomd($sStr);
            $sStr = "美国"; // 原本的slogan直接视为美国
        }
        
        if (preg_match('/频道/u', $sStr)) {
            $sStr = "美国";
        }

        if ($sFromName == "ripaojiedian") {
            $sStr = preg_replace('/\|\@ripaojiedian/', '', $sStr);
        } else if ($sFromName == "stairnode") {
            $sStr = preg_replace('/\|\@stairnode/', '', $sStr);
        } else {
            // 其他
        }
        
//        $sStr = preg_replace('/\d+/', '', $sStr); // 去数字
//        $sStr = preg_replace('/[\x{1F1E6}-\x{1F1FF}]{2}\s*/u', '', $sStr); // 去国旗
//        $sStr = preg_replace('/[a-zA-Z_]+/', '', $sStr); // 去下划线和字母

        if (preg_match('/\p{Han}/u', $sStr)) {
            $sStr = preg_replace('/[^\p{Han}]/u', '', $sStr);// 只留中文
        } else { // 没有中文,再处理一下
            $sStr = preg_replace('/^.*HK.*$/i', '香港', $sStr);
        }
        
        return $sStr;
    }
    
    private static function countryJoinFlag($str)
    {
        $aCountryFlagList = self::$aCountryFlag;
        
        $sFlag = "";
        foreach ($aCountryFlagList as $sCountryName => $sCountryFlag) {
            if (str_contains($str, $sCountryName)) {
                $sFlag = $sCountryFlag;
            }
        }
        
        if ($sFlag) {
            $str = $sFlag." ".$str;
        }
        
        return $str;
    }
    
}