Modifying the source code
Spothole is Public Domain licenced, so you can grab the source code and start modifying it for your own needs. Contributions of code back to the main repository are encouraged, but completely optional.
The source code can be found at https://git.ianrenton.com/ian/spothole.
Sorry this isn't on GitHub. There's too much noise on there now it's been given over to Copilot agents. If you want to contribute code changes, that unfortunately means you'll have to sign up for an account on the developer's Forgejo server (linked above), or email patch files to Ian, M0TRT the old-fashioned way. The hope was that Forgejo federation would be working soon, so that at least you could use a Codeberg account rather than a new login specifically for that instance, but unfortunately we're still waiting on that one!
Code structure
To navigate your way around the source code, this list may help.
Python back-end code
/core- Core classes and utilities/data- Data storage classes/providers/spot- Classes providing spots by accessing the APIs of other services/providers/alert- Classes providing alerts by accessing the APIs of other services/providers/upstream- Classes sending spots and alerts that users add to Spothole on to the APIs of other services/providers/solarconditions- Classes providing solar and propagation by accessing the APIs of other services/providers/staticdata- Classes providing static lookup data by accessing bundled data files or the APIs of other services/providers/callsign- Classes providing callsign lookup data by accessing bundled data files or the APIs of other services/providers/activityrefdata- Classes providing activity reference lookup data by accessing bundled data files or the APIs of other services/webserver- Classes for running Spothole's own web serverspothole.py- Main application script
Templates
/templates- Templates used for constructing Spothole's user-targeted HTML pages
HTML/JS/CSS front-end code
/static- Root for static files served by the web server. These are all served from a path starting/static/./static/apidocs- Contains the OpenAPI spec (openapi.yml)/static/audio- Audio files used by the web front-end/static/css- CSS files used by the web front-end/static/img- image files used by the web front-end/static/js- JavaScript used by the web front-end/static/vendor- Third-party libraries (CSS, JS, fonts and images)
Miscellaneous
/- piprequirements.txt, config, README, etc./misc- Files not directly used by Spothole itself. This includes the screenshots used in the README, example DXSpider custom commands referenced in the documentation, etc./datafiles- Local data files, used by some providers when the data will never change and/or is not easily available online in a format Spothole can handle/cache- Directory where Spothole stores all the data it uses that should be persisted to disk. Created on first run.
Maintaining a Branch
It's hoped that developers can contribute to Spothole with generally useful bug fixes and new features. However, in some cases, you might want to tailor Spothole's code to your own needs in a way that doesn't make sense to contribute back upstream. In this case, the best approach is to make your own branch of Spothole, and make your changes there. When a new version of Spothole is released, you can then merge the changes into your branch (and deal with any conflicting changes at that point.
For example:
git clone https://git.ianrenton.com/ian/spothole.git cd spothole git checkout -b my-branch
Then make your code changes, and commit them to your branch:
git add -A git commit -m "My changes"
If a new feature or change is made to Spothole that you want to incorporate, merge it into your branch:
git merge origin/main
Adding a new Page
One common change users may want to make is to add a new page to Spothole to display some bespoke information. You
can add links to the Spothole menu just by editing config.yml, so if those pages are hosted elsewhere,
you could "add a page" that way. But if you want to keep the Spothole menu, and have your page served directly from
your Spothole site, you should add it as a new template.
Navigate to the templates folder and create a new file e.g. mypage.html with the following
contents:
{% extends "base.html" %}
{% block content %}
Hello world!
{% end %}
You can then put anything you like in this file, including script tags which reference JavaScript code
stored within the static/js folder. You can also use templating to include some data. See
pagetemplate.py for what's included. You could, if you wish, create your own template for this page
and bring in spot or alert data by templating. Or you could use the same approach as the built-in pages, which
is to get the basics via templating, but fetch spots & alerts via JavaScript calls to the API. The choice is yours!
The final part of adding a new page is telling Tornado to serve it. Open webserver/webserver.py and
scroll down to where the ui_pages variable is populated. Adding your new page to that will mean it
becomes accessible from the web at e.g. your-server.com/mypage.
Adding a new Provider
Spothole is designed to be easily extensible. If you want to write your own spot provider, for example, simply add a
module to the providers.spot package containing your class. (Currently, in order to be loaded
correctly, the module (file) name should be the same as the class name, but lower case.)
Your class should extend "SpotProvider"; if it operates by polling an HTTP Server on a timer, it can instead extend " HTTPSpotProvider" where some of the work is done for you.
The class will need to implement a constructor that takes in the provider_config and provides it to the
superclass constructor, while also taking any other config parameters it needs.
If you're extending the base SpotProvider class, you will need to implement start() and
stop() methods that start and stop a separate thread which handles the provider's processing needs. The
thread should call submit() or submit_batch() when it has one or more spots to report.
If you're extending the HTTPSpotProvider class, you will need to provide a URI to query and an interval
to the superclass constructor. You'll then need to implement the http_response_to_spots() method which
is called when new data is retrieved. Your implementation should then call submit() or submit_batch()
when it has one or more spots to report.
When constructing spots, use the comments in the Spot class and the existing implementations as an example. All
parameters are optional, but you will at least want to provide a time (which must be timezone-aware)
and a dx_call.
Finally, simply add the appropriate config to the spot_providers section of config.yml, and
your provider should be instantiated on startup.
The same approach as above is also used for alerts, and other types of providers. Give Spothole's developers a shout if you need any advice.
If you want users to be able to send spots or alerts on to another service, write an upstream provider in the
providers.upstream package, extending UpstreamProvider, and add it to the
upstream_providers section of config.yml. Implement can_send_spot() and
validate_spot() to provide validation of whether the spot can be sent via the new provider. Implement
send_spot() to do the submission, raising SpotSubmissionError with a helpful message if
the service doesn't accept the spot. Alerts work the same way with the _alert equivalents. Upstream
providers are separate from spot and alert providers, but if they share a name (e.g. "POTA"), Spothole will ask the
spot or alert provider to check for new data straight after something is submitted, so it shows up quickly.
Contributing to Spothole
Contributions from the community are very much welcome. Please bear in mind the following types of contributions you may wish to make, and the associated comments:
- Bug fixes: Very welcome, of course.
- Fixes for bugs found using AI: Accepted with caution. Before submitting, please ensure you understand the change you are recommending, and why it is an improvement.
- User quality of life improvements: Welcome.
- Documentation and infrastructure improvements: Welcome.
- Support for new activities: Welcome.
- API breaking changes: Welcome if they are justifiable improvements. Please note that breaking changes will trigger a new major release and a request to all client developers to update their code, so this should be done with caution.
- New "on theme" features: Welcome. Spothole aims to be an API and web UI that provides spots and alerts from multiple sources, and augments them with as much data as is reasonable. Additional "on theme" features include allowing users to submit spots and alerts, displaying solar/propagation conditions, and activity references. "On theme" feature submissions are in one of these areas.
- New "off theme" features: Discuss with the developers first. In particular, Spothole does not want to replicate what HamAlert or DXSpider already do, and does not intend to offer user accounts or store user data server-side.
- New features written by AI: No thanks. I want to keep Spothole's codebase understood by its developers. If you have a great idea but can't code it yourself, just talk to me about it. I'd rather write it myself slowly than take on a pile of tech debt to implement it immediately.
- Pull requests written by AI: Absolutely not. Please talk to me about your change, one human to another.