Files
epgphp/manage.php
mxdabc 57dae083a6 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
2025-08-02 19:59:41 +08:00

784 lines
36 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
/**
* @file manage.php
* @brief 管理页面部分
*
* 管理界面脚本,用于处理会话管理、密码更改、登录验证、配置更新、更新日志展示等功能。
*
* 作者: Tak
* GitHub: https://github.com/taksssss/EPG-Server
* 二次开发: mxdabc
* Github: https://github.com/mxdabc/epgphp
*/
// 引入公共脚本,初始化数据库
require_once 'public.php';
initialDB();
session_start();
// 首次进入界面,检查 cron.php 是否运行正常
if ($Config['interval_time'] !== 0) {
$output = [];
exec("ps aux | grep '[c]ron.php'", $output);
if(!$output) {
exec('php cron.php > /dev/null 2>/dev/null &');
}
}
// 过渡到新的 md5 密码并生成默认 token、user_agent (如果不存在或为空)
if (!preg_match('/^[a-f0-9]{32}$/i', $Config['manage_password']) || empty($Config['token']) || empty($Config['user_agent'])) {
if (!preg_match('/^[a-f0-9]{32}$/i', $Config['manage_password'])) {
$Config['manage_password'] = md5($Config['manage_password']);
}
if (empty($Config['token'])) {
$Config['token'] = substr(bin2hex(random_bytes(5)), 0, 10); // 生成 10 位随机字符串
}
if (empty($Config['user_agent'])) {
$Config['user_agent'] = substr(bin2hex(random_bytes(5)), 0, 10); // 生成 10 位随机字符串
}
file_put_contents($configPath, json_encode($Config, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
}
// 处理密码更新请求
if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_POST['change_password'])) {
$oldPassword = md5($_POST['old_password']);
$newPassword = md5($_POST['new_password']);
// 验证原密码是否正确
if ($oldPassword === $Config['manage_password']) {
// 原密码正确,更新配置中的密码
$Config['manage_password'] = $newPassword;
// 将新配置写回 config.json
file_put_contents($configPath, json_encode($Config, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
// 设置密码更改成功的标志变量
$passwordChanged = true;
} else {
$passwordChangeError = "原密码错误";
}
}
// 检查是否提交登录表单
if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_POST['login'])) {
$password = md5($_POST['password']);
// 验证密码
if ($password === $Config['manage_password']) {
// 密码正确,设置会话变量
$_SESSION['loggedin'] = true;
// 设置会话变量,表明用户可以访问 phpliteadmin.php 、 tinyfilemanager.php
$_SESSION['can_access_phpliteadmin'] = true;
$_SESSION['can_access_tinyfilemanager'] = true;
} else {
$error = "密码错误";
}
}
// 处理密码更改成功后的提示
$passwordChangedMessage = isset($passwordChanged) ? "<p style='color:green;'>密码已更改</p>" : '';
$passwordChangeErrorMessage = isset($passwordChangeError) ? "<p style='color:red;'>$passwordChangeError</p>" : '';
// 检查是否已登录
if (!isset($_SESSION['loggedin']) || $_SESSION['loggedin'] !== true) {
// 显示登录表单
include 'assets/html/login.html';
exit;
}
// 更新配置
function updateConfigFields() {
global $Config, $configPath;
// 获取和过滤表单数据
$config_keys = array_keys(array_filter($_POST, function($key) {
return $key !== 'update_config';
}, ARRAY_FILTER_USE_KEY));
foreach ($config_keys as $key) {
${$key} = is_numeric($_POST[$key]) ? intval($_POST[$key]) : $_POST[$key];
}
// 处理 URL 列表和频道别名
$xml_urls = array_values(array_map(function($url) {
return preg_replace('/^#\s*(\S+)(\s*#.*)?$/', '# $1$2', trim(str_replace(["", ""], [",", ":"], $url)));
}, explode("\n", $xml_urls)));
$interval_time = $interval_hour * 3600 + $interval_minute * 60;
$mysql = ["host" => $mysql_host, "dbname" => $mysql_dbname, "username" => $mysql_username, "password" => $mysql_password];
// 解析频道别名
$channel_mappings = [];
if ($mappings = trim($_POST['channel_mappings'] ?? '')) {
foreach (explode("\n", $mappings) as $line) {
if ($line = trim($line)) {
list($search, $replace) = preg_split('/=》|=>/', $line);
$channel_mappings[trim($search)] = trim(str_replace("", ",", trim($replace)), '[]');
}
}
}
// 解析频道 EPG 数据
$channel_bind_epg = isset($_POST['channel_bind_epg']) ? array_filter(array_reduce(json_decode($_POST['channel_bind_epg'], true), function($result, $item) {
$epgSrc = preg_replace('/^【已停用】/', '', $item['epg_src']);
if (!empty($item['channels'])) $result[$epgSrc] = trim(str_replace("", ",", trim($item['channels'])), '[]');
return $result;
}, [])) : $Config['channel_bind_epg'];
// 更新 $Config
$oldConfig = $Config;
$config_keys_filtered = array_filter($config_keys, function($key) {
return !preg_match('/^(mysql_|interval_)/', $key);
});
$config_keys_new = ['channel_bind_epg', 'interval_time', 'mysql'];
$config_keys_save = array_merge($config_keys_filtered, $config_keys_new);
foreach ($config_keys_save as $key) {
if (isset($$key)) {
$Config[$key] = $$key;
}
}
// 检查 MySQL 有效性
$db_type_set = true;
if ($Config['db_type'] === 'mysql') {
try {
$dsn = "mysql:host={$Config['mysql']['host']};dbname={$Config['mysql']['dbname']};charset=utf8mb4";
$db = new PDO($dsn, $Config['mysql']['username'] ?? null, $Config['mysql']['password'] ?? null);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
$Config['db_type'] = 'sqlite';
$db_type_set = false;
}
}
// 将新配置写回 config.json
file_put_contents($configPath, json_encode($Config, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
// 重新启动 cron.php ,设置新的定时任务
if ($oldConfig['start_time'] !== $start_time || $oldConfig['end_time'] !== $end_time || $oldConfig['interval_time'] !== $interval_time) {
exec('php cron.php > /dev/null 2>/dev/null &');
}
return ['db_type_set' => $db_type_set];
}
// 处理服务器请求
try {
$requestMethod = $_SERVER['REQUEST_METHOD'];
$dbResponse = null;
if ($requestMethod == 'GET') {
// 确定操作类型
$action_map = [
'get_update_logs', 'get_cron_logs', 'get_channel', 'get_epg_by_channel',
'get_icon', 'get_channel_bind_epg', 'get_channel_match', 'get_gen_list',
'get_live_data', 'parse_source_info', 'toggle_status',
'download_data', 'delete_unused_icons', 'delete_unused_live_data',
'get_version_log'
];
$action = key(array_intersect_key($_GET, array_flip($action_map))) ?: '';
// 根据操作类型执行不同的逻辑
switch ($action) {
case 'get_update_logs':
// 获取更新日志
$dbResponse = $db->query("SELECT * FROM update_log")->fetchAll(PDO::FETCH_ASSOC);
break;
case 'get_cron_logs':
// 获取 cron 日志
$dbResponse = $db->query("SELECT * FROM cron_log")->fetchAll(PDO::FETCH_ASSOC);
break;
case 'get_channel':
// 获取频道
$channels = $db->query("SELECT DISTINCT channel FROM epg_data ORDER BY channel ASC")->fetchAll(PDO::FETCH_COLUMN);
$channelMappings = $Config['channel_mappings'];
$mappedChannels = [];
foreach ($channelMappings as $mapped => $original) {
if (($index = array_search(strtoupper($mapped), $channels)) !== false) {
$mappedChannels[] = [
'original' => $mapped,
'mapped' => $original
];
unset($channels[$index]); // 从剩余频道中移除
}
}
foreach ($channels as $channel) {
$mappedChannels[] = [
'original' => $channel,
'mapped' => ''
];
}
$dbResponse = [
'channels' => $mappedChannels,
'count' => count($mappedChannels)
];
break;
case 'get_epg_by_channel':
// 查询
$channel = $_GET['channel'];
$date = urldecode($_GET['date']);
$stmt = $db->prepare("SELECT epg_diyp FROM epg_data WHERE channel = :channel AND date = :date");
$stmt->execute([':channel' => $channel, ':date' => $date]);
$result = $stmt->fetch(PDO::FETCH_ASSOC); // 获取单条结果
if ($result) {
$epgData = json_decode($result['epg_diyp'], true);
$epgSource = $epgData['source'] ?? '';
$epgOutput = "";
foreach ($epgData['epg_data'] as $epgItem) {
$epgOutput .= "{$epgItem['start']} {$epgItem['title']}\n";
}
$dbResponse = ['channel' => $channel, 'source' => $epgSource, 'date' => $date, 'epg' => trim($epgOutput)];
} else {
$dbResponse = ['channel' => $channel, 'source' => '', 'date' => $date, 'epg' => '无节目信息'];
}
break;
case 'get_icon':
// 是否显示无节目单的内置台标
if(isset($_GET['get_all_icon'])) {
$iconList = $iconListMerged;
}
// 获取并合并数据库中的频道和 $iconList 中的频道,去重后按字母排序
$allChannels = array_unique(array_merge(
$db->query("SELECT DISTINCT channel FROM epg_data ORDER BY channel ASC")->fetchAll(PDO::FETCH_COLUMN),
array_keys($iconList)
));
sort($allChannels);
// 将默认台标插入到频道列表的开头
$defaultIcon = [
['channel' => '【默认台标】', 'icon' => $Config['default_icon'] ?? '']
];
$channelsInfo = array_map(function($channel) use ($iconList) {
return ['channel' => $channel, 'icon' => $iconList[$channel] ?? ''];
}, $allChannels);
$withIcons = array_filter($channelsInfo, function($c) { return !empty($c['icon']);});
$withoutIcons = array_filter($channelsInfo, function($c) { return empty($c['icon']);});
$dbResponse = [
'channels' => array_merge($defaultIcon, $withIcons, $withoutIcons),
'count' => count($allChannels)
];
break;
case 'get_channel_bind_epg':
// 获取频道绑定的 EPG
$channels = $db->query("SELECT DISTINCT channel FROM epg_data ORDER BY channel ASC")->fetchAll(PDO::FETCH_COLUMN);
$channelBindEpg = $Config['channel_bind_epg'] ?? [];
$xmlUrls = $Config['xml_urls'];
$dbResponse = array_map(function($epgSrc) use ($channelBindEpg) {
$cleanEpgSrc = trim(explode('#', strpos($epgSrc, '=>') !== false ? explode('=>', $epgSrc)[1] : ltrim($epgSrc, '# '))[0]);
$isInactive = strpos(trim($epgSrc), '#') === 0;
return [
'epg_src' => ($isInactive ? '【已停用】' : '') . $cleanEpgSrc,
'channels' => $channelBindEpg[$cleanEpgSrc] ?? ''
];
}, array_filter($xmlUrls, function($epgSrc) {
// 去除空行和包含 tvmao、cntv 的行
return !empty(ltrim($epgSrc, '# ')) && strpos($epgSrc, 'tvmao') === false && strpos($epgSrc, 'cntv') === false;
}));
$dbResponse = array_merge(
array_filter($dbResponse, function($item) { return strpos($item['epg_src'], '【已停用】') === false; }),
array_filter($dbResponse, function($item) { return strpos($item['epg_src'], '【已停用】') !== false; })
);
break;
case 'get_channel_match':
// 获取频道匹配
$channels = $db->query("SELECT channel FROM gen_list")->fetchAll(PDO::FETCH_COLUMN);
if (empty($channels)) {
echo json_encode(['ori_channels' => [], 'clean_channels' => [], 'match' => [], 'type' => []]);
exit;
}
$cleanChannels = explode("\n", t2s(implode("\n", array_map('cleanChannelName', $channels))));
$epgData = $db->query("SELECT channel FROM epg_data")->fetchAll(PDO::FETCH_COLUMN);
$channelMap = array_combine($cleanChannels, $channels);
$matches = [];
foreach ($cleanChannels as $cleanChannel) {
$originalChannel = $channelMap[$cleanChannel];
$matchResult = null;
$matchType = '未匹配';
if (in_array($cleanChannel, $epgData)) {
$matchResult = $cleanChannel;
$matchType = '精确匹配';
if ($cleanChannel !== $originalChannel) {
$matchType = '别名/忽略';
}
} else {
foreach ($epgData as $epgChannel) {
if (stripos($epgChannel, $cleanChannel) !== false) {
if (!isset($matchResult) || strlen($epgChannel) < strlen($matchResult)) {
$matchResult = $epgChannel;
$matchType = '正向模糊';
}
} elseif (stripos($cleanChannel, $epgChannel) !== false) {
if (!isset($matchResult) || strlen($epgChannel) > strlen($matchResult)) {
$matchResult = $epgChannel;
$matchType = '反向模糊';
}
}
}
}
$matches[$cleanChannel] = [
'ori_channel' => $originalChannel,
'clean_channel' => $cleanChannel,
'match' => $matchResult,
'type' => $matchType
];
}
$dbResponse = $matches;
break;
case 'get_gen_list':
// 获取生成列表
$dbResponse = $db->query("SELECT channel FROM gen_list")->fetchAll(PDO::FETCH_COLUMN);
break;
case 'get_live_data':
// 读取文件内容
function readFileContent($filePath) {
return file_exists($filePath) ? file_get_contents($filePath) : '';
}
$sourceContent = readFileContent($liveDir . 'source.txt');
$templateContent = readFileContent($liveDir . 'template.txt');
// 读取 CSV 文件并返回关联数组
function readCsvFile($filePath, $key = null) {
if (!file_exists($filePath)) return [];
$data = [];
if (($file = fopen($filePath, 'r')) !== false) {
$header = fgetcsv($file);
while (($row = fgetcsv($file)) !== false) {
if (empty(array_filter($row)) || count($row) !== count($header)) continue;
$rowData = array_combine($header, $row);
if ($key && isset($rowData[$key])) {
$data[$rowData[$key]] = $rowData; // 使用指定键映射
} else {
$data[] = $rowData;
}
}
fclose($file);
}
return $data;
}
$channelsInfo = readCsvFile($liveDir . 'channels_info.csv', 'tag');
$channelsData = readCsvFile($liveDir . 'channels.csv');
// 更新 channelsData 中的 resolution 和 speed
foreach ($channelsData as &$row) {
if (isset($channelsInfo[$row['tag']])) {
$row['resolution'] = str_replace("x", "<br>x<br>", $channelsInfo[$row['tag']]['resolution']);
$row['speed'] = $channelsInfo[$row['tag']]['speed'];
if (is_numeric($row['speed'])) { $row['speed'] .= '<br>ms';}
}
}
generateLiveFiles($channelsData, 'tv', $saveOnly = true); // 重新生成 M3U 和 TXT 文件
$dbResponse = ['source_content' => $sourceContent, 'template_content' => $templateContent, 'channels' => $channelsData,];
break;
case 'parse_source_info':
// 解析直播源
$parseResult = doParseSourceInfo();
if ($parseResult !== true) {
$dbResponse = ['success' => 'part', 'message' => $parseResult];
} else {
$dbResponse = ['success' => 'full'];
}
break;
case 'toggle_status':
// 切换状态
$toggleField = $_GET['toggle_button'] === 'toggleLiveSourceSyncBtn' ? 'live_source_auto_sync'
: ($_GET['toggle_button'] === 'toggleLiveChannelNameProcessBtn' ? 'live_channel_name_process' : '');
$currentStatus = isset($Config[$toggleField]) && $Config[$toggleField] == 1 ? 1 : 0;
$newStatus = ($currentStatus == 1) ? 0 : 1;
$Config[$toggleField] = $newStatus;
file_put_contents($configPath, json_encode($Config, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
$dbResponse = ['status' => $newStatus];
break;
case 'download_data':
// 下载数据
$url = filter_var(($_GET['url']), FILTER_VALIDATE_URL);
if ($url) {
$data = downloadData($url, '', 5);
if ($data !== false) {
$dbResponse = ['success' => true, 'data' => $data];
} else {
$dbResponse = ['success' => false, 'message' => '无法获取URL内容'];
}
} else {
$dbResponse = ['success' => false, 'message' => '无效的URL'];
}
break;
case 'delete_unused_icons':
// 清理未在使用的台标
$iconUrls = array_merge(
array_map(function($url) { return parse_url($url, PHP_URL_PATH); }, $iconList),
[parse_url($Config["default_icon"], PHP_URL_PATH)]
);
$iconPath = __DIR__ . '/data/icon';
$deletedCount = 0;
foreach (scandir($iconPath) as $file) {
if ($file === '.' || $file === '..') continue;
$iconRltPath = '/data/icon/' . $file;
if (!in_array($iconRltPath, $iconUrls)) {
if (@unlink($iconPath . '/' . $file)) {
$deletedCount++;
}
}
}
$dbResponse = ['success' => true, 'message' => "共清理了 $deletedCount 个台标"];
break;
case 'delete_unused_live_data':
// 清理未在使用的直播源缓存、未出现在频道列表中的修改记录
$sourceFilePath = $liveDir . 'source.txt';
$sourceContent = file_exists($sourceFilePath) ? file_get_contents($sourceFilePath) : '';
$urls = array_map('trim', explode("\n", $sourceContent));
// 遍历 live/file 目录,删除未使用的文件
$parentRltPath = '/' . basename(__DIR__) . '/data/live/file/'; // 相对路径
$deletedFileCount = 0;
foreach (scandir($liveFileDir) as $file) {
if ($file === '.' || $file === '..') continue;
$fileRltPath = $parentRltPath . $file;
if (!array_filter($urls, function($url) use ($fileRltPath) {
$url = trim(explode('#', ltrim($url, '# '))[0]); // 处理注释
$urlmd5 = md5(urlencode($url)); // 计算 md5
return $url && (stripos($fileRltPath, $url) !== false || stripos($fileRltPath, $urlmd5) !== false);
})) {
if (@unlink($liveFileDir . $file)) { // 如果没有匹配的 URL删除文件
$deletedFileCount++;
}
}
}
// 删除 modifications.csv 未在 channels.csv 中出现的条目
$channelsFilePath = $liveDir . 'channels.csv';
$modificationsFilePath = $liveDir . 'modifications.csv';
$deletedRecordCount = 0;
if (file_exists($channelsFilePath) && file_exists($modificationsFilePath)) {
// 读取 channels.csv 中的 tag 字段
$channelTags = [];
$file = fopen($channelsFilePath, 'r');
$header = fgetcsv($file);
while (($row = fgetcsv($file)) !== false) {
$channelTags[] = $row[array_search('tag', $header)];
}
fclose($file);
// 过滤 modifications.csv 数据并统计移除行数
$file = fopen($modificationsFilePath, 'r');
$modificationsHeader = fgetcsv($file);
$filteredData = [];
while (($row = fgetcsv($file)) !== false) {
if (in_array($row[array_search('tag', $modificationsHeader)], $channelTags)) {
$filteredData[] = $row;
} else {
$deletedRecordCount++;
}
}
fclose($file);
// 写回过滤后的数据
$file = fopen($modificationsFilePath, 'w');
fputcsv($file, $modificationsHeader);
foreach ($filteredData as $row) {
fputcsv($file, $row);
}
fclose($file);
}
$dbResponse = ['success' => true, 'message' => "共清理了 $deletedFileCount 个缓存文件, $deletedRecordCount 条修改记录。"];
break;
case 'get_version_log':
// 获取更新日志
$checkUpdateEnable = !isset($Config['check_update']) || $Config['check_update'] == 1;
$checkUpdate = isset($_GET['do_check_update']) && $_GET['do_check_update'] === 'true';
if (!$checkUpdateEnable && $checkUpdate) {
echo json_encode(['success' => true, 'is_updated' => false]);
return;
}
$localFile = 'assets/CHANGELOG.md';
$url = 'https://gitee.com/taksssss/EPG-Server/raw/main/CHANGELOG.md';
$isUpdated = false;
$updateMessage = '';
if ($checkUpdate) {
$remoteContent = @file_get_contents($url);
if ($remoteContent === false) {
echo json_encode(['success' => false, 'message' => '无法获取远程版本日志']);
return;
}
$localContent = file_exists($localFile) ? file_get_contents($localFile) : '';
if (strtok($localContent, "\n") !== strtok($remoteContent, "\n")) {
file_put_contents($localFile, $remoteContent);
$isUpdated = !empty($localContent) ? true : false;
$updateMessage = '<h3 style="color: red;">🔔 检测到新版本,请自行更新。(该提醒仅显示一次)</h3>';
}
}
$markdownContent = file_exists($localFile) ? file_get_contents($localFile) : false;
if ($markdownContent === false) {
echo json_encode(['success' => false, 'message' => '无法读取版本日志']);
return;
}
require_once 'assets/Parsedown.php';
$htmlContent = (new Parsedown())->text($markdownContent);
$dbResponse = ['success' => true, 'content' => $updateMessage . $htmlContent, 'is_updated' => $isUpdated];
break;
default:
$dbResponse = null;
break;
}
if ($dbResponse !== null) {
header('Content-Type: application/json');
echo json_encode($dbResponse);
exit;
}
}
// 处理 POST 请求
if ($requestMethod === 'POST') {
// 定义操作类型和对应的条件
$actions = [
'update_config' => isset($_POST['update_config']),
'set_gen_list' => isset($_GET['set_gen_list']),
'import_config' => isset($_POST['importExport']) && !empty($_FILES['importFile']['tmp_name']),
'export_config' => isset($_POST['importExport']) && empty($_FILES['importFile']['tmp_name']),
'upload_icon' => isset($_FILES['iconFile']),
'update_icon_list' => isset($_POST['update_icon_list']),
'upload_source_file' => isset($_FILES['liveSourceFile']),
'save_content_to_file' => isset($_POST['save_content_to_file']),
'save_source_info' => isset($_POST['save_source_info']),
'update_config_field' => isset($_POST['update_config_field']),
];
// 确定操作类型
$action = '';
foreach ($actions as $key => $condition) {
if ($condition) { $action = $key; break; }
}
switch ($action) {
case 'update_config':
// 更新配置
['db_type_set' => $db_type_set] = updateConfigFields();
echo json_encode([
'db_type_set' => $db_type_set,
'interval_time' => $Config['interval_time'],
'start_time' => $Config['start_time'],
'end_time' => $Config['end_time']
]);
exit;
case 'set_gen_list':
// 设置生成列表
$data = json_decode(file_get_contents("php://input"), true)['data'] ?? '';
try {
$db->beginTransaction();
$db->exec("DELETE FROM gen_list");
$lines = array_filter(array_map('trim', explode("\n", $data)));
foreach ($lines as $line) {
$stmt = $db->prepare("INSERT INTO gen_list (channel) VALUES (:channel)");
$stmt->bindValue(':channel', $line, PDO::PARAM_STR);
$stmt->execute();
}
$db->commit();
echo 'success';
} catch (PDOException $e) {
$db->rollBack();
echo "数据库操作失败: " . $e->getMessage();
}
exit;
case 'import_config':
// 导入配置
$zip = new ZipArchive();
$importFile = $_FILES['importFile']['tmp_name'];
$successFlag = false;
$message = "";
if ($zip->open($importFile) === TRUE) {
if ($zip->extractTo('.')) {
$successFlag = true;
$message = "导入成功!<br>3秒后自动刷新页面……";
} else {
$message = "导入失败!解压过程中发生问题。";
}
$zip->close();
} else {
$message = "导入失败!无法打开压缩文件。";
}
echo json_encode(['success' => $successFlag, 'message' => $message]);
exit;
case 'export_config':
$zip = new ZipArchive();
$zipFileName = 't.gz';
if ($zip->open($zipFileName, ZipArchive::CREATE | ZipArchive::OVERWRITE) === TRUE) {
$dataDir = __DIR__ . '/data';
$files = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($dataDir),
RecursiveIteratorIterator::LEAVES_ONLY
);
foreach ($files as $file) {
if (!$file->isDir()) {
$filePath = $file->getRealPath();
$relativePath = 'data/' . substr($filePath, strlen($dataDir) + 1);
$zip->addFile($filePath, $relativePath);
}
}
$zip->close();
header('Content-Type: application/zip');
header('Content-Disposition: attachment; filename=' . $zipFileName);
readfile($zipFileName);
unlink($zipFileName);
}
exit;
case 'upload_icon':
// 上传图标
$file = $_FILES['iconFile'];
$fileName = $file['name'];
$uploadFile = $iconDir . $fileName;
if ($file['type'] === 'image/png' && move_uploaded_file($file['tmp_name'], $uploadFile)) {
$iconUrl = $serverUrl . '/data/icon/' . basename($fileName);
echo json_encode(['success' => true, 'iconUrl' => $iconUrl]);
} else {
echo json_encode(['success' => false, 'message' => '文件上传失败']);
}
exit;
case 'update_icon_list':
// 更新图标
$iconList = [];
$updatedIcons = json_decode($_POST['updatedIcons'], true);
// 遍历更新数据
foreach ($updatedIcons as $channelData) {
$channelName = strtoupper(trim($channelData['channel']));
if ($channelName === '【默认台标】') {
// 保存默认台标到 config.json
$Config['default_icon'] = $channelData['icon'] ?? '';
file_put_contents($configPath, json_encode($Config, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
} else {
// 处理普通台标数据
$iconList[$channelName] = $channelData['icon'];
}
}
// 过滤掉图标值为空和频道名为空的条目
$iconList = array_filter($iconList, function($icon, $channel) {
return !empty($icon) && !empty($channel);
}, ARRAY_FILTER_USE_BOTH);
if (file_put_contents($iconListPath, json_encode($iconList, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE)) === false) {
echo json_encode(['success' => false, 'message' => '更新 iconList.json 时发生错误']);
} else {
echo json_encode(['success' => true]);
}
exit;
case 'upload_source_file':
// 上传直播源文件
$file = $_FILES['liveSourceFile'];
$fileName = $file['name'];
$uploadFile = $liveFileDir . $fileName;
if (move_uploaded_file($file['tmp_name'], $uploadFile)) {
$liveSourceUrl = '/data/live/file/' . basename($fileName);
$sourceFilePath = $liveDir . 'source.txt';
$currentContent = file_get_contents($sourceFilePath);
if (!file_exists($sourceFilePath) || strpos($currentContent, $liveSourceUrl) === false) {
// 如果文件不存在或文件中没有该 URL将其追加到文件末尾
$contentToAppend = trim($currentContent) ? PHP_EOL . $liveSourceUrl : $liveSourceUrl;
file_put_contents($sourceFilePath, $contentToAppend, FILE_APPEND);
}
echo json_encode(['success' => true]);
} else {
echo json_encode(['success' => false, 'message' => '文件上传失败']);
}
exit;
case 'save_content_to_file':
// 保存内容到文件
$filePath = __DIR__ . $_POST['file_path'] ?? '';
$content = $_POST['content'] ?? '';
if (file_put_contents($filePath, str_replace("", ",", $content)) !== false) {
echo json_encode(['success' => true]);
} else {
http_response_code(500);
echo json_encode(['success' => false]);
}
exit;
case 'save_source_info':
// 更新配置文件
$Config['live_tvg_logo_enable'] = (int)$_POST['live_tvg_logo_enable'];
$Config['live_tvg_id_enable'] = (int)$_POST['live_tvg_id_enable'];
$Config['live_tvg_name_enable'] = (int)$_POST['live_tvg_name_enable'];
if (file_put_contents($configPath, json_encode($Config, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)) === false) {
http_response_code(500);
echo json_encode(['success' => false, 'message' => '保存配置文件失败']);
exit;
}
// 保存直播源信息
$content = json_decode($_POST['content'], true);
if (empty($content)) {
echo json_encode(['success' => false, 'message' => '无效的数据']);
exit;
}
$fileName = $_POST['file_path'] ? 'file/' . md5(urlencode($_POST['file_path'])) : 'tv';
generateLiveFiles($content, $fileName, $saveOnly = true); // 重新生成 M3U 和 TXT 文件
echo json_encode(['success' => true]);
exit;
case 'update_config_field':
// 更新单个字段
foreach ($_POST as $key => $value) {
// 排除 update_config_field 字段
if ($key !== 'update_config_field') {
$Config[$key] = is_numeric($value) ? intval($value) : $value;
}
}
if (file_put_contents($configPath, json_encode($Config, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)) !== false) {
echo json_encode(['success' => $Config]);
} else {
http_response_code(500);
echo '保存失败';
}
exit;
}
}
} catch (Exception $e) {
// 处理数据库连接错误
}
// 生成配置管理表单
include 'assets/html/manage.html';
?>