{"id":19535213,"url":"https://github.com/r-spacex/submanager","last_synced_at":"2025-07-21T22:33:53.454Z","repository":{"id":44386675,"uuid":"389019172","full_name":"r-spacex/submanager","owner":"r-spacex","description":"A bot framework for Reddit to manage threads, wiki pages, widgets, menus and more.","archived":false,"fork":false,"pushed_at":"2022-07-10T08:49:42.000Z","size":797,"stargazers_count":3,"open_issues_count":1,"forks_count":7,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-06-21T14:41:39.073Z","etag":null,"topics":["bot-framework","praw","python","reddit","reddit-api","reddit-bot","spacex","spacex-api"],"latest_commit_sha":null,"homepage":"https://reddit.com/r/spacex","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/r-spacex.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null}},"created_at":"2021-07-24T06:20:32.000Z","updated_at":"2022-08-26T06:37:33.000Z","dependencies_parsed_at":"2022-07-15T00:16:00.533Z","dependency_job_id":null,"html_url":"https://github.com/r-spacex/submanager","commit_stats":null,"previous_names":[],"tags_count":12,"template":false,"template_full_name":null,"purl":"pkg:github/r-spacex/submanager","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/r-spacex%2Fsubmanager","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/r-spacex%2Fsubmanager/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/r-spacex%2Fsubmanager/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/r-spacex%2Fsubmanager/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/r-spacex","download_url":"https://codeload.github.com/r-spacex/submanager/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/r-spacex%2Fsubmanager/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266393201,"owners_count":23922327,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-21T11:47:31.412Z","response_time":64,"last_error":null,"robots_txt_status":null,"robots_txt_updated_at":null,"robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bot-framework","praw","python","reddit","reddit-api","reddit-bot","spacex","spacex-api"],"created_at":"2024-11-11T02:17:35.317Z","updated_at":"2025-07-21T22:33:53.429Z","avatar_url":"https://github.com/r-spacex.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Sub Manager\n\n\n\u003c!-- Things used --\u003e\n[![PyPI Python version](https://img.shields.io/pypi/pyversions/submanager?label=Python)](https://pypi.org/project/submanager/)  \u003c!-- markdown-link-check-disable-line --\u003e\n[![Framework](https://img.shields.io/badge/Framework-PRAW-orange.svg)](https://github.com/pytest-dev/pytest)\n[![Tests Pytest](https://img.shields.io/badge/Testing-Pytest-blue.svg)](https://pytest.org/)\n[![Pre-Commit](https://img.shields.io/badge/Linting-Pre--Commit-brightgreen?logo=pre-commit\u0026logoColor=white)](https://pre-commit.com/)\n[![Code style wemake](https://img.shields.io/badge/Code-wemake-000000.svg)](https://wemake-python-stylegui.de/en/stable/)\n[![Code style Black](https://img.shields.io/badge/Style-Black-000000.svg)](https://github.com/psf/black)\n\n\u003c!-- Project status --\u003e\n[![License](https://img.shields.io/github/license/r-spacex/submanager?label=License)](https://github.com/r-spacex/submanager/blob/master/LICENSE.txt)\n[![Maintainer](https://img.shields.io/badge/Maintainer-CAM--Gerlach-blue)](https://github.com/CAM-Gerlach)\n[![PyPI status](https://img.shields.io/pypi/status/submanager?label=Status)](https://pypi.org/project/submanager/)  \u003c!-- markdown-link-check-disable-line --\u003e\n[![GitHub version](https://img.shields.io/github/v/tag/r-spacex/submanager?include_prereleases\u0026label=GitHub)](https://github.com/r-spacex/submanager/releases)\n[![PyPI version](https://img.shields.io/pypi/v/submanager?label=PyPI)](https://pypi.org/project/submanager/)  \u003c!-- markdown-link-check-disable-line --\u003e\n[![PyPI wheel](https://img.shields.io/pypi/wheel/submanager?label=Wheel)](https://pypi.org/project/submanager/)  \u003c!-- markdown-link-check-disable-line --\u003e\n[![Subreddit subscribers](https://img.shields.io/reddit/subreddit-subscribers/spacex?label=Subs)](https://www.reddit.com/r/spacex/)\n\n\u003c!-- Build status --\u003e\n[![Tests status](https://github.com/r-spacex/submanager/actions/workflows/test.yaml/badge.svg?branch=master)](https://github.com/r-spacex/submanager/actions/workflows/test.yaml)\n[![Lint status](https://github.com/r-spacex/submanager/actions/workflows/lint.yaml/badge.svg?branch=master)](https://github.com/r-spacex/submanager/actions/workflows/lint.yaml)\n[![Mega-Linter](https://github.com/r-spacex/submanager/actions/workflows/mega-linter.yaml/badge.svg?branch=master)](https://github.com/r-spacex/submanager/actions/workflows/mega-linter.yaml)\n[![Semgrep scan](https://github.com/r-spacex/submanager/actions/workflows/semgrep-analysis.yaml/badge.svg?branch=master)](https://github.com/r-spacex/submanager/actions/workflows/semgrep-analysis.yaml)\n[![CodeQL analysis](https://github.com/r-spacex/submanager/actions/workflows/codeql-analysis.yaml/badge.svg?branch=master)](https://github.com/r-spacex/submanager/actions/workflows/codeql-analysis.yaml)\n[![Checked with MyPy](http://www.mypy-lang.org/static/mypy_badge.svg)](http://mypy-lang.org/)\n[![Awesome badges](https://img.shields.io/badge/Badges-Awesome-brightgreen.svg)](https://github.com/Naereen/badges)\n\n\nSub Manager is a bot framework for Reddit to automate a variety of tasks on one or more subreddits, and can be configured and run without writing any code.\nIts initial application was to automatically generate, create, pin and update threads, as well as related tasks.\nAdditionally, it can be used to automatically sync and reformat content between wiki pages, widgets and threads, as well as marked sections of the same (including the sub's sidebar and other content).\nIt includes support for automatically installing a Systemd service unit for real-time operation on modern Linux distributions, which is used in production for the r/SpaceX subreddit, and it can also be run by any other means you choose on your system.\n\n**Legal Disclaimer**: For the avoidance of doubt, Sub Manager and the r/SpaceX Github org and subreddit are unofficial fan creations, and have no affiliation with nor endorsement by [Reddit](https://www.reddit.com) or [SpaceX](https://www.spacex.com), which are trademarks of their respective companies.\n\n\n\n\u003c!-- markdownlint-disable --\u003e\n\u003c!-- START doctoc generated TOC please keep comment here to allow auto update --\u003e\n\u003c!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --\u003e\n\n- [Installation](#installation)\n  - [Create and activate fresh virtual environment](#create-and-activate-fresh-virtual-environment)\n  - [Download and install](#download-and-install)\n- [Usage](#usage)\n- [Contributing](#contributing)\n- [Configuration](#configuration)\n  - [Configuring credentials](#configuring-credentials)\n  - [Posting intervals](#posting-intervals)\n  - [Syncing sections](#syncing-sections)\n- [Running as a service](#running-as-a-service)\n\n\u003c!-- END doctoc generated TOC please keep comment here to allow auto update --\u003e\n\u003c!-- markdownlint-restore --\u003e\n\n\n\n## Installation\n\n**Note**: You may need to substitute ``python3`` for ``python`` in the commands below on some Linux distros where ``python`` isn't mapped to ``python3`` (yet).\n\n\n### Create and activate fresh virtual environment\n\nWhile Sub Manager can be installed in your system Python, we highly recommend you create and activate a virtual environment to avoid any conflicts with other packages on your system or causing any other issues.\nUsing the standard tool ``venv``, you can create an environment as follows:\n\n```bash\npython -m venv your-env-name\n```\n\nYou can then activate it with the following on Linux and macOS,\n\n```bash\nsource your-env-name/bin/activate\n```\n\nor on Windows (cmd),\n\n```cmd\n.\\your-env-name\\Scripts\\activate.bat\n```\n\nOf course, you're free to use any environment management tool of your choice (conda, virtualenvwrapper, pyenv, etc); these steps are just an example.\n\n\n### Download and install\n\nTo download and install the package from the [Python Package Index (PyPI)](https://pypi.org/project/submanager/), simply activate your environment and run  \u003c!-- markdown-link-check-disable-line --\u003e\n\n```bash\npython -m pip install submanager\n```\n\nAlternatively, if you want to use the exact pinned dependencies we do, you can ``clone`` this repo and install from the ``requirements.txt`` file:\n\n```bash\ngit clone https://github.com/r-spacex/submanager.git\ncd submanager\npython -m pip install -r requirements.txt\npython -m pip install .\n```\n\n\n\n## Usage\n\nTo use Sub Manager, you'll need to activate the appropriate environment you created previously, and then execute its main entrypoint.\nFor example, with venv under bash,\n\n```bash\nsource your-env-name/bin/activate\nsubmanager \u003ccommand\u003e\n```\n\nTo see the various commands and options available, pass it the ``--help`` flag.\n\n\n\n## Contributing\n\nFor information on how to contribute to Sub Manager, including reporting issues, setting up a development environment and contributing code, see the [Contributing Guide](https://github.com/r-spacex/submanager/blob/master/CONTRIBUTING.md).\n\n\n\n## Configuration\n\nFirst, you'll want to generate the primary Sub Manager user config file, in order to tell it what you want it to do.\nTo do so, simply run ``submanager generate-config`` to generate it at the default path, and a stock config file with some starting examples will be output (formatted as TOML for humans).\nThe static config file, which stores user configuration as human-friendly TOML, is located in the ``submanager`` subdirectory OS-appropriate user config directory, and the dynamic config file, which stores persistent internal state (e.g. current threads being managed) as machine-friendly JSON, is located in ``submanager`` subdirectory OS-appropriate user state directory.\nTo view the full paths to and status of these files on your system, simply run ``submanager get-config-info``.\nYou can specify an alternate config file for one or both with the respective ``--config-path`` and ``--dynamic-config-path`` options, allowing you to run multiple instances of the bot simultaneously on the same machine (for example, to avoid cramming everything into one big configuration file, or use multiple cores).\n\nTo improve robustness and enforce safe maintenance practices, Sub Manager must now be stopped and restarted to read-in updated config.\nIndividual modules, such as ``sync_manager`` and ``thread_manager``, can be enabled and disabled via their corresponding ``enabled`` options, and can be further configured as described below.\nTo perform a variety of checks that your configuration is valid and will result in a successful run, without actually executing any state-changing Reddit actions, run ``submanager validate-config``; if an error occurs, informative output will explain the problem and, often, how to fix it.\n\n\n### Configuring credentials\n\nStarting with Sub Manager v0.5.0 and later, the Reddit account to use for a given action can be specified per module (``sync_manager``, ``thread_manager``), per task (sync item, thread) and even per source and target, as well as globally.\nYou'll need to configure and register the account(s) involved for Reddit app access with the Reddit API.\nWe recommend you configure your credentials in ``praw.ini`` and simply refer to them via the PRAW ``site_name`` argument in the ``config`` subtable of the respective account listed under the ``accounts`` table, which will avoid any secrets leaking if you accidentally or deliberately store your ``config.toml`` somewhere public.\nHowever, if you prefer, the various arguments that ``praw.Reddit()`` can accept, e.g. ``username``, ``password``, ``client id``, ``client secret``, ``refresh token`` etc) can be also all be included as subkeys under the ``config`` subtable of the named account in the ``accounts`` table.\nSub Manager v0.5.0 supported the new token manager refresh token handling Reddit announced in early 2021, while v0.6.0 dropped that support along with PRAW due to Reddit reverting that change.\nWhile this occurred before to the first wide public release of Sub Manager (v0.6.0), this change is nevertheless transparent to users, as Sub Manager handles this for you.\n\n\n### Posting intervals\n\nIf posting new threads is enabled for a configured thread item, it can be set to either post daily, monthly, yearly etc. as soon as the period ticks over (e.g. first of the month), or at an interval of every N periods after the previous thread was posted.\n\n``new_thread_interval`` is specified as a string, either in the form ``\"UNIT\"`` (e.g. ``\"daily\"``, ``\"month\"``, etc) to trigger the first behavior, or `\"N UNIT\"` (e.g. ``\"10 weeks\"``, ``\"1 year\"``, etc) to invoke the second, where ``N`` is a positive integer and ``UNIT`` is a supported period unit.\nSupported period units for both include years, months, days, hours, minutes and seconds; weeks are currently supported for the latter, but not the former (since there is no unambiguously agreed-upon, locale-independent start of a week, and they don't divide evenly into months or years).\nFor either form, the units can be given with or without `s` or `ly` as suffices.\n\nThere's currently a minor limitation with this as currently implemented: getting it to create a new thread \"on-demand\" rather than on a schedule (or not at all) is not completely obvious.\nThere is a relatively simple workaround, however—just set the ``new_thread_interval`` to ``false``, and then whenever you want a new thread, set it to e.g. ``1 day``, wait `repeat_interval_s` seconds for it to create the new thread (or manually restart it, if you're impatient), and then set it back to ``false``.\n\nWe will soon add a proper feature for this, likely in the form of a new CLI command, e.g. ``submanager create-thread \u003cthread_name\u003e``, to programmatically tell the running Sub Manager instance to create a new post on-demand.\n\n\n### Syncing sections\n\nThe ``pattern``s of text specified in ``source`` and ``targets`` are searched for in pseudo-Markdown \"comments\", i.e. empty links that don't appear in the rendered text, like so:\n\n```markdown\n[](#/ \u003cPATTERN\u003e\u003cPATTERN_START\u003e)\n\nExample section content\n\n[](#/ \u003cPATTERN\u003e\u003cPATTERN_END\u003e)\n```\n\nThis allows easily syncing just specific sections between sources and targets.\n\nIf any variable (e.g. ``pattern``) is not specified for a ``target``, the value is recursively inherited from the respective ``defaults`` table in the sync pair, and then sync config section, including the ``context`` sub-table in each as well as the ``default_context`` in the config.\nConversely, any ``replace_patterns`` for a specific target are applied after (and in addition) to those specified in ``source`` for all targets; note the ``source`` section is *not* actually modified unless it is specified as a ``target``.\n\n\n\n## Running as a service\n\nTo install a Systemd user service that will run Sub Manager automatically, activate your Sub Manager environment and simply run the ``submanager install-service`` command.\nBy default, this will install a user-level service named ``submanager.service`` which will run Sub Manager with the primary configuration.\nIf you'd like to install another service with a different config, specify the config file path as usual with ``--config-path``, and (if you don't want the service to overwrite the default one, so you can run as many as you want at once), a custom ``suffix``; the resulting service will be named ``submanager-\u003csuffix\u003e.service``.\n\nThe installed service can be enabled and started in the typical way,\n\n```bash\nsystemctl --user daemon-reload\nsystemctl --user enable submanager\nsystemctl --user start submanager\n```\n\nand you can check its status and log, respectively, with the usual\n\n```bash\nsystemctl --user status submanager\njournalctl --user -xe -u submanager\n```\n\nNote that there are [a few considerations to keep in mind](https://wiki.archlinux.org/index.php/systemd/User#Automatic_start-up_of_systemd_user_instances) when running as a user instance of Systemd, most notably to get it to autostart on boot rather than login and persist after the user is logged out (e.g. on a server, VPS or other unattended box).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fr-spacex%2Fsubmanager","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fr-spacex%2Fsubmanager","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fr-spacex%2Fsubmanager/lists"}