docs(seo): record recovery findings and add seo copy tools
This commit is contained in:
2
code/.gitignore
vendored
2
code/.gitignore
vendored
@@ -17,4 +17,6 @@ Thumbs.db
|
||||
public/static/css/compiled/*
|
||||
public/static/js/compiled/*
|
||||
public/static/favicon/generated/*
|
||||
/public/_seo_copy_release/*
|
||||
/data/seo_copy_published/*
|
||||
/storage/*
|
||||
|
||||
293
code/scripts/seo_copy_published_audit.php
Normal file
293
code/scripts/seo_copy_published_audit.php
Normal file
@@ -0,0 +1,293 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
require dirname(__DIR__) . '/vendor/autoload.php';
|
||||
require dirname(__DIR__) . '/app/common/helper/SeoCopyStore.php';
|
||||
require dirname(__DIR__) . '/app/common/helper/SeoCopySchema.php';
|
||||
|
||||
use app\common\helper\SeoCopySchema;
|
||||
|
||||
function printUsage(): void
|
||||
{
|
||||
echo "Usage:\n";
|
||||
echo " php scripts/seo_copy_published_audit.php [--root=/abs/path] [--host=host-dir] [--format=json|text] [--sample-detail=<videoId>] [--sample-play=<videoId>:<playType>:<episode>]\n\n";
|
||||
echo "Examples:\n";
|
||||
echo " php scripts/seo_copy_published_audit.php\n";
|
||||
echo " php scripts/seo_copy_published_audit.php --host=lmjcg-com --format=text\n";
|
||||
echo " php scripts/seo_copy_published_audit.php --host=lmjcg-com --sample-detail=76310 --sample-play=76310:default:1 --format=text\n";
|
||||
}
|
||||
|
||||
function parseArgs(array $argv): array
|
||||
{
|
||||
$arrOptions = [
|
||||
'root' => dirname(__DIR__) . '/data/seo_copy_published',
|
||||
'host' => '',
|
||||
'format' => 'json',
|
||||
'sample_detail' => '',
|
||||
'sample_play' => '',
|
||||
];
|
||||
|
||||
array_shift($argv);
|
||||
|
||||
foreach ($argv as $strArg) {
|
||||
if (str_starts_with($strArg, '--root=')) {
|
||||
$arrOptions['root'] = trim(substr($strArg, strlen('--root=')));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (str_starts_with($strArg, '--host=')) {
|
||||
$arrOptions['host'] = trim(substr($strArg, strlen('--host=')));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (str_starts_with($strArg, '--format=')) {
|
||||
$arrOptions['format'] = strtolower(trim(substr($strArg, strlen('--format='))));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (str_starts_with($strArg, '--sample-detail=')) {
|
||||
$arrOptions['sample_detail'] = trim(substr($strArg, strlen('--sample-detail=')));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (str_starts_with($strArg, '--sample-play=')) {
|
||||
$arrOptions['sample_play'] = trim(substr($strArg, strlen('--sample-play=')));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (in_array($strArg, ['-h', '--help'], true)) {
|
||||
printUsage();
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
return $arrOptions;
|
||||
}
|
||||
|
||||
function listHostDirs(string $strRoot, string $strHostFilter): array
|
||||
{
|
||||
if (!is_dir($strRoot)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$arrHosts = [];
|
||||
$arrEntries = scandir($strRoot);
|
||||
if (!is_array($arrEntries)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
foreach ($arrEntries as $strEntry) {
|
||||
if ($strEntry === '.' || $strEntry === '..') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$strPath = $strRoot . '/' . $strEntry;
|
||||
if (!is_dir($strPath)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($strHostFilter !== '' && $strHostFilter !== $strEntry) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$arrHosts[] = $strEntry;
|
||||
}
|
||||
|
||||
sort($arrHosts);
|
||||
return $arrHosts;
|
||||
}
|
||||
|
||||
function collectSceneSummary(string $strRoot, string $strHost, string $strScene): array
|
||||
{
|
||||
$strSceneDir = $strRoot . '/' . $strHost . '/' . $strScene;
|
||||
$arrSummary = [
|
||||
'exists' => is_dir($strSceneDir),
|
||||
'total_files' => 0,
|
||||
'default_exists' => false,
|
||||
'non_default_count' => 0,
|
||||
'sample_non_default_keys' => [],
|
||||
];
|
||||
|
||||
if (!is_dir($strSceneDir)) {
|
||||
return $arrSummary;
|
||||
}
|
||||
|
||||
$arrFiles = glob($strSceneDir . '/*.json') ?: [];
|
||||
sort($arrFiles);
|
||||
|
||||
foreach ($arrFiles as $strFile) {
|
||||
if (!is_file($strFile)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$arrSummary['total_files']++;
|
||||
$strPageKey = preg_replace('/\.json$/i', '', basename($strFile));
|
||||
if ($strPageKey === 'default') {
|
||||
$arrSummary['default_exists'] = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
$arrSummary['non_default_count']++;
|
||||
if (count($arrSummary['sample_non_default_keys']) < 10) {
|
||||
$arrSummary['sample_non_default_keys'][] = $strPageKey;
|
||||
}
|
||||
}
|
||||
|
||||
return $arrSummary;
|
||||
}
|
||||
|
||||
function buildExpectedChecks(string $strRoot, string $strHost, string $strSampleDetail, string $strSamplePlay): array
|
||||
{
|
||||
$arrChecks = [];
|
||||
|
||||
if ($strSampleDetail !== '') {
|
||||
$strPageKey = SeoCopySchema::buildScenePageKey('detail', [$strSampleDetail]);
|
||||
$strPath = $strRoot . '/' . $strHost . '/detail/' . $strPageKey . '.json';
|
||||
$arrChecks[] = [
|
||||
'scene' => 'detail',
|
||||
'input' => $strSampleDetail,
|
||||
'expected_page_key' => $strPageKey,
|
||||
'exists' => is_file($strPath),
|
||||
'path' => $strPath,
|
||||
];
|
||||
}
|
||||
|
||||
if ($strSamplePlay !== '') {
|
||||
$arrParts = explode(':', $strSamplePlay);
|
||||
$strVideoId = trim((string)($arrParts[0] ?? ''));
|
||||
$strPlayType = trim((string)($arrParts[1] ?? 'default'));
|
||||
$strEpisode = trim((string)($arrParts[2] ?? '1'));
|
||||
$strPageKey = SeoCopySchema::buildScenePageKey('play', [$strVideoId, $strPlayType, $strEpisode]);
|
||||
$strPath = $strRoot . '/' . $strHost . '/play/' . $strPageKey . '.json';
|
||||
$arrChecks[] = [
|
||||
'scene' => 'play',
|
||||
'input' => $strSamplePlay,
|
||||
'expected_page_key' => $strPageKey,
|
||||
'exists' => is_file($strPath),
|
||||
'path' => $strPath,
|
||||
];
|
||||
}
|
||||
|
||||
return $arrChecks;
|
||||
}
|
||||
|
||||
function summarizeHost(string $strRoot, string $strHost, string $strSampleDetail, string $strSamplePlay): array
|
||||
{
|
||||
$arrScenes = [];
|
||||
foreach (SeoCopySchema::getSupportedScenes() as $strScene) {
|
||||
$arrScenes[$strScene] = collectSceneSummary($strRoot, $strHost, $strScene);
|
||||
}
|
||||
|
||||
$arrDetail = $arrScenes['detail'] ?? [];
|
||||
$arrPlay = $arrScenes['play'] ?? [];
|
||||
|
||||
return [
|
||||
'host' => $strHost,
|
||||
'detail_default_only' => !empty($arrDetail['default_exists']) && (int)($arrDetail['non_default_count'] ?? 0) === 0,
|
||||
'play_default_only' => !empty($arrPlay['default_exists']) && (int)($arrPlay['non_default_count'] ?? 0) === 0,
|
||||
'detail_has_non_default' => (int)($arrDetail['non_default_count'] ?? 0) > 0,
|
||||
'play_has_non_default' => (int)($arrPlay['non_default_count'] ?? 0) > 0,
|
||||
'scenes' => $arrScenes,
|
||||
'expected_checks' => buildExpectedChecks($strRoot, $strHost, $strSampleDetail, $strSamplePlay),
|
||||
];
|
||||
}
|
||||
|
||||
function renderText(array $arrSummary): string
|
||||
{
|
||||
$arrLines = [
|
||||
'root: ' . $arrSummary['root'],
|
||||
'total_hosts: ' . $arrSummary['total_hosts'],
|
||||
'hosts_detail_default_only: ' . $arrSummary['hosts_detail_default_only'],
|
||||
'hosts_play_default_only: ' . $arrSummary['hosts_play_default_only'],
|
||||
'hosts_detail_has_non_default: ' . $arrSummary['hosts_detail_has_non_default'],
|
||||
'hosts_play_has_non_default: ' . $arrSummary['hosts_play_has_non_default'],
|
||||
'',
|
||||
];
|
||||
|
||||
foreach ($arrSummary['hosts'] as $arrHost) {
|
||||
$arrLines[] = '[host] ' . $arrHost['host'];
|
||||
$arrLines[] = ' detail_default_only: ' . ($arrHost['detail_default_only'] ? 'yes' : 'no');
|
||||
$arrLines[] = ' play_default_only: ' . ($arrHost['play_default_only'] ? 'yes' : 'no');
|
||||
|
||||
foreach (['detail', 'play', 'home', 'category_index', 'category_list', 'search', 'rank_index', 'rank_list', 'forge'] as $strScene) {
|
||||
$arrScene = $arrHost['scenes'][$strScene] ?? [];
|
||||
if (empty($arrScene)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$arrLines[] = sprintf(
|
||||
' %s: total=%d, default=%s, non_default=%d',
|
||||
$strScene,
|
||||
(int)($arrScene['total_files'] ?? 0),
|
||||
!empty($arrScene['default_exists']) ? 'yes' : 'no',
|
||||
(int)($arrScene['non_default_count'] ?? 0)
|
||||
);
|
||||
|
||||
if (!empty($arrScene['sample_non_default_keys'])) {
|
||||
$arrLines[] = ' sample_non_default: ' . implode(', ', $arrScene['sample_non_default_keys']);
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($arrHost['expected_checks'])) {
|
||||
$arrLines[] = ' expected_checks:';
|
||||
foreach ($arrHost['expected_checks'] as $arrCheck) {
|
||||
$arrLines[] = sprintf(
|
||||
' %s | key=%s | exists=%s',
|
||||
$arrCheck['scene'],
|
||||
$arrCheck['expected_page_key'],
|
||||
$arrCheck['exists'] ? 'yes' : 'no'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$arrLines[] = '';
|
||||
}
|
||||
|
||||
return implode(PHP_EOL, $arrLines) . PHP_EOL;
|
||||
}
|
||||
|
||||
$arrOptions = parseArgs($argv);
|
||||
$strRoot = rtrim($arrOptions['root'], '/');
|
||||
|
||||
if (!is_dir($strRoot)) {
|
||||
fwrite(STDERR, "Root not found: {$strRoot}\n");
|
||||
printUsage();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$arrHosts = listHostDirs($strRoot, $arrOptions['host']);
|
||||
$arrSummary = [
|
||||
'root' => realpath($strRoot) ?: $strRoot,
|
||||
'total_hosts' => count($arrHosts),
|
||||
'hosts_detail_default_only' => 0,
|
||||
'hosts_play_default_only' => 0,
|
||||
'hosts_detail_has_non_default' => 0,
|
||||
'hosts_play_has_non_default' => 0,
|
||||
'hosts' => [],
|
||||
];
|
||||
|
||||
foreach ($arrHosts as $strHost) {
|
||||
$arrHostSummary = summarizeHost($strRoot, $strHost, $arrOptions['sample_detail'], $arrOptions['sample_play']);
|
||||
if ($arrHostSummary['detail_default_only']) {
|
||||
$arrSummary['hosts_detail_default_only']++;
|
||||
}
|
||||
if ($arrHostSummary['play_default_only']) {
|
||||
$arrSummary['hosts_play_default_only']++;
|
||||
}
|
||||
if ($arrHostSummary['detail_has_non_default']) {
|
||||
$arrSummary['hosts_detail_has_non_default']++;
|
||||
}
|
||||
if ($arrHostSummary['play_has_non_default']) {
|
||||
$arrSummary['hosts_play_has_non_default']++;
|
||||
}
|
||||
|
||||
$arrSummary['hosts'][] = $arrHostSummary;
|
||||
}
|
||||
|
||||
if ($arrOptions['format'] === 'text') {
|
||||
echo renderText($arrSummary);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
echo json_encode($arrSummary, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . PHP_EOL;
|
||||
@@ -162,6 +162,7 @@ function startTempServer(string $strCodeRoot, string $strSourceRoot, int $intPor
|
||||
|
||||
$Process = proc_open($strCommand, $arrDescriptors, $arrPipes, $strCodeRoot, array_merge($_ENV, [
|
||||
'SEO_COPY_ROOT_OVERRIDE' => $strSourceRoot,
|
||||
'SEO_COPY_PUBLISHED_ROOT' => $strSourceRoot,
|
||||
]));
|
||||
|
||||
if (!is_resource($Process)) {
|
||||
|
||||
184
code/scripts/seo_copy_restore_from_publish_logs.php
Normal file
184
code/scripts/seo_copy_restore_from_publish_logs.php
Normal file
@@ -0,0 +1,184 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use app\common\helper\SeoCopyStore;
|
||||
|
||||
require dirname(__DIR__) . '/vendor/autoload.php';
|
||||
|
||||
if (!function_exists('base_path')) {
|
||||
function base_path(string $path = ''): string
|
||||
{
|
||||
$base = dirname(__DIR__);
|
||||
return $path !== '' ? $base . '/' . ltrim($path, '/') : $base;
|
||||
}
|
||||
}
|
||||
|
||||
function usage(): void
|
||||
{
|
||||
$script = basename(__FILE__);
|
||||
echo <<<TXT
|
||||
Usage:
|
||||
php code/scripts/{$script} --host=chuanjiafeng-net [--source=/abs/log/root] [--target=/abs/target/root] [--dry-run]
|
||||
|
||||
Options:
|
||||
--host Host directory name under seo_copy, e.g. chuanjiafeng-net
|
||||
--source Publish log root. Defaults to code/storage/seo_copy_publish_logs
|
||||
--target Target root. Defaults to code/data/seo_copy_published
|
||||
--dry-run Preview only, do not write files
|
||||
|
||||
Examples:
|
||||
php code/scripts/{$script} --host=chuanjiafeng-net --dry-run
|
||||
php code/scripts/{$script} --host=liangzuan-net
|
||||
|
||||
TXT;
|
||||
}
|
||||
|
||||
function resolve_path(string $path): string
|
||||
{
|
||||
$path = trim($path);
|
||||
if ($path === '') {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (str_starts_with($path, '/')) {
|
||||
return rtrim($path, '/');
|
||||
}
|
||||
|
||||
$arrCandidates = [
|
||||
getcwd() . '/' . ltrim($path, '/'),
|
||||
base_path($path),
|
||||
];
|
||||
|
||||
foreach ($arrCandidates as $strCandidate) {
|
||||
if (file_exists($strCandidate) || is_dir($strCandidate)) {
|
||||
return rtrim($strCandidate, '/');
|
||||
}
|
||||
}
|
||||
|
||||
return rtrim($arrCandidates[0], '/');
|
||||
}
|
||||
|
||||
$arrArgs = [];
|
||||
foreach (array_slice($argv, 1) as $strArg) {
|
||||
if (strncmp($strArg, '--', 2) !== 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$strArg = substr($strArg, 2);
|
||||
if ($strArg === 'dry-run') {
|
||||
$arrArgs['dry-run'] = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
$arrParts = explode('=', $strArg, 2);
|
||||
$arrArgs[$arrParts[0]] = $arrParts[1] ?? '';
|
||||
}
|
||||
|
||||
$strHost = trim((string)($arrArgs['host'] ?? ''));
|
||||
$strSource = trim((string)($arrArgs['source'] ?? base_path('storage/seo_copy_publish_logs')));
|
||||
$strTarget = trim((string)($arrArgs['target'] ?? base_path('data/seo_copy_published')));
|
||||
$boolDryRun = !empty($arrArgs['dry-run']);
|
||||
|
||||
if ($strHost === '') {
|
||||
usage();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$strSource = resolve_path($strSource);
|
||||
$strTarget = resolve_path($strTarget);
|
||||
|
||||
if (!is_dir($strSource)) {
|
||||
fwrite(STDERR, "publish log root not found: {$strSource}\n");
|
||||
exit(2);
|
||||
}
|
||||
|
||||
$arrScenes = ['home', 'category_index', 'category_list', 'search', 'rank_index', 'rank_list', 'detail', 'forge', 'play'];
|
||||
$arrFilesByScene = [];
|
||||
$arrMatchedPaths = [];
|
||||
|
||||
$it = new RecursiveIteratorIterator(
|
||||
new RecursiveDirectoryIterator($strSource, FilesystemIterator::SKIP_DOTS)
|
||||
);
|
||||
|
||||
foreach ($it as $file) {
|
||||
if (!$file->isFile()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$strPath = $file->getPathname();
|
||||
if (!str_ends_with($strPath, '.json')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!preg_match(
|
||||
'#/backups/[^/]+/' . preg_quote($strHost, '#') . '/([^/]+)/([^/]+)\.json$#',
|
||||
$strPath,
|
||||
$arrMatch
|
||||
)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$strScene = $arrMatch[1];
|
||||
$strPageKey = $arrMatch[2];
|
||||
if (!in_array($strScene, $arrScenes, true)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$arrFilesByScene[$strScene][$strPageKey] = $strPath;
|
||||
$arrMatchedPaths[] = $strPath;
|
||||
}
|
||||
|
||||
if (empty($arrFilesByScene)) {
|
||||
fwrite(STDERR, "no backup files found for host: {$strHost}\n");
|
||||
exit(3);
|
||||
}
|
||||
|
||||
ksort($arrFilesByScene);
|
||||
|
||||
$arrSummary = [];
|
||||
foreach ($arrScenes as $strScene) {
|
||||
$arrPageMap = $arrFilesByScene[$strScene] ?? [];
|
||||
ksort($arrPageMap);
|
||||
|
||||
$arrSummary[$strScene] = [
|
||||
'count' => count($arrPageMap),
|
||||
'files' => array_keys($arrPageMap),
|
||||
];
|
||||
|
||||
if ($boolDryRun) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($arrPageMap as $strPageKey => $strFile) {
|
||||
$strPageKey = (string)$strPageKey;
|
||||
$strJson = @file_get_contents($strFile);
|
||||
if ($strJson === false || trim($strJson) === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$arrData = json_decode($strJson, true);
|
||||
if (!is_array($arrData)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
SeoCopyStore::writePageDataToRoot($strTarget, $strHost, $strScene, $strPageKey, $arrData);
|
||||
}
|
||||
}
|
||||
|
||||
echo "host: {$strHost}\n";
|
||||
echo "source: {$strSource}\n";
|
||||
echo "target: {$strTarget}\n";
|
||||
echo "mode: " . ($boolDryRun ? 'dry-run' : 'write') . "\n";
|
||||
echo "matched_paths: " . count($arrMatchedPaths) . "\n\n";
|
||||
|
||||
foreach ($arrSummary as $strScene => $arrInfo) {
|
||||
if ($arrInfo['count'] === 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
echo "[{$strScene}] count=" . $arrInfo['count'] . "\n";
|
||||
foreach ($arrInfo['files'] as $strName) {
|
||||
echo " - {$strName}.json\n";
|
||||
}
|
||||
}
|
||||
152
code/scripts/seo_copy_restore_from_source.php
Normal file
152
code/scripts/seo_copy_restore_from_source.php
Normal file
@@ -0,0 +1,152 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use app\common\helper\SeoCopyStore;
|
||||
|
||||
require dirname(__DIR__) . '/vendor/autoload.php';
|
||||
|
||||
if (!function_exists('base_path')) {
|
||||
function base_path(string $path = ''): string
|
||||
{
|
||||
$base = dirname(__DIR__);
|
||||
return $path !== '' ? $base . '/' . ltrim($path, '/') : $base;
|
||||
}
|
||||
}
|
||||
|
||||
function usage(): void
|
||||
{
|
||||
$script = basename(__FILE__);
|
||||
echo <<<TXT
|
||||
Usage:
|
||||
php code/scripts/{$script} --host=chuanjiafeng-net --source=/abs/source/path [--target=/abs/target/path] [--dry-run]
|
||||
|
||||
Options:
|
||||
--host Host directory name under seo_copy, e.g. chuanjiafeng-net
|
||||
--source Source root that contains <host>/detail/*.json and <host>/play/*.json
|
||||
--target Target root. Defaults to code/data/seo_copy_published
|
||||
--dry-run Preview only, do not write files
|
||||
|
||||
Examples:
|
||||
php code/scripts/{$script} \\
|
||||
--host=chuanjiafeng-net \\
|
||||
--source=code/storage/domain_bootstrap_bundles/chuanjiafeng-compact/data/seo_copy \\
|
||||
--dry-run
|
||||
|
||||
TXT;
|
||||
}
|
||||
|
||||
function resolve_path(string $path): string
|
||||
{
|
||||
$path = trim($path);
|
||||
if ($path === '') {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (str_starts_with($path, '/')) {
|
||||
return rtrim($path, '/');
|
||||
}
|
||||
|
||||
$arrCandidates = [
|
||||
getcwd() . '/' . ltrim($path, '/'),
|
||||
base_path($path),
|
||||
];
|
||||
|
||||
foreach ($arrCandidates as $strCandidate) {
|
||||
if (file_exists($strCandidate) || is_dir($strCandidate)) {
|
||||
return rtrim($strCandidate, '/');
|
||||
}
|
||||
}
|
||||
|
||||
return rtrim($arrCandidates[0], '/');
|
||||
}
|
||||
|
||||
$arrArgs = [];
|
||||
foreach (array_slice($argv, 1) as $strArg) {
|
||||
if (strncmp($strArg, '--', 2) !== 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$strArg = substr($strArg, 2);
|
||||
if ($strArg === 'dry-run') {
|
||||
$arrArgs['dry-run'] = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
$arrParts = explode('=', $strArg, 2);
|
||||
$arrArgs[$arrParts[0]] = $arrParts[1] ?? '';
|
||||
}
|
||||
|
||||
$strHost = trim((string)($arrArgs['host'] ?? ''));
|
||||
$strSource = trim((string)($arrArgs['source'] ?? ''));
|
||||
$strTarget = trim((string)($arrArgs['target'] ?? base_path('data/seo_copy_published')));
|
||||
$boolDryRun = !empty($arrArgs['dry-run']);
|
||||
|
||||
if ($strHost === '' || $strSource === '') {
|
||||
usage();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$strSource = resolve_path($strSource);
|
||||
$strTarget = resolve_path($strTarget);
|
||||
|
||||
$strHostSource = $strSource . '/' . $strHost;
|
||||
if (!is_dir($strHostSource)) {
|
||||
fwrite(STDERR, "source host dir not found: {$strHostSource}\n");
|
||||
exit(2);
|
||||
}
|
||||
|
||||
$arrScenes = ['detail', 'play'];
|
||||
$arrSummary = [];
|
||||
|
||||
foreach ($arrScenes as $strScene) {
|
||||
$strSceneDir = $strHostSource . '/' . $strScene;
|
||||
$arrFiles = [];
|
||||
|
||||
if (is_dir($strSceneDir)) {
|
||||
foreach (glob($strSceneDir . '/*.json') ?: [] as $strFile) {
|
||||
if (!is_file($strFile)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$arrFiles[] = $strFile;
|
||||
}
|
||||
}
|
||||
|
||||
sort($arrFiles);
|
||||
$arrSummary[$strScene] = [
|
||||
'count' => count($arrFiles),
|
||||
'files' => array_map('basename', $arrFiles),
|
||||
];
|
||||
|
||||
if ($boolDryRun) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($arrFiles as $strFile) {
|
||||
$strPageKey = basename($strFile, '.json');
|
||||
$strJson = file_get_contents($strFile);
|
||||
if ($strJson === false || trim($strJson) === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$arrData = json_decode($strJson, true);
|
||||
if (!is_array($arrData)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
SeoCopyStore::writePageDataToRoot($strTarget, $strHost, $strScene, $strPageKey, $arrData);
|
||||
}
|
||||
}
|
||||
|
||||
echo "host: {$strHost}\n";
|
||||
echo "source: {$strSource}\n";
|
||||
echo "target: {$strTarget}\n";
|
||||
echo "mode: " . ($boolDryRun ? 'dry-run' : 'write') . "\n\n";
|
||||
|
||||
foreach ($arrSummary as $strScene => $arrInfo) {
|
||||
echo "[{$strScene}] count=" . $arrInfo['count'] . "\n";
|
||||
foreach ($arrInfo['files'] as $strName) {
|
||||
echo " - {$strName}\n";
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user