diff --git a/.run/Help.run.xml b/.run/Help.run.xml
new file mode 100644
index 0000000..16706ca
--- /dev/null
+++ b/.run/Help.run.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/composer.json b/composer.json
index 6fdc6b1..6880b6b 100644
--- a/composer.json
+++ b/composer.json
@@ -8,7 +8,8 @@
},
"minimum-stability": "stable",
"require": {
- "php": "^8.3"
+ "php": "^8.3",
+ "symfony/console": "^7.0"
},
"autoload": {
"psr-4": {
@@ -31,4 +32,4 @@
"docs": "https://git.jrosset.ovh/jrosset/calibre_metadata_parser_ff/wiki",
"source": "https://git.jrosset.ovh/jrosset/calibre_metadata_parser_ff"
}
-}
\ No newline at end of file
+}
diff --git a/run.php b/run.php
new file mode 100644
index 0000000..bc81103
--- /dev/null
+++ b/run.php
@@ -0,0 +1,9 @@
+run();
diff --git a/src/Main.php b/src/Main.php
new file mode 100644
index 0000000..ad26497
--- /dev/null
+++ b/src/Main.php
@@ -0,0 +1,137 @@
+command = (new SingleCommandApplication())
+ ->setName('calibre_metadata_parser_ff')
+ ->setDescription(<<<'EOF'
+Calibre metadata parser for FanFiction files
+
+ Each input file, if valid (EPUB file), is transformed to a Calibre input directory, containing the EPUB file and the metadata file (metadata.opf).
+ The metadata are extracted from the "title" page of the EPUB, based on FicHub.net or FF2EBOOK.com.
+EOF
+ )
+ ->addArgument(
+ Main::ARGUMENT_FILES,
+ InputArgument::REQUIRED | InputArgument::IS_ARRAY,
+ 'The files or directories to process'
+ )
+ ->setCode($this->execute(...));
+ }
+
+ /**
+ * Run the command
+ *
+ * @return void
+ *
+ * @throws Throwable If an error occurs
+ */
+ public function run(): void
+ {
+ $this->command->run();
+ }
+
+ /**
+ * Execute the command
+ *
+ * @param InputInterface $input The command line input
+ * @param OutputInterface $output The command line output
+ *
+ * @return int The command exit status code
+ *
+ * @throws Throwable If an error occurs
+ */
+ private function execute(InputInterface $input, OutputInterface $output): int
+ {
+ foreach ($input->getArgument(self::ARGUMENT_FILES) as $file) {
+ //region Check if file or directory exists
+ $fileInfo = new SplFileInfo($file);
+ if (!file_exists($file)) {
+ $output->writeln('Unable to find ' . ($fileInfo->isDir() ? 'directory' : 'file') . ': ' . $fileInfo->getPathname() . '');
+ }
+ //endregion
+
+ if ($fileInfo->isDir()) {
+ $this->processDirectory($file, $output);
+ } else {
+ $this->processFile($file, $output);
+ }
+ }
+ return Command::SUCCESS;
+ }
+
+ /**
+ * Process a directory
+ *
+ * @param SplFileInfo $directory The directory
+ * @param OutputInterface $output The command line output
+ *
+ * @return void
+ *
+ * @throws Throwable If an error occurs
+ */
+ private function processDirectory(SplFileInfo $directory, OutputInterface $output): void
+ {
+ $output->writeln('Processing directory: ' . $directory->getPathname() . '');
+
+ if (!$directory->isReadable()) {
+ $output->writeln('The directory is not readable');
+ return;
+ }
+
+ $directoryIterator = new RecursiveDirectoryIterator($directory->getPathname());
+ $directoryIterator = new RecursiveIteratorIterator($directoryIterator);
+ $directoryIterator = new RegexIterator($directoryIterator, /** @lang PhpRegExp */ '/\.epub$/', RegexIterator::MATCH);
+
+ /** @var SplFileInfo $file */
+ foreach ($directoryIterator as $file) {
+ $this->processFile($file, $output);
+ }
+ }
+
+ /**
+ * Process a file
+ *
+ * @param SplFileInfo $file The file
+ * @param OutputInterface $output The command line output
+ *
+ * @return void
+ *
+ * @throws Throwable If an error occurs
+ */
+ private function processFile(SplFileInfo $file, OutputInterface $output): void
+ {
+
+ }
+}
\ No newline at end of file