diff --git a/README.md b/README.md index 5e98c69..575f20c 100755 --- a/README.md +++ b/README.md @@ -64,6 +64,7 @@ src/gemini-dl.php --source gemini://.. --target /path/to/download # Optional +-a, --absolute - no value, absolute filepath in links (ignored on --keep), disabled by default -c, --crawl - no value, crawl document links (entire capsule download), disabled by default -d, --delay - integer, pause between requests (seconds), 1 by default -i, --index - string, index filename of directory listing, index.gmi by default diff --git a/help.gmi b/help.gmi index 7320a2b..c6a2635 100755 --- a/help.gmi +++ b/help.gmi @@ -17,6 +17,7 @@ ## Optional + -a, --absolute - no value, absolute filepath in links (ignored on --keep), disabled by default -c, --crawl - no value, crawl document links (entire capsule download), disabled by default -d, --delay - integer, pause between requests (seconds), 1 by default -i, --index - string, index filename of directory listing, index.gmi by default diff --git a/src/Controller/Cli.php b/src/Controller/Cli.php index 92995b7..a2ed982 100755 --- a/src/Controller/Cli.php +++ b/src/Controller/Cli.php @@ -102,6 +102,12 @@ class Cli $this->source[$offset] ); + // Build filesystem location + $filename = $this->filesystem->getFilenameFromNetAddress( + $source, + $this->option->index + ); + // Build request $request = new Request( $source->get() @@ -188,7 +194,7 @@ class Cli ) ); - // Set downloader mode + // Set data mode $raw = ($this->option->raw || !str_contains((string) $response->getMeta(), 'text/gemini')); // Parse gemtext @@ -228,12 +234,25 @@ class Cli // Address --keep not requested if (!$this->option->keep) { + // Generate absolute local file name + $local = $this->filesystem->getFilenameFromNetAddress( + $address, + $this->option->index, + ); + + // Absolute option skipped, make local path relative + if (!$this->option->absolute) + { + $local = Filesystem::getFilenameRelativeToDirname( + $local, + dirname( + $filename + ) + ); + } // Replace link to local path $link->setAddress( - $this->filesystem->getFilenameFromNetAddress( - $address, - $this->option->index, - ) + $local ); } @@ -244,22 +263,10 @@ class Cli } } - // Build document filesystem location - $filename = $this->filesystem->getFilenameFromNetAddress( - $source, - $this->option->index - ); - // Save document to file - $result = $this->filesystem->save( - $filename, - $raw || empty($document) ? $response->getBody() - : $document->toString() - ); - - // Debug FS - if ($result) - { + if ($this->filesystem->save($filename, $raw || empty($document) ? $response->getBody() + : $document->toString()) + ) { print( Message::green( _("\tsave: ") . $filename diff --git a/src/Model/Cli/Option.php b/src/Model/Cli/Option.php index d5ead84..c1711a0 100755 --- a/src/Model/Cli/Option.php +++ b/src/Model/Cli/Option.php @@ -6,6 +6,7 @@ namespace Yggverse\GeminiDL\Model\Cli; class Option { + public bool $absolute = false; public bool $crawl = false; public int $delay = 1; public bool $external = false; @@ -32,6 +33,10 @@ class Option } // Define variables + $this->absolute = boolval( + isset($options['absolute']) || isset($options['a']) || $this->absolute + ); + $this->crawl = boolval( isset($options['crawl']) || isset($options['c']) || $this->crawl ); diff --git a/src/Model/Filesystem.php b/src/Model/Filesystem.php index 064dcbf..f44e1a6 100755 --- a/src/Model/Filesystem.php +++ b/src/Model/Filesystem.php @@ -174,4 +174,70 @@ class Filesystem $data ); } + + // Helpers + public static function getFilenameRelativeToDirname( + string $filename, + string $dirname + ): string + { + // Validate paths + if (empty($filename)) + { + throw new \Exception( + 'Filename is could not be empty' + ); + } + + if (empty($dirname)) + { + throw new \Exception( + 'Dirname is could not be empty' + ); + } + + if (str_starts_with($filename, $dirname)) + { + return ltrim( + str_replace( + $dirname, + DIRECTORY_SEPARATOR, + $filename + ), + DIRECTORY_SEPARATOR + ); + } + + $filepath = explode( + DIRECTORY_SEPARATOR, + dirname( + $filename + ) + ); + + $segments = []; + + foreach ( + explode( + DIRECTORY_SEPARATOR, + $dirname + ) as $level => $directory) + { + if (isset($filepath[$level]) && $filepath[$level] == $directory) + { + continue; + } + + $segments[] = '..'; + } + + $segments[] = basename( + $filename + ); + + return implode( + DIRECTORY_SEPARATOR, + $segments + ); + } } \ No newline at end of file diff --git a/src/gemini-dl.php b/src/gemini-dl.php index 15befeb..939c322 100755 --- a/src/gemini-dl.php +++ b/src/gemini-dl.php @@ -15,8 +15,9 @@ try // Start application $cli = new Cli( getopt( - 'cd:ef:hi:kl:m:rs:t:u', + 'acd:ef:hi:kl:m:rs:t:u', [ + 'absolute:', 'crawl:', 'delay:', 'external',