NeoCities Command Line Interface Tools
As I’ve mentioned before, I currently manage the site by hand. It didn’t take much time fiddling with the NeoCities web file manager before I decided I needed something a little snappier that would quickly allow me to upload files from CLI. This is a collection of ongoing notes.
You’ll need an API Key, which can be generated. The easiest way to do this is probably using CURL. You can assign this key to the Environmental Variable NEOCITIES_API_KEY (System > Advanced System Settings > Advanced > Environmental Variable) .
> curl "https://USER:PASS@neocities.org/api/key"
neocitizen: Python client library for Neocities API
There’s a new library in town, poyo46’s neocitizen. I found the documentation on this a bit non-intuitive and ended up digging through the code to try to understand how it works.
F:\NeoCities>neocitizen upload --help Usage: neocitizen upload [OPTIONS] Upload local data to your Neocities site. Options: -d, --dir PATH Local directory path. --dir-on-server TEXT Destination directory. -f, --file TEXT (local file path):(path on server) --help Show this message and exit.To upload a specific directory:
- Uploads contents of test to root
> neocitizen upload --dir=test
- Uploads /test/ to /test/
> neocitizen upload -d test --dir-on-server test
- Uploads /test/ to /test2/
> neocitizen upload -d test --dir-on-server test2
I ran into trouble trying to upload individual files, and consulted the code to see what arguments were expected to make sure I wasn't messing them up.
@pytest.mark.parametrize( "args, expected_code", [ (["upload"], 0), (["upload", "--dir=foo"], 0), (["upload", "--dir=foo", "--dir-on-server=bar"], 0), (["upload", "--file=foo.txt"], 0), (["upload", "--file=foo.txt:dir/foo.txt", "--file=bar.txt:dir/bar.txt"], 0), (["upload", "--file=foo.txt:dir1/foo.txt:dir2/foo.txt"], 1), ], )
Based on the above code, it seems this should work, right?
F:\NeoCities>neocitizen upload --file=iguess.webp Traceback (most recent call last): File "c:\python36\lib\runpy.py", line 193, in _run_module_as_main "__main__", mod_spec) File "c:\python36\lib\runpy.py", line 85, in _run_code exec(code, run_globals) File "C:\Python36\Scripts\neocitizen.exe\__main__.py", line 7, inFile "c:\python36\lib\site-packages\click\core.py", line 1128, in __call__ return self.main(*args, **kwargs) File "c:\python36\lib\site-packages\click\core.py", line 1053, in main rv = self.invoke(ctx) File "c:\python36\lib\site-packages\click\core.py", line 1659, in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) File "c:\python36\lib\site-packages\click\core.py", line 1395, in invoke return ctx.invoke(self.callback, **ctx.params) File "c:\python36\lib\site-packages\click\core.py", line 754, in invoke return __callback(*args, **kwargs) File "c:\python36\lib\site-packages\neocitizen\cli.py", line 55, in upload raise BadParameter TypeError: __init__() missing 1 required positional argument: 'message'
How about this?
F:\NeoCities>neocitizen upload --file=iguess.webp:iguess.webp Traceback (most recent call last): File "c:\python36\lib\runpy.py", line 193, in _run_module_as_main "__main__", mod_spec) File "c:\python36\lib\runpy.py", line 85, in _run_code exec(code, run_globals) File "C:\Python36\Scripts\neocitizen.exe\__main__.py", line 7, inFile "c:\python36\lib\site-packages\click\core.py", line 1128, in __call__ return self.main(*args, **kwargs) File "c:\python36\lib\site-packages\click\core.py", line 1053, in main rv = self.invoke(ctx) File "c:\python36\lib\site-packages\click\core.py", line 1659, in invoke return _process_result(sub_ctx.command.invoke(sub_ctx)) File "c:\python36\lib\site-packages\click\core.py", line 1395, in invoke return ctx.invoke(self.callback, **ctx.params) File "c:\python36\lib\site-packages\click\core.py", line 754, in invoke return __callback(*args, **kwargs) File "c:\python36\lib\site-packages\neocitizen\cli.py", line 56, in upload api.upload_files(file_map={paths[0]: paths[1]}) File "c:\python36\lib\site-packages\neocitizen\api.py", line 266, in upload_fi les extension = get_extension(local_path) File "c:\python36\lib\site-packages\neocitizen\utils.py", line 31, in get_exte nsion i = path.name.rfind(".") AttributeError: 'str' object has no attribute 'name'
Assuming I haven't done something horribly wrong.... IDK maybe I did do something horribly wrong. The library is packed into an exe so I would have to figure out how to unpack it to make any changes.
Worth it?
It's a quick way to upload a directory from the CLI.
Neocities Ruby Gem (a.k.a. THAT OLD CHESTNUT)
I have long wrestled with my ancient nemesis, Ruby CLI, on Windows. Previously:
F:\NeoCities>gem install neocities ERROR: Could not find a valid gem 'neocities' (>= 0), here is why: Unable to download data from https://rubygems.org/ - SSL_connect retur ned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed ( https://api.rubygems.org/specs.4.8.gz)
I’ve tried many things to remove that certificate error, which even prevents me from updating gem itself. This time I did a fresh install of the latest version of Ruby. I found I was able to install some gems, but when I tried neocities…
>gem install neocities Temporarily enhancing PATH to include DevKit... Building native extensions. This could take a while... ERROR: Error installing neocities: ERROR: Failed to build gem native extension. current directory: C:/Ruby23-x64/lib/ruby/gems/2.3.0/gems/neocities-0.0.15/ext C:/Ruby23-x64/bin/ruby.exe mkrf_conf.rb mkrf_conf.rb:4:in '': uninitialized constant Gem::Command (NameError) rake failed, exit code 1 Gem files will remain installed in C:/Ruby23-x64/lib/ruby/gems/2.3.0/gems/neocit ies-0.0.15 for inspection. Results logged to C:/Ruby23-x64/lib/ruby/gems/2.3.0/extensions/x64-mingw32/2.3.0 /neocities-0.0.15/gem_make.out
I tried updating Ruby Gems to no effect. I knew I couldn’t be the only person having this issue, and fortunately I wasn’t the only person posting about it either. Mere days ago kingpanther13 provided a solution for issue #35, uninitialized constant Gem::Command (NameError) when building extension:
For anyone else having this issue, I spent hours trying to get the neocities CLI to work using Ruby 3.1 and kept getting this same error no matter what I tried, using #34 , using the instructions given by Jamesgecko, everything. I finally decided to do a fresh install of Ruby for version 2.7.5 with the devkit, and just simply using "gem install neocities" worked like a charm on the first try.
So I uninstalled Ruby 3.1.1 and installed Ruby 2.7.5… and it worked! My only lingering issue was using cmd as an Administrator from within Atom. I found setting Atom’s program properties to administrator allowed this.
Example usage for uploading the local file images/iguess.webp to the images directory:
> neocities upload -d images images/iguess.webp
One thing I like about the NeoCities CLI is it won’t upload the file if a matching version exists on the server. One thing I don't like is it's all or nothing--you can either upload an individual file or you can push the entire site to root, but you can't upload a specific directory like you can with neocitizen.
I spent a significant amount of time troubleshooting this gem. Was it worth it?
If I want to take advantage of push I have to keep my local files much cleaner than they are now.
Shadowm00n's Neocities Management Script
Shadowm00n's Neocities Management Script is a Perl-based client. Haven't investigated it yet.