init: Upload Code From Github

要提交的变更:
	修改:     README.md
	新文件:   README_zh-CN.md
	新文件:   assets/CHANGELOG.md
	新文件:   assets/Parsedown.php
	新文件:   assets/css/login.css
	新文件:   assets/css/manage.css
	新文件:   assets/defaultConfig.json
	新文件:   assets/defaultIconList.json
	新文件:   assets/html/favicon.ico
	新文件:   assets/html/login.html
	新文件:   assets/html/manage.html
	新文件:   assets/js/console.js
	新文件:   assets/js/manage.js
	新文件:   assets/opencc/composer.json
	新文件:   assets/opencc/composer.lock
	新文件:   assets/opencc/vendor/autoload.php
	新文件:   assets/opencc/vendor/bin/opencc
	新文件:   assets/opencc/vendor/composer/ClassLoader.php
	新文件:   assets/opencc/vendor/composer/InstalledVersions.php
	新文件:   assets/opencc/vendor/composer/LICENSE
	新文件:   assets/opencc/vendor/composer/autoload_classmap.php
	新文件:   assets/opencc/vendor/composer/autoload_files.php
	新文件:   assets/opencc/vendor/composer/autoload_namespaces.php
	新文件:   assets/opencc/vendor/composer/autoload_psr4.php
	新文件:   assets/opencc/vendor/composer/autoload_real.php
	新文件:   assets/opencc/vendor/composer/autoload_static.php
	新文件:   assets/opencc/vendor/composer/installed.json
	新文件:   assets/opencc/vendor/composer/installed.php
	新文件:   assets/opencc/vendor/composer/platform_check.php
	新文件:   assets/opencc/vendor/overtrue/php-opencc/.editorconfig
	新文件:   assets/opencc/vendor/overtrue/php-opencc/.github/FUNDING.yml
	新文件:   assets/opencc/vendor/overtrue/php-opencc/.github/workflows/test.yml
	新文件:   assets/opencc/vendor/overtrue/php-opencc/LICENSE
	新文件:   assets/opencc/vendor/overtrue/php-opencc/README.md
	新文件:   assets/opencc/vendor/overtrue/php-opencc/bin/build
	新文件:   assets/opencc/vendor/overtrue/php-opencc/bin/opencc
	新文件:   assets/opencc/vendor/overtrue/php-opencc/composer.json
	新文件:   assets/opencc/vendor/overtrue/php-opencc/data/dictionary/HKVariants.txt
	新文件:   assets/opencc/vendor/overtrue/php-opencc/data/dictionary/HKVariantsRevPhrases.txt
	新文件:   assets/opencc/vendor/overtrue/php-opencc/data/dictionary/JPShinjitaiCharacters.txt
	新文件:   assets/opencc/vendor/overtrue/php-opencc/data/dictionary/JPShinjitaiPhrases.txt
	新文件:   assets/opencc/vendor/overtrue/php-opencc/data/dictionary/JPVariants.txt
	新文件:   assets/opencc/vendor/overtrue/php-opencc/data/dictionary/README.md
	新文件:   assets/opencc/vendor/overtrue/php-opencc/data/dictionary/STCharacters.txt
	新文件:   assets/opencc/vendor/overtrue/php-opencc/data/dictionary/STPhrases.txt
	新文件:   assets/opencc/vendor/overtrue/php-opencc/data/dictionary/TSCharacters.txt
	新文件:   assets/opencc/vendor/overtrue/php-opencc/data/dictionary/TSPhrases.txt
	新文件:   assets/opencc/vendor/overtrue/php-opencc/data/dictionary/TWPhrasesIT.txt
	新文件:   assets/opencc/vendor/overtrue/php-opencc/data/dictionary/TWPhrasesName.txt
	新文件:   assets/opencc/vendor/overtrue/php-opencc/data/dictionary/TWPhrasesOther.txt
	新文件:   assets/opencc/vendor/overtrue/php-opencc/data/dictionary/TWVariants.txt
	新文件:   assets/opencc/vendor/overtrue/php-opencc/data/dictionary/TWVariantsRevPhrases.txt
	新文件:   assets/opencc/vendor/overtrue/php-opencc/data/parsed/HKVariants.php
	新文件:   assets/opencc/vendor/overtrue/php-opencc/data/parsed/HKVariantsRev.php
	新文件:   assets/opencc/vendor/overtrue/php-opencc/data/parsed/HKVariantsRevPhrases.php
	新文件:   assets/opencc/vendor/overtrue/php-opencc/data/parsed/JPShinjitaiCharacters.php
	新文件:   assets/opencc/vendor/overtrue/php-opencc/data/parsed/JPShinjitaiPhrases.php
	新文件:   assets/opencc/vendor/overtrue/php-opencc/data/parsed/JPVariants.php
	新文件:   assets/opencc/vendor/overtrue/php-opencc/data/parsed/JPVariantsRev.php
	新文件:   assets/opencc/vendor/overtrue/php-opencc/data/parsed/STCharacters.php
	新文件:   assets/opencc/vendor/overtrue/php-opencc/data/parsed/STPhrases.php
	新文件:   assets/opencc/vendor/overtrue/php-opencc/data/parsed/TSCharacters.php
	新文件:   assets/opencc/vendor/overtrue/php-opencc/data/parsed/TSPhrases.php
	新文件:   assets/opencc/vendor/overtrue/php-opencc/data/parsed/TWPhrases.php
	新文件:   assets/opencc/vendor/overtrue/php-opencc/data/parsed/TWPhrasesIT.php
	新文件:   assets/opencc/vendor/overtrue/php-opencc/data/parsed/TWPhrasesName.php
	新文件:   assets/opencc/vendor/overtrue/php-opencc/data/parsed/TWPhrasesOther.php
	新文件:   assets/opencc/vendor/overtrue/php-opencc/data/parsed/TWPhrasesRev.php
	新文件:   assets/opencc/vendor/overtrue/php-opencc/data/parsed/TWVariants.php
	新文件:   assets/opencc/vendor/overtrue/php-opencc/data/parsed/TWVariantsRev.php
	新文件:   assets/opencc/vendor/overtrue/php-opencc/data/parsed/TWVariantsRevPhrases.php
	新文件:   assets/opencc/vendor/overtrue/php-opencc/src/Console/BuildCommand.php
	新文件:   assets/opencc/vendor/overtrue/php-opencc/src/Console/ConvertCommand.php
	新文件:   assets/opencc/vendor/overtrue/php-opencc/src/Contracts/ConverterInterface.php
	新文件:   assets/opencc/vendor/overtrue/php-opencc/src/Converter.php
	新文件:   assets/opencc/vendor/overtrue/php-opencc/src/Dictionary.php
	新文件:   assets/opencc/vendor/overtrue/php-opencc/src/OpenCC.php
	新文件:   assets/opencc/vendor/overtrue/php-opencc/src/Strategy.php
	新文件:   assets/opencc/vendor/psr/container/.gitignore
	新文件:   assets/opencc/vendor/psr/container/LICENSE
	新文件:   assets/opencc/vendor/psr/container/README.md
	新文件:   assets/opencc/vendor/psr/container/composer.json
	新文件:   assets/opencc/vendor/psr/container/src/ContainerExceptionInterface.php
	新文件:   assets/opencc/vendor/psr/container/src/ContainerInterface.php
	新文件:   assets/opencc/vendor/psr/container/src/NotFoundExceptionInterface.php
	新文件:   assets/opencc/vendor/symfony/console/Application.php
	新文件:   assets/opencc/vendor/symfony/console/Attribute/AsCommand.php
	新文件:   assets/opencc/vendor/symfony/console/CHANGELOG.md
	新文件:   assets/opencc/vendor/symfony/console/CI/GithubActionReporter.php
	新文件:   assets/opencc/vendor/symfony/console/Color.php
	新文件:   assets/opencc/vendor/symfony/console/Command/Command.php
	新文件:   assets/opencc/vendor/symfony/console/Command/CompleteCommand.php
	新文件:   assets/opencc/vendor/symfony/console/Command/DumpCompletionCommand.php
	新文件:   assets/opencc/vendor/symfony/console/Command/HelpCommand.php
	新文件:   assets/opencc/vendor/symfony/console/Command/LazyCommand.php
	新文件:   assets/opencc/vendor/symfony/console/Command/ListCommand.php
	新文件:   assets/opencc/vendor/symfony/console/Command/LockableTrait.php
	新文件:   assets/opencc/vendor/symfony/console/Command/SignalableCommandInterface.php
	新文件:   assets/opencc/vendor/symfony/console/Command/TraceableCommand.php
	新文件:   assets/opencc/vendor/symfony/console/CommandLoader/CommandLoaderInterface.php
	新文件:   assets/opencc/vendor/symfony/console/CommandLoader/ContainerCommandLoader.php
	新文件:   assets/opencc/vendor/symfony/console/CommandLoader/FactoryCommandLoader.php
	新文件:   assets/opencc/vendor/symfony/console/Completion/CompletionInput.php
	新文件:   assets/opencc/vendor/symfony/console/Completion/CompletionSuggestions.php
	新文件:   assets/opencc/vendor/symfony/console/Completion/Output/BashCompletionOutput.php
	新文件:   assets/opencc/vendor/symfony/console/Completion/Output/CompletionOutputInterface.php
	新文件:   assets/opencc/vendor/symfony/console/Completion/Output/FishCompletionOutput.php
	新文件:   assets/opencc/vendor/symfony/console/Completion/Output/ZshCompletionOutput.php
	新文件:   assets/opencc/vendor/symfony/console/Completion/Suggestion.php
	新文件:   assets/opencc/vendor/symfony/console/ConsoleEvents.php
	新文件:   assets/opencc/vendor/symfony/console/Cursor.php
	新文件:   assets/opencc/vendor/symfony/console/DataCollector/CommandDataCollector.php
	新文件:   assets/opencc/vendor/symfony/console/Debug/CliRequest.php
	新文件:   assets/opencc/vendor/symfony/console/DependencyInjection/AddConsoleCommandPass.php
	新文件:   assets/opencc/vendor/symfony/console/Descriptor/ApplicationDescription.php
	新文件:   assets/opencc/vendor/symfony/console/Descriptor/Descriptor.php
	新文件:   assets/opencc/vendor/symfony/console/Descriptor/DescriptorInterface.php
	新文件:   assets/opencc/vendor/symfony/console/Descriptor/JsonDescriptor.php
	新文件:   assets/opencc/vendor/symfony/console/Descriptor/MarkdownDescriptor.php
	新文件:   assets/opencc/vendor/symfony/console/Descriptor/ReStructuredTextDescriptor.php
	新文件:   assets/opencc/vendor/symfony/console/Descriptor/TextDescriptor.php
	新文件:   assets/opencc/vendor/symfony/console/Descriptor/XmlDescriptor.php
	新文件:   assets/opencc/vendor/symfony/console/Event/ConsoleCommandEvent.php
	新文件:   assets/opencc/vendor/symfony/console/Event/ConsoleErrorEvent.php
	新文件:   assets/opencc/vendor/symfony/console/Event/ConsoleEvent.php
	新文件:   assets/opencc/vendor/symfony/console/Event/ConsoleSignalEvent.php
	新文件:   assets/opencc/vendor/symfony/console/Event/ConsoleTerminateEvent.php
	新文件:   assets/opencc/vendor/symfony/console/EventListener/ErrorListener.php
	新文件:   assets/opencc/vendor/symfony/console/Exception/CommandNotFoundException.php
	新文件:   assets/opencc/vendor/symfony/console/Exception/ExceptionInterface.php
	新文件:   assets/opencc/vendor/symfony/console/Exception/InvalidArgumentException.php
	新文件:   assets/opencc/vendor/symfony/console/Exception/InvalidOptionException.php
	新文件:   assets/opencc/vendor/symfony/console/Exception/LogicException.php
	新文件:   assets/opencc/vendor/symfony/console/Exception/MissingInputException.php
	新文件:   assets/opencc/vendor/symfony/console/Exception/NamespaceNotFoundException.php
	新文件:   assets/opencc/vendor/symfony/console/Exception/RunCommandFailedException.php
	新文件:   assets/opencc/vendor/symfony/console/Exception/RuntimeException.php
	新文件:   assets/opencc/vendor/symfony/console/Formatter/NullOutputFormatter.php
	新文件:   assets/opencc/vendor/symfony/console/Formatter/NullOutputFormatterStyle.php
	新文件:   assets/opencc/vendor/symfony/console/Formatter/OutputFormatter.php
	新文件:   assets/opencc/vendor/symfony/console/Formatter/OutputFormatterInterface.php
	新文件:   assets/opencc/vendor/symfony/console/Formatter/OutputFormatterStyle.php
	新文件:   assets/opencc/vendor/symfony/console/Formatter/OutputFormatterStyleInterface.php
	新文件:   assets/opencc/vendor/symfony/console/Formatter/OutputFormatterStyleStack.php
	新文件:   assets/opencc/vendor/symfony/console/Formatter/WrappableOutputFormatterInterface.php
	新文件:   assets/opencc/vendor/symfony/console/Helper/DebugFormatterHelper.php
	新文件:   assets/opencc/vendor/symfony/console/Helper/DescriptorHelper.php
	新文件:   assets/opencc/vendor/symfony/console/Helper/Dumper.php
	新文件:   assets/opencc/vendor/symfony/console/Helper/FormatterHelper.php
	新文件:   assets/opencc/vendor/symfony/console/Helper/Helper.php
	新文件:   assets/opencc/vendor/symfony/console/Helper/HelperInterface.php
	新文件:   assets/opencc/vendor/symfony/console/Helper/HelperSet.php
	新文件:   assets/opencc/vendor/symfony/console/Helper/InputAwareHelper.php
	新文件:   assets/opencc/vendor/symfony/console/Helper/OutputWrapper.php
	新文件:   assets/opencc/vendor/symfony/console/Helper/ProcessHelper.php
	新文件:   assets/opencc/vendor/symfony/console/Helper/ProgressBar.php
	新文件:   assets/opencc/vendor/symfony/console/Helper/ProgressIndicator.php
	新文件:   assets/opencc/vendor/symfony/console/Helper/QuestionHelper.php
	新文件:   assets/opencc/vendor/symfony/console/Helper/SymfonyQuestionHelper.php
	新文件:   assets/opencc/vendor/symfony/console/Helper/Table.php
	新文件:   assets/opencc/vendor/symfony/console/Helper/TableCell.php
	新文件:   assets/opencc/vendor/symfony/console/Helper/TableCellStyle.php
	新文件:   assets/opencc/vendor/symfony/console/Helper/TableRows.php
	新文件:   assets/opencc/vendor/symfony/console/Helper/TableSeparator.php
	新文件:   assets/opencc/vendor/symfony/console/Helper/TableStyle.php
	新文件:   assets/opencc/vendor/symfony/console/Input/ArgvInput.php
	新文件:   assets/opencc/vendor/symfony/console/Input/ArrayInput.php
	新文件:   assets/opencc/vendor/symfony/console/Input/Input.php
	新文件:   assets/opencc/vendor/symfony/console/Input/InputArgument.php
	新文件:   assets/opencc/vendor/symfony/console/Input/InputAwareInterface.php
	新文件:   assets/opencc/vendor/symfony/console/Input/InputDefinition.php
	新文件:   assets/opencc/vendor/symfony/console/Input/InputInterface.php
	新文件:   assets/opencc/vendor/symfony/console/Input/InputOption.php
	新文件:   assets/opencc/vendor/symfony/console/Input/StreamableInputInterface.php
	新文件:   assets/opencc/vendor/symfony/console/Input/StringInput.php
	新文件:   assets/opencc/vendor/symfony/console/LICENSE
	新文件:   assets/opencc/vendor/symfony/console/Logger/ConsoleLogger.php
	新文件:   assets/opencc/vendor/symfony/console/Messenger/RunCommandContext.php
	新文件:   assets/opencc/vendor/symfony/console/Messenger/RunCommandMessage.php
	新文件:   assets/opencc/vendor/symfony/console/Messenger/RunCommandMessageHandler.php
	新文件:   assets/opencc/vendor/symfony/console/Output/AnsiColorMode.php
	新文件:   assets/opencc/vendor/symfony/console/Output/BufferedOutput.php
	新文件:   assets/opencc/vendor/symfony/console/Output/ConsoleOutput.php
	新文件:   assets/opencc/vendor/symfony/console/Output/ConsoleOutputInterface.php
	新文件:   assets/opencc/vendor/symfony/console/Output/ConsoleSectionOutput.php
	新文件:   assets/opencc/vendor/symfony/console/Output/NullOutput.php
	新文件:   assets/opencc/vendor/symfony/console/Output/Output.php
	新文件:   assets/opencc/vendor/symfony/console/Output/OutputInterface.php
	新文件:   assets/opencc/vendor/symfony/console/Output/StreamOutput.php
	新文件:   assets/opencc/vendor/symfony/console/Output/TrimmedBufferOutput.php
	新文件:   assets/opencc/vendor/symfony/console/Question/ChoiceQuestion.php
	新文件:   assets/opencc/vendor/symfony/console/Question/ConfirmationQuestion.php
	新文件:   assets/opencc/vendor/symfony/console/Question/Question.php
	新文件:   assets/opencc/vendor/symfony/console/README.md
	新文件:   assets/opencc/vendor/symfony/console/Resources/bin/hiddeninput.exe
	新文件:   assets/opencc/vendor/symfony/console/Resources/completion.bash
	新文件:   assets/opencc/vendor/symfony/console/Resources/completion.fish
	新文件:   assets/opencc/vendor/symfony/console/Resources/completion.zsh
	新文件:   assets/opencc/vendor/symfony/console/SignalRegistry/SignalMap.php
	新文件:   assets/opencc/vendor/symfony/console/SignalRegistry/SignalRegistry.php
	新文件:   assets/opencc/vendor/symfony/console/SingleCommandApplication.php
	新文件:   assets/opencc/vendor/symfony/console/Style/OutputStyle.php
	新文件:   assets/opencc/vendor/symfony/console/Style/StyleInterface.php
	新文件:   assets/opencc/vendor/symfony/console/Style/SymfonyStyle.php
	新文件:   assets/opencc/vendor/symfony/console/Terminal.php
	新文件:   assets/opencc/vendor/symfony/console/Tester/ApplicationTester.php
	新文件:   assets/opencc/vendor/symfony/console/Tester/CommandCompletionTester.php
	新文件:   assets/opencc/vendor/symfony/console/Tester/CommandTester.php
	新文件:   assets/opencc/vendor/symfony/console/Tester/Constraint/CommandIsSuccessful.php
	新文件:   assets/opencc/vendor/symfony/console/Tester/TesterTrait.php
	新文件:   assets/opencc/vendor/symfony/console/composer.json
	新文件:   assets/opencc/vendor/symfony/deprecation-contracts/CHANGELOG.md
	新文件:   assets/opencc/vendor/symfony/deprecation-contracts/LICENSE
	新文件:   assets/opencc/vendor/symfony/deprecation-contracts/README.md
	新文件:   assets/opencc/vendor/symfony/deprecation-contracts/composer.json
	新文件:   assets/opencc/vendor/symfony/deprecation-contracts/function.php
	新文件:   assets/opencc/vendor/symfony/polyfill-ctype/Ctype.php
	新文件:   assets/opencc/vendor/symfony/polyfill-ctype/LICENSE
	新文件:   assets/opencc/vendor/symfony/polyfill-ctype/README.md
	新文件:   assets/opencc/vendor/symfony/polyfill-ctype/bootstrap.php
	新文件:   assets/opencc/vendor/symfony/polyfill-ctype/bootstrap80.php
	新文件:   assets/opencc/vendor/symfony/polyfill-ctype/composer.json
	新文件:   assets/opencc/vendor/symfony/polyfill-intl-grapheme/Grapheme.php
	新文件:   assets/opencc/vendor/symfony/polyfill-intl-grapheme/LICENSE
	新文件:   assets/opencc/vendor/symfony/polyfill-intl-grapheme/README.md
	新文件:   assets/opencc/vendor/symfony/polyfill-intl-grapheme/bootstrap.php
	新文件:   assets/opencc/vendor/symfony/polyfill-intl-grapheme/bootstrap80.php
	新文件:   assets/opencc/vendor/symfony/polyfill-intl-grapheme/composer.json
	新文件:   assets/opencc/vendor/symfony/polyfill-intl-normalizer/LICENSE
	新文件:   assets/opencc/vendor/symfony/polyfill-intl-normalizer/Normalizer.php
	新文件:   assets/opencc/vendor/symfony/polyfill-intl-normalizer/README.md
	新文件:   assets/opencc/vendor/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php
	新文件:   assets/opencc/vendor/symfony/polyfill-intl-normalizer/Resources/unidata/canonicalComposition.php
	新文件:   assets/opencc/vendor/symfony/polyfill-intl-normalizer/Resources/unidata/canonicalDecomposition.php
	新文件:   assets/opencc/vendor/symfony/polyfill-intl-normalizer/Resources/unidata/combiningClass.php
	新文件:   assets/opencc/vendor/symfony/polyfill-intl-normalizer/Resources/unidata/compatibilityDecomposition.php
	新文件:   assets/opencc/vendor/symfony/polyfill-intl-normalizer/bootstrap.php
	新文件:   assets/opencc/vendor/symfony/polyfill-intl-normalizer/bootstrap80.php
	新文件:   assets/opencc/vendor/symfony/polyfill-intl-normalizer/composer.json
	新文件:   assets/opencc/vendor/symfony/polyfill-mbstring/LICENSE
	新文件:   assets/opencc/vendor/symfony/polyfill-mbstring/Mbstring.php
	新文件:   assets/opencc/vendor/symfony/polyfill-mbstring/README.md
	新文件:   assets/opencc/vendor/symfony/polyfill-mbstring/Resources/unidata/caseFolding.php
	新文件:   assets/opencc/vendor/symfony/polyfill-mbstring/Resources/unidata/lowerCase.php
	新文件:   assets/opencc/vendor/symfony/polyfill-mbstring/Resources/unidata/titleCaseRegexp.php
	新文件:   assets/opencc/vendor/symfony/polyfill-mbstring/Resources/unidata/upperCase.php
	新文件:   assets/opencc/vendor/symfony/polyfill-mbstring/bootstrap.php
	新文件:   assets/opencc/vendor/symfony/polyfill-mbstring/bootstrap80.php
	新文件:   assets/opencc/vendor/symfony/polyfill-mbstring/composer.json
	新文件:   assets/opencc/vendor/symfony/process/CHANGELOG.md
	新文件:   assets/opencc/vendor/symfony/process/Exception/ExceptionInterface.php
	新文件:   assets/opencc/vendor/symfony/process/Exception/InvalidArgumentException.php
	新文件:   assets/opencc/vendor/symfony/process/Exception/LogicException.php
	新文件:   assets/opencc/vendor/symfony/process/Exception/ProcessFailedException.php
	新文件:   assets/opencc/vendor/symfony/process/Exception/ProcessSignaledException.php
	新文件:   assets/opencc/vendor/symfony/process/Exception/ProcessTimedOutException.php
	新文件:   assets/opencc/vendor/symfony/process/Exception/RunProcessFailedException.php
	新文件:   assets/opencc/vendor/symfony/process/Exception/RuntimeException.php
	新文件:   assets/opencc/vendor/symfony/process/ExecutableFinder.php
	新文件:   assets/opencc/vendor/symfony/process/InputStream.php
	新文件:   assets/opencc/vendor/symfony/process/LICENSE
	新文件:   assets/opencc/vendor/symfony/process/Messenger/RunProcessContext.php
	新文件:   assets/opencc/vendor/symfony/process/Messenger/RunProcessMessage.php
	新文件:   assets/opencc/vendor/symfony/process/Messenger/RunProcessMessageHandler.php
	新文件:   assets/opencc/vendor/symfony/process/PhpExecutableFinder.php
	新文件:   assets/opencc/vendor/symfony/process/PhpProcess.php
	新文件:   assets/opencc/vendor/symfony/process/PhpSubprocess.php
	新文件:   assets/opencc/vendor/symfony/process/Pipes/AbstractPipes.php
	新文件:   assets/opencc/vendor/symfony/process/Pipes/PipesInterface.php
	新文件:   assets/opencc/vendor/symfony/process/Pipes/UnixPipes.php
	新文件:   assets/opencc/vendor/symfony/process/Pipes/WindowsPipes.php
	新文件:   assets/opencc/vendor/symfony/process/Process.php
	新文件:   assets/opencc/vendor/symfony/process/ProcessUtils.php
	新文件:   assets/opencc/vendor/symfony/process/README.md
	新文件:   assets/opencc/vendor/symfony/process/composer.json
	新文件:   assets/opencc/vendor/symfony/service-contracts/Attribute/Required.php
	新文件:   assets/opencc/vendor/symfony/service-contracts/Attribute/SubscribedService.php
	新文件:   assets/opencc/vendor/symfony/service-contracts/CHANGELOG.md
	新文件:   assets/opencc/vendor/symfony/service-contracts/LICENSE
	新文件:   assets/opencc/vendor/symfony/service-contracts/README.md
	新文件:   assets/opencc/vendor/symfony/service-contracts/ResetInterface.php
	新文件:   assets/opencc/vendor/symfony/service-contracts/ServiceCollectionInterface.php
	新文件:   assets/opencc/vendor/symfony/service-contracts/ServiceLocatorTrait.php
	新文件:   assets/opencc/vendor/symfony/service-contracts/ServiceMethodsSubscriberTrait.php
	新文件:   assets/opencc/vendor/symfony/service-contracts/ServiceProviderInterface.php
	新文件:   assets/opencc/vendor/symfony/service-contracts/ServiceSubscriberInterface.php
	新文件:   assets/opencc/vendor/symfony/service-contracts/ServiceSubscriberTrait.php
	新文件:   assets/opencc/vendor/symfony/service-contracts/Test/ServiceLocatorTest.php
	新文件:   assets/opencc/vendor/symfony/service-contracts/Test/ServiceLocatorTestCase.php
	新文件:   assets/opencc/vendor/symfony/service-contracts/composer.json
	新文件:   assets/opencc/vendor/symfony/string/AbstractString.php
	新文件:   assets/opencc/vendor/symfony/string/AbstractUnicodeString.php
	新文件:   assets/opencc/vendor/symfony/string/ByteString.php
	新文件:   assets/opencc/vendor/symfony/string/CHANGELOG.md
	新文件:   assets/opencc/vendor/symfony/string/CodePointString.php
	新文件:   assets/opencc/vendor/symfony/string/Exception/ExceptionInterface.php
	新文件:   assets/opencc/vendor/symfony/string/Exception/InvalidArgumentException.php
	新文件:   assets/opencc/vendor/symfony/string/Exception/RuntimeException.php
	新文件:   assets/opencc/vendor/symfony/string/Inflector/EnglishInflector.php
	新文件:   assets/opencc/vendor/symfony/string/Inflector/FrenchInflector.php
	新文件:   assets/opencc/vendor/symfony/string/Inflector/InflectorInterface.php
	新文件:   assets/opencc/vendor/symfony/string/LICENSE
	新文件:   assets/opencc/vendor/symfony/string/LazyString.php
	新文件:   assets/opencc/vendor/symfony/string/README.md
	新文件:   assets/opencc/vendor/symfony/string/Resources/data/wcswidth_table_wide.php
	新文件:   assets/opencc/vendor/symfony/string/Resources/data/wcswidth_table_zero.php
	新文件:   assets/opencc/vendor/symfony/string/Resources/functions.php
	新文件:   assets/opencc/vendor/symfony/string/Slugger/AsciiSlugger.php
	新文件:   assets/opencc/vendor/symfony/string/Slugger/SluggerInterface.php
	新文件:   assets/opencc/vendor/symfony/string/UnicodeString.php
	新文件:   assets/opencc/vendor/symfony/string/composer.json
	新文件:   assets/phpliteadmin.php
	新文件:   config/Caddyfile
	新文件:   config/nginx.conf
	新文件:   cron.php
	新文件:   cron/requirements.txt
	新文件:   cron/update.py
	新文件:   index.php
	新文件:   manage.php
	新文件:   public.php
	新文件:   update.php
This commit is contained in:
mxd
2025-08-02 19:59:41 +08:00
parent ffb0d826bf
commit 57dae083a6
321 changed files with 180641 additions and 2 deletions

587
update.php Normal file
View File

@@ -0,0 +1,587 @@
<?php
/**
* @file update.php
* @brief 更新脚本
*
* 该脚本用于定期从配置的 XML 源下载节目数据,并将其存入 SQLite 数据库中。
*
* 作者: Tak
* GitHub: https://github.com/taksssss/EPG-Server
* 二次开发: mxdabc
* Github: https://github.com/mxdabc/epgphp
*/
// 禁用 PHP 输出缓冲
ob_implicit_flush(true);
@ob_end_flush();
// 设置 header防止浏览器缓存输出
header('X-Accel-Buffering: no');
// 显示 favicon
echo '<link rel="icon" href="assets/html/favicon.ico" type="image/x-icon">';
echo '<title>更新数据</title>';
// 引入公共脚本
require_once 'public.php';
ini_set('memory_limit', '256M');
// 设置超时时间为20分钟
set_time_limit(20*60);
// 删除过期数据和日志
function deleteOldData($db, &$log_messages) {
global $Config, $thresholdDate;
// 删除 t.xml 和 t.xml.gz 文件
@unlink(__DIR__ . '/t.xml');
@unlink(__DIR__ . '/t.xml.gz');
logMessage($log_messages, "[Start] 开始生成数据...");
echo "<strong>请注意:在生成数据期间无法访问XMLTV文件和API接口</strong>";
echo "<br>";
// 循环清理过期数据
$tables = [
'epg_data' => ['date', '清理EPG数据'],
'update_log' => ['timestamp', '清理更新日志'],
'cron_log' => ['timestamp', '清理定时日志']
];
foreach ($tables as $table => $values) {
list($column, $logMessage) = $values;
$stmt = $db->prepare("DELETE FROM $table WHERE $column < :thresholdDate");
$stmt->bindValue(':thresholdDate', $thresholdDate, PDO::PARAM_STR);
$stmt->execute();
logMessage($log_messages, "[{$logMessage}] 共 {$stmt->rowCount()} 条。");
}
// 清理 memcached 数据
if (class_exists('Memcached')) {
$memcached = new Memcached();
if ($memcached->addServer('127.0.0.1', 11211)) {
$memcached->flush();
logMessage($log_messages, "[Memcached] 已清空。");
} else {
logMessage($log_messages, "[Memcached] 状态异常。");
}
} else {
logMessage($log_messages, "[Memcached] 未安装。");
}
// 清理 redis 数据
if (class_exists('Redis')) {
$redis = new Redis();
try {
$redis->connect('127.0.0.1', 6379);
if (!empty($Config['redis_password'])) {
$redis->auth($Config['redis_password']);
}
$redis->flushAll();
logMessage($log_messages, "[Redis] 已清空。");
} catch (Exception $e) {
logMessage($log_messages, "[Redis] 状态异常:" . $e->getMessage());
}
} else {
logMessage($log_messages, "[Redis] 未安装。");
}
echo "<br>";
}
// 格式化时间函数,同时转化为 UTC+8 时间
function getFormatTime($time, $overwrite_time_zone) {
if (empty($time)) return ['', ''];
$time = $overwrite_time_zone ? substr($time, 0, -5) . $overwrite_time_zone : $time;
$time = str_replace(' ', '', $time);
$datetime = DateTime::createFromFormat('YmdHisO', $time);
if (!$datetime) return [null, null];
$datetime->setTimezone(new DateTimeZone('+0800'));
return [$datetime->format('Y-m-d'), $datetime->format('H:i')];
}
// 辅助函数:将日期和时间格式化为 XMLTV 格式
function formatTime($date, $time) {
return date('YmdHis O', strtotime("$date $time"));
}
// 获取限定频道列表及映射关系
function getGenList($db) {
global $Config;
$channels = $db->query("SELECT channel FROM gen_list")->fetchAll(PDO::FETCH_COLUMN);
if (empty($channels)) {
return ['gen_list_mapping' => [], 'gen_list' => []];
}
$channelsSimplified = explode("\n", t2s(implode("\n", $channels)));
$allEpgChannels = $db->query("SELECT DISTINCT channel FROM epg_data WHERE date = DATE('now')")
->fetchAll(PDO::FETCH_COLUMN); // 避免匹配只有历史 EPG 的频道
$gen_list_mapping = [];
$cleanedChannels = array_map('cleanChannelName', $channelsSimplified);
foreach ($cleanedChannels as $index => $cleanedChannel) {
$bestMatch = $cleanedChannel; // 默认使用清理后的频道名
$bestMatchLength = 0; // 初始为0表示未找到任何匹配
foreach ($allEpgChannels as $epgChannel) {
if (strcasecmp($cleanedChannel, $epgChannel) === 0) {
$bestMatch = $epgChannel;
break; // 精确匹配,立即跳出循环
}
// 模糊匹配并选择最长的频道名称
if ((stripos($epgChannel, $cleanedChannel) === 0 || stripos($cleanedChannel, $epgChannel) !== false)
&& strlen($epgChannel) > $bestMatchLength) {
$bestMatch = $epgChannel;
$bestMatchLength = strlen($epgChannel); // 更新为更长的匹配
}
}
// 将原始频道名称添加到映射数组中
$gen_list_mapping[$bestMatch][] = $channels[$index];
}
return [
'gen_list_mapping' => $gen_list_mapping,
'gen_list' => array_unique($cleanedChannels)
];
}
// 获取频道指定 EPG 关系
function getChannelBindEPG() {
global $Config;
$channelBindEPG = [];
foreach ($Config['channel_bind_epg'] ?? [] as $epg_src => $channels) {
foreach (array_map('trim', explode(',', $channels)) as $channel) {
$channelBindEPG[$channel][] = $epg_src;
}
}
return $channelBindEPG;
}
// 下载 XML 数据并存入数据库
function downloadXmlData($xml_url, $userAgent, $db, &$log_messages, $gen_list) {
global $Config;
$xml_data = downloadData($xml_url, $userAgent);
if ($xml_data !== false && stripos($xml_data, 'not found') === false) {
if (substr($xml_data, 0, 2) === "\x1F\x8B") { // 通过魔数判断 .gz 文件
$xml_data = gzdecode($xml_data);
if ($xml_data === false) {
logMessage($log_messages, ' [解压缩失败!!!]');
return;
}
}
// 获取文件大小(字节)并转换为 KB/MB
$fileSize = strlen($xml_data);
$fileSizeReadable = $fileSize >= 1048576
? round($fileSize / 1048576, 2) . ' MB'
: round($fileSize / 1024, 2) . ' KB';
logMessage($log_messages, "[下载] 成功: xml 文件 {$fileSizeReadable}");
$xml_data = preg_replace('/[\x00-\x1F]/u', ' ', $xml_data); // 清除所有控制字符
if (isset($Config['all_chs']) && $Config['all_chs']) { $xml_data = t2s($xml_data); }
$db->beginTransaction();
try {
$processCount = processXmlData($xml_url, $xml_data, $db, $gen_list);
$db->commit();
logMessage($log_messages, "[更新] 成功:共 {$processCount}");
} catch (Exception $e) {
$db->rollBack();
logMessage($log_messages, "[处理数据出错], 错误原因: " . $e->getMessage());
}
} else {
logMessage($log_messages, "[下载EPG数据] 失败!!!");
}
echo "<br>";
}
// 处理 XML 数据并逐步存入数据库
function processXmlData($xml_url, $xml_data, $db, $gen_list) {
global $Config, $processedRecords, $channel_bind_epg, $thresholdDate;
// 统计处理数据量
$processCount = 0;
$reader = new XMLReader();
if (!$reader->XML($xml_data)) {
throw new Exception("无法解析 XML 数据");
}
$cleanChannelNames = [];
// 读取频道数据
while ($reader->read() && $reader->name !== 'channel');
while ($reader->name === 'channel') {
$channel = new SimpleXMLElement($reader->readOuterXML());
$channelId = (string)$channel['id'];
$cleanChannelNames[$channelId] = cleanChannelName((string)$channel->{'display-name'});
$reader->next('channel');
}
// 繁简转换和频道筛选
$simplifiedChannelNames = (isset($Config['all_chs']) && $Config['all_chs']) ?
$cleanChannelNames : explode("\n", t2s(implode("\n", $cleanChannelNames)));
$channelNamesMap = [];
foreach ($cleanChannelNames as $channelId => $channelName) {
$channelNameSimplified = array_shift($simplifiedChannelNames);
// 假如 channel_bind_epg 存在且频道在其中有记录,且不为当前 xml_url直接跳过
if (!empty($channel_bind_epg) &&
isset($channel_bind_epg[$channelNameSimplified]) &&
!in_array($xml_url, $channel_bind_epg[$channelNameSimplified])
) {
continue; // 跳过当前循环,继续处理下一个
}
// 当 gen_list_enable 为 0 时,插入所有数据
if (empty($Config['gen_list_enable'])) {
$channelNamesMap[$channelId] = $channelNameSimplified;
continue;
}
$matchFound = false;
foreach ($gen_list as $item) {
if (stripos($channelNameSimplified, $item) !== false ||
stripos($item, $channelNameSimplified) !== false) {
$matchFound = true;
break;
}
}
if ($matchFound) {
$channelNamesMap[$channelId] = $channelNameSimplified;
}
}
$reader->close();
$reader->XML($xml_data); // 重置 XMLReader
while ($reader->read() && $reader->name !== 'programme');
$currentChannelProgrammes = [];
$crossDayProgrammes = []; // 保存跨天的节目数据
// 修正 epg.pw 时区错误
$overwrite_time_zone = strpos($xml_data, 'epg.pw') !== false ? '+0800' : '';
while ($reader->name === 'programme') {
$programme = new SimpleXMLElement($reader->readOuterXML());
[$startDate, $startTime] = getFormatTime((string)$programme['start'], $overwrite_time_zone);
[$endDate, $endTime] = getFormatTime((string)$programme['stop'], $overwrite_time_zone);
// 判断数据是否符合设定期限
if (empty($startDate) || $startDate < $thresholdDate || empty($endDate)) {
$reader->next('programme');
continue;
}
$channelId = (string)$programme['channel'];
$channelName = $channelNamesMap[$channelId] ?? null;
$recordKey = $channelName . '-' . $startDate;
// 优先处理跨天数据
if (isset($crossDayProgrammes[$channelId][$startDate]) && !isset($processedRecords[$recordKey])) {
$currentChannelProgrammes[$channelId]['diyp_data'][$startDate] = array_merge(
$currentChannelProgrammes[$channelId]['diyp_data'][$startDate] ?? [],
$crossDayProgrammes[$channelId][$startDate]
);
$currentChannelProgrammes[$channelId]['channel_name'] = $channelName;
unset($crossDayProgrammes[$channelId][$startDate]);
}
if ($channelName && !isset($processedRecords[$recordKey])) {
$programmeData = [
'start' => $startTime,
'end' => $startDate === $endDate ? $endTime : '00:00',
'title' => (string)$programme->title,
'desc' => isset($programme->desc) ? (string)$programme->desc : ''
];
$currentChannelProgrammes[$channelId]['diyp_data'][$startDate][] = $programmeData;
// 保存跨天的节目数据
if ($startDate !== $endDate && $endTime !== '00:00') {
$crossDayProgrammes[$channelId][$endDate][] = [
'start' => '00:00',
'end' => $endTime,
'title' => $programmeData['title'],
'desc' => $programmeData['desc']
];
}
$currentChannelProgrammes[$channelId]['channel_name'] = $channelName;
// 每次达到 50 时,插入数据并保留最后一条
if (count($currentChannelProgrammes) >= 50) {
$lastProgramme = array_pop($currentChannelProgrammes); // 取出最后一条
insertDataToDatabase($currentChannelProgrammes, $db, $xml_url); // 插入前 49 条
$currentChannelProgrammes = [$channelId => $lastProgramme]; // 清空并重新赋值最后一条
}
}
$processCount++;
$reader->next('programme');
}
// 插入剩余的数据
if ($currentChannelProgrammes) {
insertDataToDatabase($currentChannelProgrammes, $db, $xml_url);
}
$reader->close();
return $processCount;
}
// 从 epg_data 读取数据,生成 iconList.json 及 xmltv 文件
function processIconListAndXmltv($db, $gen_list_mapping, &$log_messages) {
global $Config, $iconList, $iconListPath;
$currentDate = date('Y-m-d'); // 获取当前日期
$dateCondition = $Config['include_future_only'] ? "WHERE date >= '$currentDate'" : '';
// 合并查询
$query = "SELECT date, channel, epg_diyp FROM epg_data $dateCondition ORDER BY channel ASC, date ASC";
$stmt = $db->query($query);
// 存储节目数据以按频道分组
$channelData = [];
while ($program = $stmt->fetch(PDO::FETCH_ASSOC)) {
$channelName = $program['channel'];
$iconUrl = iconUrlMatch($channelName, $getDefault = false);
if ($iconUrl) {
$iconList[strtoupper($channelName)] = $iconUrl;
$program['icon'] = $iconUrl;
}
// gen_list_enable 为 0 或存在映射,则处理频道数据
if (empty($Config['gen_list_enable']) || isset($gen_list_mapping[$channelName])) {
$channelData[$channelName][] = $program;
}
}
// 更新 iconList.json 文件中的数据
if (file_put_contents($iconListPath,
json_encode($iconList, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE)) === false) {
logMessage($log_messages, "[台标列表] 更新 iconList.json 时发生错误!!!");
} else {
logMessage($log_messages, "[台标列表] 已更新 iconList.json");
}
logMessage($log_messages, "[XMLTV] 开始生成并写入XMLTV文件...");
// 判断是否生成 xmltv 文件
if (empty($Config['gen_xml'])) {
return;
}
// 创建 XMLWriter 实例
$xmlFilePath = __DIR__ . '/t.xml';
$xmlWriter = new XMLWriter();
$xmlWriter->openUri($xmlFilePath);
$xmlWriter->startDocument('1.0', 'UTF-8');
$xmlWriter->startElement('tv');
$xmlWriter->writeAttribute('generator-info-name', 'CrestekkEPG');
$xmlWriter->writeAttribute('generator-info-url', 'https://github.com/mxdabc/epgphp');
$xmlWriter->setIndent(true);
$xmlWriter->setIndentString(' '); // 设置缩进
// 将 $Config['channel_mappings'] 中的映射值转换为数组
$channelMappings = array_map(function($mapped) {
return strpos($mapped, 'regex:') === 0 ? [$mapped] : array_map('trim', explode(',', $mapped));
}, $Config['channel_mappings']);
// 逐个频道处理
foreach ($channelData as $channelName => $programs) {
// 写入频道信息
$xmlWriter->startElement('channel');
$xmlWriter->writeAttribute('id', htmlspecialchars($channelName, ENT_XML1, 'UTF-8'));
// 为该频道生成多个 display-name ,包括原频道名、限定频道列表、频道别名
$displayNames = array_unique(array_merge(
[$channelName],
$gen_list_mapping[$channelName] ?? [],
$channelMappings[$channelName] ?? []
));
foreach ($displayNames as $displayName) {
$xmlWriter->startElement('display-name');
$xmlWriter->writeAttribute('lang', 'zh');
$xmlWriter->text(htmlspecialchars($displayName, ENT_XML1, 'UTF-8'));
$xmlWriter->endElement(); // display-name
}
$iconUrl = $programs[0]['icon'] ?? '';
if ($iconUrl) {
$xmlWriter->startElement('icon');
$xmlWriter->writeAttribute('src', $iconUrl);
$xmlWriter->endElement(); // icon
}
$xmlWriter->endElement(); // channel
// 写入该频道的所有节目数据
foreach ($programs as $programIndex => &$program) {
$data = json_decode($program['epg_diyp'], true);
$dataCount = count($data['epg_data']);
$end_date = $program['date'];
for ($index = 0; $index < $dataCount; $index++) {
$item = $data['epg_data'][$index];
$end_time = $item['end'];
// 如果结束时间为 00:00切换到第二天的日期
if ($end_time == '00:00') {
$end_date = date('Ymd', strtotime($end_date . ' +1 day')); // 切换日期
// 合并下一个节目
if (isset($programs[$programIndex + 1])) {
$nextData = json_decode($programs[$programIndex + 1]['epg_diyp'], true);
$nextItem = $nextData['epg_data'][0] ?? null;
if ($nextItem && $nextItem['title'] == $item['title']) {
$end_time = $nextItem['end'];
array_splice($nextData['epg_data'], 0, 1); // 删除下一个节目的第一个项目
$programs[$programIndex + 1]['epg_diyp'] = json_encode($nextData);
}
}
}
// 写入当前节目
$xmlWriter->startElement('programme');
$xmlWriter->writeAttribute('channel', htmlspecialchars($channelName, ENT_XML1, 'UTF-8'));
$xmlWriter->writeAttribute('start', formatTime($program['date'], $item['start']));
$xmlWriter->writeAttribute('stop', formatTime($end_date, $end_time));
$xmlWriter->startElement('title');
$xmlWriter->writeAttribute('lang', 'zh');
$xmlWriter->text(htmlspecialchars($item['title'], ENT_XML1, 'UTF-8'));
$xmlWriter->endElement(); // title
if (!empty($item['desc'])) {
$xmlWriter->startElement('desc');
$xmlWriter->writeAttribute('lang', 'zh');
$xmlWriter->text(htmlspecialchars($item['desc'], ENT_XML1, 'UTF-8'));
$xmlWriter->endElement(); // desc
}
$xmlWriter->endElement(); // programme
}
}
}
// 结束 XML 文档
$xmlWriter->endElement(); // tv
$xmlWriter->endDocument();
$xmlWriter->flush();
logMessage($log_messages, "[XMLTV] 开始生成GZ压缩文件...");
// 所有频道数据写入完成后,生成 t.xml.gz 文件
compressXmlFile($xmlFilePath);
logMessage($log_messages, "[XMLTV] GZ压缩文件压缩成功");
logMessage($log_messages, "[XMLTV] 已生成 t.xml 和 t.xml.gz");
}
// 生成 t.xml.gz 压缩文件
function compressXmlFile($xmlFilePath) {
$gzFilePath = $xmlFilePath . '.gz';
// 打开原文件和压缩文件
$file = fopen($xmlFilePath, 'rb');
$gzFile = gzopen($gzFilePath, 'wb9'); // 最高压缩等级
// 将文件内容写入到压缩文件中
while (!feof($file)) {
gzwrite($gzFile, fread($file, 1024 * 512));
}
// 关闭文件
fclose($file);
gzclose($gzFile);
}
// 记录开始时间
$startTime = microtime(true);
// 统计更新前数据条数
$initialCount = $db->query("SELECT COUNT(*) FROM epg_data")->fetchColumn();
// 删除过期数据
$thresholdDate = date('Y-m-d', strtotime("-{$Config['days_to_keep']} days +1 day"));
deleteOldData($db, $log_messages);
// 获取限定频道列表及映射关系
$gen_res = getGenList($db);
$gen_list = $gen_res['gen_list'];
$gen_list_mapping = $gen_res['gen_list_mapping'];
// 获取频道指定 EPG 关系
$channel_bind_epg = getChannelBindEPG();
// 全局变量,用于记录已处理的记录
$processedRecords = [];
// 更新数据
foreach ($Config['xml_urls'] as $xml_url) {
// 去掉空白字符,忽略空行和以 # 开头的 URL
$xml_url = trim($xml_url);
if (empty($xml_url) || strpos($xml_url, '#') === 0) {
continue;
} elseif (preg_match('/^(tvmao|cntv)/i', $xml_url, $matches)) {
$data_source = strtolower($matches[0]);
downloadJSONData($data_source, $xml_url, $db, $log_messages);
continue;
}
// 更新 XML 数据
list($xml_url_str, , $userAgent) = explode('#', $xml_url) + [1 => '', 2 => ''];
$userAgent = trim($userAgent);
$cleaned_url = trim(strpos($xml_url_str, '=>') !== false ? explode('=>', $xml_url_str)[1] : $xml_url_str);
logMessage($log_messages, "[地址] $cleaned_url");
// 判断是否有限定频道列表并下载数据
if (strpos($xml_url_str, '=>') !== false) {
$tmp_gen_list = array_map('trim', explode(",", explode('=>', $xml_url_str)[0]));
logMessage($log_messages, "[临时] 限定频道:" . implode(", ", $tmp_gen_list));
downloadXmlData($cleaned_url, $userAgent, $db, $log_messages, $tmp_gen_list, 1);
} else {
downloadXmlData($cleaned_url, $userAgent, $db, $log_messages, $gen_list);
}
}
// 更新 iconList.json 及生成 xmltv 文件
processIconListAndXmltv($db, $gen_list_mapping, $log_messages);
// 判断是否同步更新直播源
if (isset($Config['live_source_auto_sync']) && $Config['live_source_auto_sync'] == 1) {
$parseResult = doParseSourceInfo();
if ($parseResult !== true) {
logMessage($log_messages, "[直播文件] 部分更新异常:" . rtrim(str_replace('<br>', '、', $parseResult), '、'));
} else {
logMessage($log_messages, "[直播文件] 已同步更新");
}
}
// 统计更新后数据条数
$finalCount = $db->query("SELECT COUNT(*) FROM epg_data")->fetchColumn();
$dif = $finalCount - $initialCount;
$msg = $dif != 0 ? ($dif > 0 ? " 增加 $dif" : " 减少 " . abs($dif) . "") : "";
// 记录结束时间
$endTime = microtime(true);
// 计算运行时间(以秒为单位)
$executionTime = round($endTime - $startTime, 1);
echo "<br>";
logMessage($log_messages, "[更新完成] {$executionTime} 秒。节目天数:更新前 {$initialCount} ,更新后 {$finalCount}" . $msg);
// 将日志信息写入数据库
$log_message_str = implode("<br>", $log_messages);
$timestamp = date('Y-m-d H:i:s'); // 使用设定的时区时间
$stmt = $db->prepare('INSERT INTO update_log (timestamp, log_message) VALUES (:timestamp, :log_message)');
$stmt->bindValue(':timestamp', $timestamp, PDO::PARAM_STR);
$stmt->bindValue(':log_message', $log_message_str, PDO::PARAM_STR);
$stmt->execute();
?>